IIC通信协议
IIC(Inter- Integrated Circuit)总线是一种由 PHILIPS 公司开发的两线式串行总线,用于连接微控制器及其外围设备。它是由数据线 SDA 和时钟 SCL 构成的串行总线,可发送和接收数据。在 CPU 与被控 IC 之间、 IC 与 IC 之间进行双向传送, 高速 IIC 总线一般可达 400kbps 以上。
I2C 总线在传送数据过程中共有三种类型信号, 它们分别是:开始信号、结束信号和应答信号。
开始信号: SCL 为高电平时, SDA 由高电平向低电平跳变,开始传送数据。
结束信号: SCL 为高电平时, SDA 由低电平向高电平跳变,结束传送数据。
应答信号:接收数据的 IC 在接收到 8bit 数据后,向发送数据的 IC 发出特定的低电平脉冲,
表示已收到数据。 CPU 向受控单元发出一个信号后,等待受控单元发出一个应号, CPU 接
收到应答信号后,根据实际情况作出是否继续传递信号的判断。若未收到应答信号,由判断为受控单元出现故障。
这些信号中,起始信号是必需的,结束信号和应答信号,都可以不要。 IIC 总线时序图:

1.初始化:IIC的初始化为SDA和SCL均为高。
2.开始信号:处理器让SCL时钟保持高电平,然后让SDA数据信号由高变低就表示一个开始信号。同时IIC总线上的设备检测到这个开始信号它就知道处理器要发送数据了。
3.停止信号:处理器让SCL时钟保持高电平,然后让SDA数据信号由低变高就表示一个停止信号。同时IIC总线上的设备检测到这个停止信号它就知道处理器已经结束了数据传输,我们就可以各忙各个的了,如休眠等。

4.数据传输:SDA上的数据只能在SCL为低电平期间翻转变化,在SCL为高电平期间必须保持稳定,IIC设备只在SCL为高电平期间采集SDA数据。
5.响应信号(ACK):单片机发完8bit数据后就不再驱动总线了(SDA引脚变输入),而SDA和SDL硬件设计时都有上拉电阻,所以这时候SDA变成高电平。那么在第8个数据位,如果外接IIC设备能收到信号的话接着在第9个周期把SDA拉低,那么处理器检测到SDA拉低就能知道外接IIC设备数据已经收到。IIC数据从最高位开始传输(小端传输)。

6.单片机读操作的大致流程:首先单片机发送起始信号,接着使用写操作进行芯片寻址0xa0,接着定位片内子地址address,因为我们要读数据,但是刚才使用的是写操作进行芯片寻址,我们要把R/W位设置成读操作才可以对address处数据进行读操作,所以接下来需要重新发送一个起始位,接着使用读操作进行芯片寻址0xa1,接着单片机从IIC总线中读取8位数据保存到变量中,最后单片机发送一个结束信号完成整个读过程,其中中间夹杂着应答过程。

7.单片机写数据的大致流程:首先发送起始信号,接着使用写操作芯片寻址0xa0,接着进行片内子地址寻址address,接着向address写入info,最后发送停止信号,其中中间夹杂着应答的过程。

