七、STM32中IIC协议
概述
Inter-Integrated Circuit (IIC),也常称为I2C(I squared C),是一种同步、串行、半双工通信总线协议。它主要用于连接低速外围设备到处理器或微控制器上,如MPU6050姿态传感器、OLED显示屏、存储器等。IIC协议具有两根线:时钟线(SCL)和数据线(SDA),这两根线都配置为开漏输出模式,并需要外接上拉电阻(一般为4.7KΩ)。
7.2 STM32中的软件实现
硬件连接
在STM32上实现IIC协议,首先需要将GPIO引脚配置为开漏输出模式,并连接上拉电阻。通常,SCL和SDA分别连接到STM32的两个GPIO引脚。
注意:这里的"Start"和"Stop"是逻辑上的标记,用于表示IIC协议的起始和终止条件。
实际的电信号变化不会直接在时序图中以波形形式展示。
代码部分:
实现软件IIC的软件实现,初始化GPIO。
void MyI2C_Init(void)
{
// 配置RCC
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
// 配置GPIO
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_11|GPIO_Pin_10;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStruct);
GPIO_SetBits(GPIOB,GPIO_Pin_11|GPIO_Pin_10);
}
// 写SCL
void MyI2C_W_SCL(uint8_t BitValue)
{
GPIO_WriteBit(GPIOB,GPIO_Pin_10,(BitAction)BitValue);
Delay_us(10);
}
// 写SDA
void MyI2C_W_SDA(uint8_t BitValue)
{
GPIO_WriteBit(GPIOB,GPIO_Pin_11,(BitAction)BitValue);
Delay_us(10);
}
// 读取SDA的数据
uint8_t MyI2C_R_SDA(void)
{
uint8_t BitValue;
BitValue = GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11);
Delay_us(10);
return BitValue;
}
起始与终止信号
- 起始条件:在SCL为高电平时,SDA由高电平切换到低电平。
- 终止条件:在SCL为高电平时,SDA由低电平切换到高电平。
代码部分:
// 起始信号
void MyI2C_Start(void)
{
MyI2C_W_SDA(1);
MyI2C_W_SCL(1);
Delay_us(1);
MyI2C_W_SDA(0);
Delay_us(1);
MyI2C_W_SCL(0);
}
// 停止信号
void MyI2C_Stop(void)
{
MyI2C_W_SDA(0);
MyI2C_W_SCL(1);
Delay_us(1);
MyI2C_W_SDA(1);
Delay_us(1);
}
发送和接收字节
- 发送一个字节:在SCL低电平期间,主机(通常是STM32微控制器)将数据位依次放到SDA线上(高位先行),然后释放SCL。从机在SCL高电平期间读取数据位,此时SDA上不允许有数据变化。这个过程重复8次,以发送一个完整的字节。
- 接收一个字节:过程与发送相似,但在SCL低电平期间,从机将数据放到SDA上,主机在SCL高电平期间读取。
代码部分:
// 发送数据
void MyI2C_SendByte(uint8_t Byte)
{
uint8_t i;
for(i = 0;i < 8; i++)
{
MyI2C_W_SDA(Byte & (0x80>>i)? 1: 0);
MyI2C_W_SCL(1);
Delay_us(1);
MyI2C_W_SCL(0);
}
}
// 读取数据
uint8_t MyI2C_RecvByte(void)
{
uint8_t i;
uint8_t Byte = 0;
MyI2C_W_SDA(1); // 释放SDA总线
for(i = 0; i < 8; i++)
{
MyI2C_W_SCL(1);
Delay_us(1);
if(MyI2C_R_SDA())
{
Byte |= (0x80>>i);
}
MyI2C_W_SCL(0);
Delay_us(1);
}
return Byte;
}
应答机制
- 发送应答:主机在接收完一个字节后,在下一个时钟周期发送一位数据作为应答,0表示应答(ACK),1表示非应答(NACK)。
- 接收应答:主机在发送完一个字节后,在下一个时钟周期接收一位数据,以判断从机是否应答。
代码部分:
// 发送应答位
void MyI2C_SendAck(uint8_t AckBit)
{
MyI2C_W_SDA(AckBit);
MyI2C_W_SCL(1);
Delay_us(1);
MyI2C_W_SCL(0);
Delay_us(1);
}
// 接收应答位
uint8_t MyI2C_ReceiveAck(void)
{
uint8_t AckBit;
MyI2C_W_SDA(1);
MyI2C_W_SCL(1);
Delay_us(1);
AckBit = MyI2C_R_SDA();
MyI2C_W_SCL(0);
Delay_us(1);
return AckBit;
}
7.3 STM32中IIC硬件实现
…