模块名:I2C总线驱动 型号:I2C
功能描述: 此模块包括发送数据及接收数据,应答位发送,并提供了几个直接面对器件的操作函数,能很 方便的与用户程序进行连接并扩展。 需要注意的是,函数是采用延时方法产生 SCL 脉冲,对高晶振频率要做一定的修改!! 在写E2PROM的时候一定要延时!!! 说明: 1us机器周期,晶振频率要小于12MHz 返回 1 则操作成功,返回 0 则操作失败。 sla 为器件从地址,suba 为器件子地址。 *************************************************************************************/ #include "AT89X52.h" #include #define _Nop() _nop_() //定义空指令 sbit SDA = P1^3; //模拟I2C数据传输位 sbit SCL = P1^2; //模拟I2C时钟控制位 bit bdata I2C_Ack; //应答标志位 /************************************ I2C_Start ************************************ 函数名:void I2C_Start() 入口: 出口: 功能描述:启动I2C总线,即发送I2C初始条件 调用函数: 全局变量: 创建者:陈曦 日期:2005-6-15 修改者: 日期: **********************************************************************************/ void I2C_Start() { SDA = 1; //发送起始条件的数据信号 _Nop(); SCL = 1; _Nop(); //起始条件建立时间大于4.7us,延时 _Nop(); _Nop(); _Nop(); _Nop(); SDA = 0; //发送起始信号 _Nop(); //起始条件建立时间大于4us,延时 _Nop(); _Nop(); _Nop(); _Nop(); SCL = 0; //钳住I2C总线准备发送或接收数据 _Nop(); _Nop(); } /************************************ I2C_Stop ************************************
函数名:void I2C_Stop() 入口: 出口: 功能描述:结束I2C总线,即发送I2C结束条件 调用函数: 全局变量: 创建者:陈曦 日期:2005-6-15 修改者: 日期: **********************************************************************************/ void I2C_Stop() { SDA = 0; //发送结束条件的数据信号 _Nop(); SCL = 1; //发送结束条件的时钟信号 _Nop(); //结束条件建立时间大于4us,延时 _Nop(); _Nop(); _Nop(); _Nop(); SDA = 1; //发送I2C总线结束信号 _Nop(); _Nop(); _Nop(); _Nop(); }
/************************************ I2C_CheckAck ************************************ 函数名:bit I2C_CheckAck(void) 入口: 出口:0(无应答),1(有应答) 功能描述: 检验I2C总线应答信号,有应答则返回1,否则返回0,超时值取255 调用函数:void I2C_Stop() 全局变量: 创建者:陈曦 日期:2005-6-15 修改者: 日期: **********************************************************************************/ bit I2C_CheckAck(void) { uchar errtime = 255; // 因故障接收方无 Ack,超时值为255 SDA = 1; _Nop(); _Nop(); _Nop(); SCL = 1; _Nop(); //时钟电平周期大于 4 us _Nop(); _Nop(); _Nop(); _Nop(); while(SDA) { errtime--; if(errtime==0) { I2C_Stop(); return(0); } } SCL = 0; _Nop(); return(1); } /************************************ I2C_SendB ************************************ 函数名:void I2C_SendB(uchar c) 入口:uchar 型数据 出口: 功能描述: 字节数据传送函数,将数据 c 发送出去,可以是地址,也可以是数据,发完后等待应答,并对 此状态位进行操作 调用函数:bit I2C_CheckAck() 全局变量:I2C_Ack 创建者:陈曦 日期:2005-6-15 修改者: 日期: **********************************************************************************/ void I2C_SendB(uchar c) { uchar BitCnt; for (BitCnt=0; BitCnt<8; BitCnt++) //要传送的数据长度为8位 { if((c< { SDA = 1; } else { SDA = 0; } _Nop(); _Nop(); SCL = 1; //置时钟线为高通知被控器开始接收数据位 _Nop(); //保证时钟高电平周期大于 4us _Nop(); _Nop(); _Nop(); _Nop(); SCL = 0; } _Nop(); _Nop(); I2C_Ack = I2C_CheckAck(); //检验应答信号 _Nop(); _Nop(); } /************************************ I2C_RcvB ************************************
函数名:uchar I2C_RcvB() 入口: 出口:uchar型数据 功能描述: 接收从器件传来的数据,并判断总线错误(不发应答信号),收完后需要调用应答函数。 调用函数: 全局变量: 创建者:陈曦 日期:2005-6-15 修改者: 日期: **********************************************************************************/ uchar I2C_RcvB() { uchar retc; uchar BitCnt; //位 retc = 0; SDA = 1; //置数据总线为输入方式 for(BitCnt=0;BitCnt<8;BitCnt++) { _Nop(); SCL = 0; //置时钟线为低准备接收数据位 _Nop(); //时钟低电平周期大于4.7us _Nop(); _Nop(); _Nop(); _Nop(); SCL = 1; //置时钟线为高使数据有效 _Nop(); _Nop(); retc = retc<<1; if(SDA==1) { retc = retc + 1; //读数据位,接收的数据放入retc中 } _Nop(); _Nop(); } SCL = 0; _Nop(); _Nop(); return(retc); } /************************************ I2C_Ackn ************************************ 函数名:void I2C_Ackn(bit a) 入口:0或1 出口: 功能描述:主控制器进行应答信号(可以是应答或非应答信号) 调用函数: 全局变量: 创建者:陈曦 日期:2005-6-15 修改者: 日期: **********************************************************************************/ void I2C_Ackn(bit a) { if(a==0) //在此发送应答或非应答信号 { SDA = 0; } else { SDA = 1; } _Nop(); _Nop(); _Nop(); SCL = 1; _Nop(); //时钟电平周期大于 4 us _Nop(); _Nop(); _Nop(); _Nop(); SCL = 0; //清时钟线钳住I2C总线以便继续接收 _Nop(); _Nop(); }
/******************************** I2C_ISendB ************************************ 函数名:bit I2C_ISendB(uchar sla, uchar suba, uchar c) 入口:从器件地址 sla,子地址 suba, 发送字节 c 出口:0(操作有误),1(操作成功) 功能描述:从启动总线到发送地址、数据,结束总线的全过程, 如果返回1,表示操作成功,否则操作有误。 调用函数:I2C_Start(),I2C_SendB(uchar c),I2C_Stop() 全局变量:I2C_Ack 创建者:陈曦 日期:2005-6-15 修改者: 日期: **********************************************************************************/ 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) { return(0); } I2C_SendB(c); //发送数据 if(!I2C_Ack) { return(0); } I2C_Stop(); //结束总线 return(1); } /********************************** I2C_IRcvB ************************************ 函数名:bit I2C_IRcvB(uchar sla, uchar suba, uchar *c) 入口:从器件地址 sla, 子地址 suba, 收到的数据在 c 出口:1(操作成功),0(操作有误) 功能描述:从启动总线到发送地址、读数据,结束总线的全过程。 调用函数: I2CS_tart(), I2C_SendB(uchar c), I2C_RcvB(), I2C_Ackn(bit a), I2C_Stop() 全局变量:I2C_Ack 创建者:陈曦 日期:2005-5-15 修改者: 日期: **********************************************************************************/ bit I2C_IRcvB(uchar sla, uchar suba, uchar *c) { I2C_Start(); //启动总线 I2C_SendB(sla); if(!I2C_Ack) { return(0); } I2C_SendB(suba); //发送器件子地址 if(!I2C_Ack) { return(0); } I2C_Start(); //重复起始条件 I2C_SendB(sla+1); //发送读操作的地址 if(!I2C_Ack) { return(0); } *c = I2C_RcvB(); //读取数据 I2C_Ackn(1); //发送非应答位 I2C_Stop(); //结束总线 return(1); }
|