简介
此篇只对bsp_i2c_gpio库进行讲解,运用起来是跟硬件i2c的原理一样的,此篇纯靠个人理解解读,欢迎指出错误。
我的步骤是根据代码解读的,可以结合着一起看
函数
//起始信号函数
void i2c_Start(void);
//终止信号函数
void i2c_Stop(void);
//发送byte数据函数
void i2c_SendByte(uint8_t _ucByte);
//读取byte数据函数
uint8_t i2c_ReadByte(void);
//等待响应函数
uint8_t i2c_WaitAck(void);
//应答ack函数
void i2c_Ack(void);
//非应答noack函数
void i2c_NAck(void);
//检查设备函数
uint8_t i2c_CheckDevice(uint8_t _Address);
i2c_Delay函数
简介
相当于i2c在每个周期的时间,每次高低电平的等待时间
代码
/*
*********************************************************************************************************
* 函 数 名: i2c_Delay
* 功能说明: I2C总线位延迟,最快400KHz
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
static void i2c_Delay(void)
{
uint8_t i;
/*
可用逻辑分析仪测量I2C通讯时的频率
工作条件:CPU主频168MHz ,MDK编译环境,1级优化
经测试,循环次数为20~250时都能通讯正常
*/
for (i = 0; i < 40; i++);
}
i2c_Start函数
简介
发送起始信号,从来自i2c总线协议手册下图可以看出,在SCL为高时,SDA由高转低完成发送起始信号
代码
/*
*********************************************************************************************************
* 函 数 名: i2c_Start
* 功能说明: CPU发起I2C总线启动信号
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
void i2c_Start(void)
{
/* 当SCL高电平时,SDA出现一个下跳沿表示I2C总线启动信号 */
EEPROM_I2C_SDA_1();
EEPROM_I2C_SCL_1();
i2c_Delay();
EEPROM_I2C_SDA_0();
i2c_Delay();
EEPROM_I2C_SCL_0();
i2c_Delay();
}
i2c_Stop函数
简介
发送停止信号,从来自i2c总线协议手册下图可以看出,在SCL为高时,SDA由低转高完成发送起始信号
代码
/*
*********************************************************************************************************
* 函 数 名: i2c_Stop
* 功能说明: CPU发起I2C总线停止信号
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
void i2c_Stop(void)
{
/* 当SCL高电平时,SDA出现一个上跳沿表示I2C总线停止信号 */
EEPROM_I2C_SDA_0();
EEPROM_I2C_SCL_1();
i2c_Delay();
EEPROM_I2C_SDA_1();
}
i2c_SendByte函数
简介
向i2c总线发送1byte数据(也就是8bit)
步骤:
代码
/*
*********************************************************************************************************
* 函 数 名: i2c_SendByte
* 功能说明: CPU向I2C总线设备发送8bit数据
* 形 参:_ucByte : 等待发送的字节
* 返 回 值: 无
*********************************************************************************************************
*/
void i2c_SendByte(uint8_t _ucByte)
{
uint8_t i;
/* 先发送字节的高位bit7 */
for (i = 0; i < 8; i++)
{
if (_ucByte & 0x80)
{
EEPROM_I2C_SDA_1();
}
else
{
EEPROM_I2C_SDA_0();
}
i2c_Delay();
EEPROM_I2C_SCL_1();
i2c_Delay();
EEPROM_I2C_SCL_0();
if (i == 7)
{
EEPROM_I2C_SDA_1(); // 释放总线
}
_ucByte <<= 1; /* 左移一个bit */
i2c_Delay();
}
}
i2c_ReadByte函数
简介
CPU从i2c总线读取1byte的数据
例子:vlaue=0 要读取 0b1011 0101 数据
要传入的数据 | 左位移后 | 写入后 |
1 | 0000 0000 | 0000 0001 |
0 | 0000 0010 | 0000 0010 |
1 | 0000 0100 | 0000 0101 |
1 | 0000 1010 | 0000 1011 |
0 | 0001 0110 | 0001 0110 |
1 | 0010 1100 | 0010 1101 |
0 | 0101 1010 | 0101 1010 |
1 | 1011 0100 | 1011 0101 |
这样我们就完整的读到了1byte的数据,从代码完整的解决了从高位传入数据的问题
结合代码看我的步骤
代码
/*
*********************************************************************************************************
* 函 数 名: i2c_ReadByte
* 功能说明: CPU从I2C总线设备读取8bit数据
* 形 参:无
* 返 回 值: 读到的数据
*********************************************************************************************************
*/
uint8_t i2c_ReadByte(void)
{
uint8_t i;
uint8_t value;
/* 读到第1个bit为数据的bit7 */
value = 0;
for (i = 0; i < 8; i++)
{
value <<= 1;
EEPROM_I2C_SCL_1();
i2c_Delay();
if (EEPROM_I2C_SDA_READ())
{
value++;
}
EEPROM_I2C_SCL_0();
i2c_Delay();
}
return value;
}
i2c_WaitAck函数
是每次发送完8bit的数据后的一个等待应答ack函数
代码
/*
*********************************************************************************************************
* 函 数 名: i2c_WaitAck
* 功能说明: CPU产生一个时钟,并读取器件的ACK应答信号
* 形 参:无
* 返 回 值: 返回0表示正确应答,1表示无器件响应
*********************************************************************************************************
*/
uint8_t i2c_WaitAck(void)
{
uint8_t re;
EEPROM_I2C_SDA_1(); /* CPU释放SDA总线 */
i2c_Delay();
EEPROM_I2C_SCL_1(); /* CPU驱动SCL = 1, 此时器件会返回ACK应答 */
i2c_Delay();
if (EEPROM_I2C_SDA_READ()) /* CPU读取SDA口线状态 */
{
re = 1;
}
else
{
re = 0;
}
EEPROM_I2C_SCL_0();
i2c_Delay();
return re;
}
i2c_Ack与i2c_NAck函数
简介
下图是i2c总线协议的介绍,看起来很繁杂其实就那么几句话,SCL和SDA的信号搭配
总结一下 ![](https://img-blog.csdnimg.cn/c2f14d214d804024a1f61a839a6a03d0.png)
代码
/*
*********************************************************************************************************
* 函 数 名: i2c_Ack
* 功能说明: CPU产生一个ACK信号
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
void i2c_Ack(void)
{
EEPROM_I2C_SDA_0(); /* CPU驱动SDA = 0 */
i2c_Delay();
EEPROM_I2C_SCL_1(); /* CPU产生1个时钟 */
i2c_Delay();
EEPROM_I2C_SCL_0();
i2c_Delay();
EEPROM_I2C_SDA_1(); /* CPU释放SDA总线 */
}
/*
*********************************************************************************************************
* 函 数 名: i2c_NAck
* 功能说明: CPU产生1个NACK信号
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
void i2c_NAck(void)
{
EEPROM_I2C_SDA_1(); /* CPU驱动SDA = 1 */
i2c_Delay();
EEPROM_I2C_SCL_1(); /* CPU产生1个时钟 */
i2c_Delay();
EEPROM_I2C_SCL_0();
i2c_Delay();
}
i2c_CheckDevice函数
简介
检测I2C总线设备,CPU向发送设备地址,然后读取设备应答来判断该设备是否存在
代码
/*
*********************************************************************************************************
* 函 数 名: i2c_CheckDevice
* 功能说明: 检测I2C总线设备,CPU向发送设备地址,然后读取设备应答来判断该设备是否存在
* 形 参:_Address:设备的I2C总线地址
* 返 回 值: 返回值 0 表示正确, 返回1表示未探测到
*********************************************************************************************************
*/
uint8_t i2c_CheckDevice(uint8_t _Address)
{
uint8_t ucAck;
i2c_CfgGpio(); /* 配置GPIO */
i2c_Start(); /* 发送启动信号 */
/* 发送设备地址+读写控制bit(0 = w, 1 = r) bit7 先传 */
i2c_SendByte(_Address | EEPROM_I2C_WR);
ucAck = i2c_WaitAck(); /* 检测设备的ACK应答 */
i2c_Stop(); /* 发送停止信号 */
return ucAck;
}
手写笔记有点丑,见谅