STM32 L4 IO模拟IIC
#include "IOI2C.h"
static void I2C_Delay(void)
{
uint8_t i;
/*
下面的时间是通过逻辑分析仪测试得到的。
CPU主频72MHz时,在内部Flash运行, MDK工程不优化
循环次数为10时,SCL频率 = 205KHz
循环次数为7时,SCL频率 = 347KHz, SCL高电平时间1.5us,SCL低电平时间2.87us
循环次数为5时,SCL频率 = 421KHz, SCL高电平时间1.25us,SCL低电平时间2.375us
IAR工程编译效率高,不能设置为7
*/
for (i = 0; i < 25; i++);
}
//毫秒级的延时
void delay_ms(u16 time)
{
u16 i=0;
while(time--)
{
i=12000; //自己定义
while(i--) ;
}
}
void IIC_Init(void)
{
GPIO_InitTypeDef GPIO_Initure;
__HAL_RCC_GPIOH_CLK_ENABLE(); //使能GPIOH时钟
//PH4,5初始化设置
GPIO_Initure.Pin=GPIO_PIN_4|GPIO_PIN_5;
GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP; //推挽输出
GPIO_Initure.Pull=GPIO_PULLUP; //上拉
GPIO_Initure.Speed=GPIO_SPEED_FAST; //快速
HAL_GPIO_Init(GPIOH,&GPIO_Initure);
I2C_SDA_HIGH;
I2C_SCL_HIGH;
}
//产生IIC起始信号
void IIC_Start(void)
{
I2C_SDA_HIGH;
I2C_SCL_HIGH;
I2C_Delay();
I2C_SDA_LOW;//START:when CLK is high,DATA change form high to low
I2C_Delay();
I2C_SCL_LOW;//钳住I2C总线,准备发送或接收数据
}
//产生IIC停止信号
void IIC_Stop(void)
{
I2C_SCL_LOW;
I2C_SDA_LOW;//STOP:when CLK is high DATA change form low to high
I2C_Delay();
I2C_SCL_HIGH;
I2C_Delay();
I2C_SDA_HIGH;//发送I2C总线结束信号
}
//等待应答信号到来
//返回值:1,接收应答失败
// 0,接收应答成功
u8 IIC_Wait_Ack(void)
{
u8 ucErrTime=0;
I2C_SDA_HIGH;I2C_Delay();
I2C_SCL_HIGH;I2C_Delay();
while(I2C_SDA_READ)
{
ucErrTime++;
if(ucErrTime>250)
{
IIC_Stop();
return 1;
}
}
I2C_SCL_LOW;//时钟输出0
return 0;
}
//产生ACK应答
void IIC_Ack(void)
{
I2C_SCL_LOW;
I2C_SDA_LOW;
I2C_Delay();
I2C_SCL_HIGH;
I2C_Delay();
I2C_SCL_LOW;
}
//不产生ACK应答
void IIC_NAck(void)
{
I2C_SCL_LOW;
I2C_SDA_HIGH;
I2C_Delay();
I2C_SCL_HIGH;
I2C_Delay();
I2C_SCL_LOW;
}
void IIC_Send_Byte(u8 txd)
{
uint8_t i;
I2C_SCL_LOW;//拉低时钟开始数据传输
/* 先发送字节的高位bit7 */
for (i = 0; i < 8; i++)
{
if (txd & 0x80)
{
I2C_SDA_HIGH;
}
else
{
I2C_SDA_LOW;
}
I2C_Delay();
I2C_SCL_HIGH;
I2C_Delay();
I2C_SCL_LOW;
if (i == 7)
{
I2C_SDA_HIGH; // 释放总线
}
txd <<= 1; /* 左移一个bit */
I2C_Delay();
}
}
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK
u8 IIC_Read_Byte(unsigned char ack)
{
unsigned char i,receive=0;
for(i=0;i<8;i++ )
{
I2C_SCL_LOW;
I2C_Delay();
I2C_SCL_HIGH;
receive<<=1;
if(I2C_SDA_READ)receive++;
I2C_Delay();
}
if (!ack)
IIC_NAck();//发送nACK
else
IIC_Ack(); //发送ACK
return receive;
}
#ifndef _IOI2C_H
#define _IOI2C_H
#include "user_inc.h"
#define I2C_SCL_HIGH HAL_GPIO_WritePin(EEPROM_SCL_GPIO_Port,EEPROM_SCL_Pin,GPIO_PIN_SET) // 输出高电平
#define I2C_SCL_LOW HAL_GPIO_WritePin(EEPROM_SCL_GPIO_Port,EEPROM_SCL_Pin,GPIO_PIN_RESET) // 输出低电平
#define I2C_SDA_HIGH HAL_GPIO_WritePin(EEPROM_SDA_GPIO_Port,EEPROM_SDA_Pin,GPIO_PIN_SET) // 输出高电平
#define I2C_SDA_LOW HAL_GPIO_WritePin(EEPROM_SDA_GPIO_Port,EEPROM_SDA_Pin,GPIO_PIN_RESET) // 输出低电平
#define I2C_SDA_READ HAL_GPIO_ReadPin(EEPROM_SDA_GPIO_Port ,EEPROM_SDA_Pin)
//IIC所有操作函数
void IIC_Init(void); //初始化IIC的IO口
void IIC_Start(void); //发送IIC开始信号
void IIC_Stop(void); //发送IIC停止信号
void IIC_Send_Byte(u8 txd); //IIC发送一个字节
u8 IIC_Read_Byte(unsigned char ack);//IIC读取一个字节
u8 IIC_Wait_Ack(void); //IIC等待ACK信号
void IIC_Ack(void); //IIC发送ACK信号
void IIC_NAck(void); //IIC不发送ACK信号
void IIC_Write_One_Byte(u8 daddr,u8 addr,u8 data);
u8 IIC_Read_One_Byte(u8 daddr,u8 addr);
void delay_ms(u16 time);
#endif

浙公网安备 33010602011771号