📄 i2c_bus.c
字号:
/*****************************************************************************
用51单片机模拟I2C总线主器件的程序
注意:
本程序是采用软件延迟的方法产生SCL脉冲,所以对高晶振频率要作
一定的修改(本程序是1us机器周期,即晶振频率要小于12MHz)
开发过程:
2004-3-24 16:41
I2C总线的驱动程序和读写24CXX模块的程序在AT24C02,AT24C16上调试通过
2005-1-11 10:55
将I2C总线的驱动程序和读写24CXX模块的代码分离,I2C总线的驱动程序
在文件I2C_bus.c中,读写24CXX模块的程序在文件I2C_24CXX.c中。
******************************************************************************/
#include "..\..\includes.h"
#if CFG_I2C_BUS_EN > 0
//---------------------------------------------------------
// 启动信号
// 在SCL线为高电平的时候,让SDA从1变到0,就可以产生启动信号
//---------------------------------------------------------
extern void I2C_Start( void )
{
SDA = 1;
_nop_();
SCL = 1;
_nop_(); // 在标准模式下,起始条件的建立时间的最小值为4.7us
_nop_(); // 可以参见《I2C协议标准》第27页
_nop_();
_nop_();
_nop_();
SDA = 0; // 发送起始信号
_nop_(); // 在标准模式下,起始条件的保持时间的最小值为4us
_nop_(); // 可以参见《I2C协议标准》第27页
_nop_();
_nop_();
_nop_();
SCL=0; // 钳住I2C总线,准备发送或接收数据
_nop_();
_nop_();
}
//----------------------------------------------------------
// 结束信号
// 在SCL线为高电平的时候,让SDA从0变到1,就可以产生结束信号
//----------------------------------------------------------
extern void I2C_Stop( void )
{
SDA = 0;
_nop_();
SCL = 1;
_nop_(); // 在标准模式下,结束条件的建立时间的最小值为4us
_nop_(); // 可以参见《I2C协议标准》第27页
_nop_();
_nop_();
_nop_();
SDA = 1; // 发送I2C总线结束信号
_nop_();
_nop_();
_nop_();
_nop_();
SCL = 0;
_nop_();
_nop_();
}
//--------------------------------------------------------
// 发ACK应答信号
//--------------------------------------------------------
extern void I2C_ACK( void )
{
SDA = 0;
_nop_();
_nop_();
_nop_();
SCL = 1;
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
SCL = 0; // 让I2C总线处于等待状态
_nop_();
_nop_();
}
//--------------------------------------------------------
// 发出非ACK应答信号
//--------------------------------------------------------
extern void I2C_UnACK( void )
{
SDA = 1;
_nop_();
_nop_();
_nop_();
SCL = 1;
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
SCL = 0; // 让I2C总线处于等待状态
_nop_();
_nop_();
}
//----------------------------------------------------------------
// 判断接收器在接收完一个字节的数据以后,是否返回应答信号
//
// 如果返回应答信号, 函数返回TRUE
// 如果没有返回应答信号,函数返回FALSE
//----------------------------------------------------------------
extern BOOLEAN I2C_IsACK( void )
{
BOOLEAN isACK;
_nop_();
_nop_();
SDA = 1; // 8位数据发送完以后,发送器件释放数据线,准备接收应答
_nop_();
_nop_();
SCL = 1;
_nop_();
_nop_();
_nop_();
if( SDA==0 ) // 判断接收器是否返回应答信号
{
isACK = TRUE;
}
else
{
isACK = FALSE;
}
SCL = 0;
_nop_();
_nop_();
return isACK;
}
//--------------------------------------------------------------------
// 接收发送器件传来的数据
//
// 返回值:函数返回接收到的数据
//
// 注意事项:
// 在本函数中,并不负责返回ACK应答信号给发送器件,所以,在调用完
// 本函数以后,需要调用发ACK应答信号函数(或者发非ACK应答信号函数)
//--------------------------------------------------------------------
extern INT8U I2C_ReceiveByte( void )
{
INT8U i, receive;
receive = 0;
SDA = 1; // 置数据线为输入方式
for( i=0; i<8; i++ )
{
_nop_();
SCL = 0; // 置时钟线为低,准备接收数据位
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
SCL = 1; // 置时钟线为高,让SDA数据线上数据有效
_nop_();
_nop_();
receive <<= 1;
if( SDA==1 ) // 读取一位数据位
{
receive |= 0x01;
}
_nop_();
_nop_();
}
SCL = 0;
_nop_();
_nop_();
return receive;
}
//-------------------------------------------------------------------------
// 发送一个字节
//
// 参数: ch是将要发送的一个字节数据
//
// 返回值:
// 如果发送器收到接收器返回的ACK应答信号, 函数返回TRUE
// 如果发送器没有收到接收器返回的ACK应答信号,函数返回FALSE
//
// 注意事项:
// 在本函数中,已经完成了释放数据线,等待接收器件返回应答信号这些操作,
// 所以,在调用本函数以后,不要再去重复这些功能。
//-------------------------------------------------------------------------
extern BOOLEAN I2C_SendByte( INT8U ch )
{
INT8U i;
for( i=0; i<8; i++ ) // 从字节的高位开始逐位发送,一个字节有8位,所以重复8次
{
if( ( (ch<<i)&0x80 ) != 0 )
SDA = 1;
else
SDA = 0;
_nop_();
SCL = 1; // 置时钟线为高,让SDA线上的数据位有效
_nop_();
_nop_();
_nop_();
_nop_();
SCL = 0;
}
return I2C_IsACK();
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -