C51单片机模拟I2C总线驱动程序
51单片机的I2C底层驱动程序(IO口模拟)

51单片机的I2C底层驱动程序(IO口模拟)/*Title:I2C for 80C51Author:yuyouliang51单片机(本人使用STC89C52单片机,12T模式)的I2C驱动程序,使用逻辑分析仪对该协议进行分析,发现波形比较美观,SCL 的频率在70KHz左右(11.0592M晶振),低于标准的100K,可以适应大多数的I2C器件。
如果感觉速度过快或过慢,可以自行修改延时。
希望可以给读者一个参考,给读者一些帮助!*//*i2c.h文件 */#ifndef __I2C_H_#define __I2C_H_sbit SCL = P2^1;sbit SDA = P2^0;void start_i2c(); //启动I2C总线:SCL高电平期间,SDA由高变低void stop_i2c(); //停止I2C总线:SCL高电平期间,SDA由低变高void send_i2c(unsigned char c); //主机发送一个字节,先发送最高位unsigned char receive_i2c(); //主机接收一个字节,先接收最高位void master_ack(bit ack); //主机非应答信号(填参数0)或应答信号(填参数1)void slave_ack(); //等待从机应答信号#endif/* i2c.c文件 */#include#include#include#define nop() _nop_()void start_i2c() //启动I2C总线:SCL高电平期间,SDA由高变低{SDA=1;SCL=1;nop();nop();nop();nop();SDA=0;SCL=0;}void stop_i2c() //停止I2C总线,SCL高电平期间,SDA由低变高{SDA=0;SCL=1;nop();nop();nop();nop();SDA=1;}void slave_ack() //等待从机应答信号,如果从机迟迟没有应答,则结束总线。
C51单片机模块驱动程序参考

0x38,0x39,0x41,0x42,0x43,0x44,0x45,0x46
};定义在函数外部
unsigned char Key_ASC2(unsigned char key)
{
unsigned char key_asc2;
{
StartI2C();
Write8Bit(0xA2);
ChackAck();
Write8Bit(RomAddress);
ChackAck();
StartI2C();
Write8Bit(0xA3);
ChackAck();
for(;bytes!=1;bytes--)
{
*RamAddress=Read8Bit();
i=*ptr;
i &=பைடு நூலகம்0x80;
if(i==0)
break;
}
}
函数功能描述:向1602指令寄存器写指令;
void WriteW(uint a)
{
ptr=0xAFF0;//RS=0,R/W=0
*ptr=a;
}
函数功能描述:LCD初始化;
void LCD_Init(void)
{
CheckBF();
WriteW(0x38);
函数功能描述:键盘初始化,将标志位置1;
void Key_Init(void)
{
bKeyUp_Flag=1;//标志(全局变量)位置1
}
函数功能描述:键盘扫描函数,得到键的行列位置;
unsigned char GetScanKey(void)
{
unsigned char key, i, temp;
I2C总线(主)C51源程序

I2C总线(主)C51源程序#define ROMADDRESS 0xA0sfr IIC_CON = 0xA0;sbit WP = IIC_CON^5;sfr IIC_INTER = 0x90;sbit SCL = IIC_INTER^6;sbit SDA = IIC_INTER^7;bit ack; /*应答标志位*/void DelayMs(unsigned char i){unsigned int count;for(i;i!=0;i--)for(count=6;count!=0;count--);}/************************************************************** *********//*名称: IIC_Start()/*说明: 启动I2C总线,即发送I2C起始条件./*输入: 无/*输出: 无/************************************************************** *********/void IIC_Start(void){SCL=1; DelayMs(1);SDA=1; DelayMs(1);SDA=0; DelayMs(1); /*发送起始信号*/SCL=0; DelayMs(1); /*钳住I2C总线,准备发送或接收数据 */ }/***********************************************************************//*名称: IIC_Stop()/*说明: 结束I2C总线,即发送I2C结束条件./*输入: 无/*输出: 无/************************************************************** *********/void IIC_Stop(void){SCL=1; DelayMs(1); /*发送结束条件的时钟信号*/SDA=0; DelayMs(1);SDA=1; DelayMs(1); /*发送I2C总线结束信号*/SCL=0; DelayMs(1);}/************************************************************** *********//*名称: IIC_DataSend()/*说明: 将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对此状态位进行操作.(不应答或非应答都使ack=0)ack=1表示发送数据正常; ack=0表示被控器无应答或损坏。
周立功—I2C 总线实验

I2C 总线实验(实时时钟、EEPROM 和ZLG7290 的实验)一.实验目的加深用户对I2C 总线的理解,熟悉I2C 器件的使用,提供用户实际开发的能力。
二.实验设备及器件IBM PC 机一台DP-51PROC 单片机综合仿真实验仪一台三.实验内容进行I2C 总线控制的实时时钟、EEPROM、ZLG7290 键盘LED 控制器实验。
四.实验要求熟练掌握I2C 总线的控制,灵活运用I2C 主控器软件包,深刻理解实时时钟、EEPROM、ZLG7290 键盘LED 控制的各种功能。
五.实验步骤1.使用导线连接D5 区的SCL、SDA 到A2 区的P16、P17(SCL~P16、SDA~P17),连接D5 区的RST_L、INT_KEY 到A2 区的P10、INT0(RST_L~P10、INT_KEY~INT0),短接D5 区的JP1 跳线。
2.把模拟I2C 软件包“VIIC_C51.C”文件加入到Keil C51 的项目中,程序源文件的开头包含“VIIC_C51.H”头文件。
修改VIIC_C51.C 文件中的sbit SDA=P1^7;和sbit SCL=P1^6;。
图3.21 RTC原理图3.使用函数ISendStr(uchar sla,uchar suba,uchar *s,uchar no)对PCF8563T实时时钟进行设置初始时间,再使用IRcvStr(uchar sla,uchar suba,uchar*s,uchar no)对PCF8563T 实时时钟的时间进行读取。
EEPROM 原理图4.使用函数ISendStr(uchar sla,uchar suba,uchar *s,uchar no);对24WC02EEPROM 进行写入,再使用IRcvStr(uchar sla,uchar suba,uchar *s,uchar no);对24WC02 EEPROM 进行读取。
ZLG7290 原理图5.对ZLG7290 键盘LED 控制器的操作也同理,只是在程序开始的地方增加复位操作和程序中间增加查询是否有键按下。
在51上用P1口模拟I2C

在51上用P1口模拟I2C在51上用P1口模拟I2C原文:下面是用普通C51实现的I2C基本电平模拟函数和通用函数。
/* 电平模拟函数和基本读写函数void IIC_Start(void);void IIC_Stop(void);void SEND_0(void);void SEND_1(void);bit Check_Acknowledge(void);void Write_Byte(uchar b)reentrant;bit Write_N_Bytes(uchar *buffer,uchar n)reentrant;bit Read_N_Bytes(uchar SlaveAdr,uchar n,uchar *buffer); uchar Read_Byte(void)reentrant;*/#include<string.h>#include<reg52.h>#include<intrins.h>#include"aiic_51.h"sbit SCL=P1^6;sbit SDA=P1^7;void DELAY(uint t){while(t!=0)t--;}void IIC_Start(void){//启动I2C总线的函数,当SCL为高电平时使SDA产生一个负跳变SDA=1;SCL=1;DELAY(DELAY_TIME);SDA=0;DELAY(DELAY_TIME);SCL=0;DELAY(DELAY_TIME);}void IIC_Stop(void){//终止I2C总线,当SCL为高电平时使SDA产生一个正跳变SDA=0;SCL=1;DELAY(DELAY_TIME);SDA=1;DELAY(DELAY_TIME);SCL=0;DELAY(DELAY_TIME);}void SEND_0(void){//发送0,在SCL为高电平时使SDA信号为低SDA=0;SCL=1;DELAY(DELAY_TIME);SCL=0;DELAY(DELAY_TIME);}void SEND_1(void){//发送1,在SCL为高电平时使SDA信号为高SDA=1;SCL=1;DELAY(DELAY_TIME);SCL=0;DELAY(DELAY_TIME);}bit Check_Acknowledge(void){//发送完一个字节后检验设备的应答信号SDA=1;SCL=1;DELAY(DELAY_TIME/2);F0=SDA;DELAY(DELAY_TIME/2);SCL=0;DELAY(DELAY_TIME);if(F0==1)return FALSE;return TRUE;}void Write_Byte(uchar b)reentrant{//向IIC总线写一个字节uchar i;for(i=0;i<8;i++)if((b<<i)&0x80)SEND_1();elseSEND_0();}bit Write_N_Bytes(uchar *buffer,uchar n)reentrant {//向I2C总线写n个字节uchar i;IIC_Start();for(i=0;i<n;i++){Write_Byte(buffer);if(!Check_Acknowledge()){IIC_Stop();return(i==n);}}IIC_Stop();return TRUE;}uchar Read_Byte(void)reentrant{//从I2C总线读一个字节uchar b=0,i;for(i=0;i<8;i++){SDA=1; //释放总线SCL=1; //接受数据DELAY(10);F0=SDA;DELAY(10);SCL=0;if(F0==1){b=b<<1;b=b|0x01;}elseb=b<<1;}return b;}bit Read_N_Bytes(uchar SlaveAdr,uchar n,uchar *buffer) {//从I2C总线读n个字节uchar i;IIC_Start();Write_Byte(SlaveAdr); //向总线发送接收器地址if(!Check_Acknowledge()) //等待接收器应答信号return FALSE;for(i=0;i<n;i++){buffer=Read_Byte();if(i!=n)SEND_0(); //发送应答elseSEND_1(); //发送非应答}IIC_Stop();return TRUE;}使用上述代码,你可以在51上用P1口模拟I2C。
C51实现I2C总线单主多从通信

设计论文
C51 实现 I2C 单主多从通信
专业: 航空电子信息
班级:
航电 1203
姓名:
陈瑞金
指 导 老 师 : 鄢立、程秀玲
时 间:
2014.04
1
陈瑞金
________________________________________________________________________________________________________________
五、程序的编写
1、设计思路--------------------------------------------------------------12
2、参考程序
a.主机程序------------------------------------------------------------14
2、关于 24C02 的读写---------------------------------------------------7
四、硬件电路
1、Proteurs 绘制的电路图----------------------------------------------8
2、Proteurs 仿真效果图------------------------------------------------10
当主机接收数据时,它收到最后一个数据字节后,必须向从机发出一个结束传送的信号。这个信号是由对从机 的“非应答”来实现的。然后,从机释放 SDA 线,以允许主机产生终止信号。
(2)数据帧率格式 I2C 总线上传送的数据信号是广义的,既包括地址信号,又包括真正的数据信号。在起始信号后必须传送一个
第16章 C51模拟I2C总线

16.1.3
2C总线数据操作 I
在I2C总线上,数据是伴随着时钟脉冲,一位一位地传
送的,数据位由低到高传送,每位数据占一个时钟脉 冲。I2C总线上的在时钟线SCL高电平期间,数据线 SDA的状态就表示要传送的数据,高电平为数据1,低 电平为数据0。在数据传送时,SDA上数据的改变在时 钟线为低电平时完成,而SCL为高电平时,SDA必须 保持稳定,否则SDA上的变化会被当作起始或终止信 号而致使数据传输停止。
16.3.9 多字节写子函数
启动I2C
多字节写子函数用于主器件发送
发送写寻址地 址
多个字节的数据。首先发送起始 位,接着是寻址字节,然后是数 据的所要存入单元的首地址,外 围器件此时产生正确的应答后, 主器件便将开始多个字节的数据 传输。多字节写子函数的流程图, 如图所示。
应答检查
写数据存储首 地址
16.3.8 单字节读子函数
单字节读子函数用于从I2C数据总
线读入单个字节的数据。程序中, 可以通过for循环语句,逐位将数 据读入。该函数在使用之前,同样 需要先使用起始信号子函数启动 I2C总线数据传输。单字节读子函 数emp=0?
否
左移一位
读一个bit
返回数据
16.2 I2C总线接口EEPROM存储器
目前,市场上I2C总线接口器件有多种,例如A/D转换器、D/A转换器、时钟芯 片和存储器等。这里以典型的I2C总线接口的存储器为例进行介绍。
I2C总线接口EEPROM存储器是一种采用I2C总线接口的串行总线存储器,这类 存储器具有体积小、引脚少、功耗低、工作电压范围宽等特点。目前,Atmel、 MicroChip、National等公司均提供各种型号的I2C总线接口的串行EEPROM存 储器。在单片机系统中使用较多的EEPROM存储器是24系列串行EEPROM。 其具有型号多、容量大、支持I2C总线协议、占用单片机I/O端口少,芯片扩展 方便、读写简单等优点。
软件模拟I2C总线的C51实现.

软件模拟I2C总线的C51实现摘要:介绍51系列单片机上的I2C总线主节点模拟程序,从而实现与具有I2C接口的器件通信。
1I2C总线简介1.1硬件结构I2C串行总线支持所有NMOS、CMOS、I2L工艺制造的器件。
从物理上看由两根双向I/O线组成,一根为数据线(SDA),一根为时钟线(SCL),通过这两根线把所有器件连接到总线上,并通过SDA和SCL在各器件间传递信息(根据地址识别每个器件)。
SDA和SCL通过上拉电阻接正电源,总线空闲时,两根线都是高电平。
这两根I/O线在电气上允许“线与”操作,其输出的驱动形式为集电极开路或漏极开路。
根据通信速度的不同,I2C总线分为三种工作模式:标准模式、快速模式和高速模式。
它们分别对应不同的波特率:100kb/s、400kb/s和3.4Gb/s。
总线上允许的设备数以总线上的电容量不超过400pF为限。
1.2数据传输I2C总线上数据为同步传输。
挂在I2C总线上的每一个器件都有一个独立的地址,而且在传输过程中有主节点和从节点的区分,主节点的作用是启动和结束一次通信,并负责控制总线时钟,总线上可以有多个主节点或多个从节点,但是在一次通信中只能有一个节点作为主节点。
主从机之间一次数据的传输称为一帧,由启动信号、地址信息、应答位及停止位组成。
其传送格式见图1。
2MCS-51与I2C总线芯片接口及程序2.18051经I2C总线扩展存储器PCF8582对于内部没有硬件I2C总线接口的51系列单片机,可以采用软件模拟的方法实现I2C总线接口功能。
硬件连接如图2所示。
用8051的P1.6和P1.7作为I2C总线的SCL利SDA信号,在总线上连接256*8的EEPROM芯片PCF8582。
8051单片机与PCF8582进行数据传递时,首先传送器件的从机地址SLA,格式如下:START为起始信号,从机地址的固定部分是4位——1010,可编程部分由,则该片的从机地址为引脚A2、A1、A0确定。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
功能描述:从启动总线到发送地址、读数据,结束总线的全过程。
I2C_IRcvB
调用函数: I2CS_tart(), I2C_SendB(uchar c), I2C_RcvB(), I2C_Ackn(bit a), I2C_Stop()
需要注意的是,函数是采用延时方法产生 SCL 脉冲,对高晶振频率要做一定的修改!! 在写 E2PROM 的时候一定要延时!!!
说明:
1us 机器周期,晶振频率要小于 12MHz 返回 1 则操作成功,返回 0 则操作失败。 sla 为器件从地址,suba 为器件子地址。
******************************************************************************* ******/
调用函数: 全局变量:
******************************************************************************* ***/
uchar I2C_RcvB()
{
uchar retc;
uchar BitCnt;
//位
retc = 0; SDA = 1;
功能描述: 检验 I2C 总线应答信号,有应答则返回 1,否则返回 0,超时值取 255.
解释:I2C 总线协议中规定传输的每个字节之后必须跟一个应答位,所以从器件在接收到每个 字节之后必须反馈一个应答信号给主控制器,而主控制器就需要检测从器件回传的应答信号, 根据其信息做出相应的处理.另外,主从之别是相对的,接收数据的即为从,发送数据的及为主.
bit I2C_ISendB(uchar sla, uchar suba, uchar c) { I2C_Start(); //启动总线
I2C_SendB(sla); if(!I2C_Ack) {
return(0); }
//发送器件地址
I2C_SendB(suba); //发送器件子地址
if(!I2C_Ack) {
SomeNOP();//结束条件建立时间大于 4us,延时
SDA = 1;
//发送 I2C 总线结束信号
SomeNOP();
}
/************************************ ************************************
I2C_CheckAck
函数名:bit I2C_CheckAck(void) 入口: 出口:0(无应答),1(有应答)
#i nclude "AT89X52.h" #i nclude <intrins.h>
#define SomeNOP(); {_nop_();_nop_();_nop_();_nop_();_nop_();} //定义空指令
sbit SDA = P1^3; sbit SCL = P1^2;
//模拟 I2C 数据传输位 //模拟 I2C 时钟控制位
/******************************** ************************************
I2C_ISendB
函数名:bit I2C_ISendB(uchar sla, uchar suba, uchar c) 入口:从器件地址 sla,子地址 suba, 发送字节 c 出口:0(操作有误),1(操作成功)
再看看应答信号的格式:在由发送器产生的时钟响应周期里,发送器先释放 SDA(置高),然后 由接受器将 SDA 拉低,并在这个时钟脉冲周期的高电平期间保持稳定的低电平.即表示从器 件做出了应答.
调用函数:void I2C_Stop() 全局变量:
******************************************************************************* ***/
/************************************ ************************************
I2C_RcvB
函数名:uchar I2C_RcvB() 入口: 出口:uchar 型数据
功能描述: 接收从器件传来的数据,并判断总线错误(不发应答信号),收完后需要调用应答函数。
SDA = 0;
//发送起始信号
SomeNOP(); //起始条件建立时间大于 4us,延时
SCL = 0;
//钳住 I2C 总线准备发送或接收数据
/******解释:I2C 总线在空闲状态下都是被上拉为高电平的,所以当它们处于低电平时就表示 忙的状态.***/ _nop_(); _nop_(); }
void I2C_SendB(uchar c) { uchar BitCnt;
for (BitCnt=0; BitCnt<8; BitCnt++) //要传送的数据长度为 8 位
{ if((c<<BitCnt)&0x80)
//判断发送位(从高位起发送)
{
SDA = 1;
} else { SDA = 0; }
******************************************************************************* ***/
void I2C_Stop()
{ SDA = 0;
//发送结束条件的数据信号
_Nop(); SCL = 1;
//发送结束条件的时钟信号
void I2C_Ackn(bit a)
{ if(a==0) {
SDA = 0; } else {
SDA = 1; } SomeNOP(); SCL = 1; SomeNOP(); SCL = 0; _nop_(); _nop_(); }
//在此发送应答或非应答信号
//时钟电平周期大于 4 us //清时钟线钳住 I2C 总线以便继续接收
bit bdata I2C_Ack; //应答标志位
/************************************ ************************************
函数名:void I2C_Start() 入口: 出口:
功能描述:启动 I2C 总线,即发送 I2C 初始条件
return(0); }
I2C_SendB(c); if(!I2C_Ack) {
return(0); }
//发送数据
I2C_Stop(); return(1); }
//结束总线
/********************************** ************************************
函数名:void I2C_Ackn(bit a) 入口:0 或 1 出口:
Ackn
功能描述:主控制器进行应答信号(可以是应答或非应答信号)
说明:作为接收方的时候,必须根据当前自己的状态向发送器反馈应答信号 调用函数: 全局变量:
******************************************************************************* ***/
******************************************************************************* ***/
void I2C_Start()
{
SDA = 1;
//发送起始条件的数据信号
_Nop();
SCL = 1;
SomeNOP(); //起始条件建立时间大于 4.7us,延时
I2C_Start
解释: 在 I2C 总线协议中规定的起始位格式是:在 SCL 高电平期间,SDA 发生从高到低的电平 跳变.它与其它数据格式的区别在于,协议中规定有效的数据必须在 SCL 的高电平期间保持 不变,只有在 SCL 的低电平期间才能发生跳变.所以这一有别与其它格式的数据才能做为起 始位. 调用函数: 全局变量:
注意:在传送数据时,数据(SDA)的改变只能发生在 SCL 的低电平期间,在 SCL 的高电平期间 保持不变
调用函数:bit I2C_CheckAck() 全局变量:I2C_Ack
******************************************************************************* ***/
/**********************************
I2C
*************************************
总
线
驱
动
模块名:I2C 总线驱动 型号:I2C
创建人:陈曦 日期:2005-6-15 修改人:陈曦 日期:2005-6-19
功能描述:
此模块包括发送数据及接收数据,应答位发送,并提供了几个直接面对器件的操作函数,能 很 方便的与用户程序进行连接并扩展。
retc = retc<<1;
if(SDA==1)
{ retc = retc + 1;
//读数据位,接收的数据放入 retc 中
}
_nop_();
_nop_();
}
SCL = 0; _nop_(); _nop_();
return(retc); }
/************************************ ************************************