📄 i2c_c51.c
字号:
/************************************************************************************************
** MCS-51系列单片机模拟I2C软件包(V1.2)
** 文件名 :I2C_C51.C
** 相关文件:I2C_C51.H
** 功能说明:本模拟I2C软件包包含了I2C操作的底层函数,如发送数据及接收数据,应答位发送,并提供
了几个直接面对器件的操作函数,它很方便的与用户程序连接并扩展.....
** 注 意: 函数是采用软件延时的方法产生SCL脉冲,固对高晶振频率要作一定的修改....
(本软件包是1us机器周期,即晶振频率要小于12MHZ)
** 总线时序符合I2C标准模式,100Kbit/S。
** 更新时间:2002.06.05
************************************************************************************************/
#include "INCLUDE.H"
sbit SDA = P0^1; //模拟I2C数据传送位
sbit SCL = P0^0; //模拟I2C时钟控制位
#define SDA_InPut() {P0MDOUT &= ~0x02; P0 |= 0x02;}
#define SDA_OutPut() {P0MDOUT |= 0x02; }
bit ack; //应答标志位
/*******************************************************************
** 起动I2C总线函数
** 函数原型: void Start_I2c();
** 功 能: 启动I2C总线,即发送I2C起始条件.
** ________________
SCL .... \ 0
1 \___________________
_________
SDA .... 1 \ 0
\____________________________
**
**----------------------------------------------------------------------------------------------------
** 作 者 : 严俊生
** 日 期 : 2007-07-15
**----------------------------------------------------------------------------------------------------
** 修改人 :
** 日 期 :
********************************************************************/
static void Start_I2c(void)
{
SDA_OutPut();
SDA = 1; _nop_(); //发送起始条件的数据信号
SCL = 1; _nop_(); //起始条件建立时间大于4.7us,延时
_nop_(); _nop_();
_nop_(); _nop_();
SDA = 0; _nop_(); //发送起始信号
_nop_(); _nop_(); //起始条件锁定时间大于4μs
_nop_(); _nop_();
SCL = 0; //钳住I2C总线,准备发送或接收数据
_nop_(); _nop_();
}
/********************************************************************************************************
** 结束I2C总线函数
** 函数原型: void Stop_I2c();
** 功 能: 结束I2C总线,即发送I2C结束条件.
** ________________________________
SCL .... 0 /
___/ 1
_________________________
SDA .... 0 /
_________/ 1
**
**----------------------------------------------------------------------------------------------------
** 作 者 : 严俊生
** 日 期 : 2007-07-15
**----------------------------------------------------------------------------------------------------
** 修改人 :
** 日 期 :
********************************************************************************************************/
void Stop_I2c()
{
SDA_OutPut();
SDA = 0; _nop_(); //发送结束条件的数据信号和发送结束条件的时钟信号
SCL = 1; _nop_(); //结束条件建立时间大于4μs
_nop_(); _nop_();
_nop_(); _nop_();
SDA = 1; _nop_(); //发送I2C总线结束信号
_nop_(); _nop_();
}
/******************************************************************************************************
** I2C字节数据发送函数
** 函数原型: void SendByte(uchar c);
** 功 能: 将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对此状态位进行操作.(不应答或非应答
** 都使ack=0)。发送数据正常,ack=1; ack=0表示被控器无应答或损坏。
** 入口参数:c 要发送到I2C总线上的数据或者是地址
**
**----------------------------------------------------------------------------------------------------
** 作 者 : 严俊生
** 日 期 : 2007-07-15
**----------------------------------------------------------------------------------------------------
** 修改人 :
** 日 期 :
******************************************************************************************************/
void SendByte(uchar c)
{ uchar BitCnt;
SDA_OutPut();
for(BitCnt=0;BitCnt<8;BitCnt++) //要传送的数据长度为8位
{
if((c<<BitCnt)&0x80) SDA = 1; //判断发送位
else SDA = 0;
_nop_();
SCL=1; _nop_(); //置时钟线为高,通知被控器开始接收数据位
_nop_(); _nop_(); //保证时钟高电平周期大于4μs
_nop_(); _nop_();
SCL=0;
}
_nop_(); _nop_();
SDA = 1; //8位发送完后释放数据线,准备接收应答位*/
_nop_(); _nop_();
SDA_InPut();
SCL = 1; _nop_();
_nop_(); _nop_();
if(SDA == 1) ack = 0;
else ack = 1; //判断是否接收到应答信号*/
SCL = 0;
_nop_(); _nop_();
}
/******************************************************************************************************
** I2C字节数据接收函数
** 函数原型: uchar RcvByte();
** 功 能: 用来接收从器件传来的数据,并判断总线错误(不发应答信号),发完后请用应答函数应答从机。
** 入口参数:无
** 返回参数:从I2C上接受到的数据
**
**----------------------------------------------------------------------------------------------------
** 作 者 : 严俊生
** 日 期 : 2007-07-15
**----------------------------------------------------------------------------------------------------
** 修改人 :
** 日 期 :
******************************************************************************************************/
#if IRcvStr_EN
uchar RcvByte(void)
{uchar retc=0,BitCnt;
SDA = 1; //置数据线为输入方式
SDA_InPut();
for(BitCnt=0;BitCnt<8;BitCnt++)
{
_nop_(); SCL = 0; //置时钟线为低,准备接收数据位
_nop_(); _nop_(); //时钟低电平周期大于4.7μs
_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);
}
#endif
/******************************************************************************************************
** I2C应答子函数
** 函数原型: void Ack_I2c(bit a);
** 功 能: 主控器进行应答信号(可以是应答或非应答信号,由位参数a决定)
**
**----------------------------------------------------------------------------------------------------
** 作 者 : 严俊生
** 日 期 : 2007-07-15
**----------------------------------------------------------------------------------------------------
** 修改人 :
** 日 期 :
******************************************************************************************************/
#if IRcvStr_EN
void Ack_I2c(bit a)
{
SDA_OutPut();
if(a == 0) SDA = 0; //在此发出应答或非应答信号
else SDA = 1;
_nop_();
_nop_(); _nop_();
SCL = 1; _nop_();
_nop_(); _nop_(); //时钟低电平周期大于4μs
_nop_(); _nop_();
SCL = 0; //清时钟线,钳住I2C总线以便继续接收
_nop_(); _nop_();
}
#endif
/******************************************************************************************************
**
** I2C用户对外接口函数
**
******************************************************************************************************/
/**=================== 以下为IIC写程序 ======================**/
/******************************************************************************************************
** 向无子地址器件发送字节数据函数
** 函数原型: bit ISendByte(uchar sla,ucahr c);
** 功 能: 从启动总线到发送地址,数据,结束总线的全过程,从器件地址sla.如果返回1表示操作成功,否则
操作有误。
** 入口参数:sla 器件从地址
c 需要向器件中发送的字节数据
** 返回参数:操作成功与否标志
** 注意: 使用前必须已结束总线。
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -