STM32IIC外设介绍
1、IIC通信协议
IIC通信协议是同步半双工通信协议,支持总线挂载多设备,两根通信线(SCL、SDA),带数据应答功能。
IIC时序基本单元:
起始条件:SCL高电平期间,SDA从高电平切换到低电平,之后SCL切换低电平
终止条件:SCL高电平期间,SDA从低电平切换到高电平
发送一位数据:SCL低电平期间,主机数据放置SDA,释放SCL,从机在SCL高电平期间读取数据,数据高位先行
接收一位数据:SCL低电平期间,从机数据放置SDA,释放SCL,主机在SCL高电平期间读取数据,数据高位先行。主机接收之前,需释放SDA
发送应答:主机接收字节后,发送数据。0表示应答,1表示非应答
接收应答:主机发送字节后,释放SDA接收数据。0表示应答,1表示非应答
2、STM32IIC外设资源
STM32F103C8T6有两个IIC资源,IIC1_SCL引脚为PB6,IIC1_SDA引脚为PB7,IIC2_SCL引脚为PB10,IIC2_SDA引脚为PB11。支持多主机模式,支持7位/10位地址模式。
7位地址:一位读写位,7位地址
10位地址:一位读写位,前5位必须是11110,10位地址
3、软件模拟IIC通信
1、引脚选择,配置时钟和函数封装
软件模拟IIC对引脚没有要求,可以任意引脚,这里选用PB10为SCL,PB11为SDA。
对写SCL、SDA和读SDA进行函数封装。SCL和SDA均要配置成开漏输出模式(Out_OD)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; //开漏输出模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
void IIC_W_SCL(uint8_t BitValue) //写SCL
{
GPIO_WriteBit(GPIOB, GPIO_Pin_10, (BitAction)BitValue);
Delay_us(10);
}
void IIC_W_SDA(uint8_t BitValue) //写SDA
{
GPIO_WriteBit(GPIOB, GPIO_Pin_11, (BitAction)BitValue);
Delay_us(10);
}
uint8_t IIC_R_SDA(void) //读SDA
{
uint8_t BitValue;
BitValue = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11);
Delay_us(10);
return BitValue;
}
2、起始条件
IIC_W_SDA(1);
IIC_W_SCL(1);
IIC_W_SDA(0);
IIC_W_SCL(0);
3、终止条件
IIC_W_SDA(0);
IIC_W_SCL(1);
IIC_W_SDA(1);
4、发送字节
uint8_t i;
for(i=0;i<8;i++) //循环8次,发送字节数据
{
IIC_W_SDA(Byte & (0x80>>i)); //写入Byte某一位
IIC_W_SCL(1);
IIC_W_SCL(0);
}
5.接收字节
uint8_t i, Byte = 0x00;
IIC_W_SDA(1); //接收前先释放SDA
for (i = 0; i < 8; i ++)
{
IIC_W_SCL(1);
if (IIC_R_SDA() == 1){Byte |= (0x80 >> i);}
IIC_W_SCL(0);
}
return Byte;
6、发送应答
IIC_W_SDA(AckBit);
IIC_W_SCL(1);
IIC_W_SCL(0);
7、接收应答
uint8_t AckBit;
IIC_W_SDA(1); //接收前先释放SDA
IIC_W_SCL(1);
AckBit=IIC_R_SDA();
IIC_W_SCL(0);
return AckBit;
4、硬件IIC通信(基于标准库,STM32作为主机)
1、配置时钟
引脚需配置成复用开漏输出模式,选用IIC2外设,IIC2_SCL引脚为PB10,IIC2_SDA引脚为PB11。
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; //复用开漏输出模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
2、IIC结构体配置
I2C_InitTypeDef I2C_InitStructure;
I2C_InitStructure.I2C_Ack=I2C_Ack_Enable; //开启应答
I2C_InitStructure.I2C_AcknowledgedAddress=I2C_AcknowledgedAddress_7bit; //响应7位地址模式
I2C_InitStructure.I2C_ClockSpeed=50000; //时钟数率,标准速度,50KHZ
I2C_InitStructure.I2C_DutyCycle=I2C_DutyCycle_2; //低电平:高电平=2:1,占空比(在时钟数率>100KHZ情况下才有用)
I2C_InitStructure.I2C_Mode=I2C_Mode_I2C; //I2C模式
I2C_InitStructure.I2C_OwnAddress1=0x00; //自主地址(作为从机才使用到)
I2C_Init(I2C2,&I2C_InitStructure);
3、IIC使能
I2C_Cmd(I2C2,ENABLE);
4、IIC相关常用库函数介绍
I2C_CheckEvent(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT); //用于检查具体事件的发生
I2C_GenerateSTART(I2C_TypeDef* I2Cx, FunctionalState NewState); //生成起始条件
I2C_GenerateSTOP(I2C_TypeDef* I2Cx, FunctionalState NewState); //生成终止条件
I2C_Send7bitAddress(I2C_TypeDef* I2Cx, uint8_t Address, uint8_t I2C_Direction); //发送7位地址
I2C_SendData(I2C_TypeDef* I2Cx, uint8_t Data); //发送数据
I2C_AcknowledgeConfig(I2C_TypeDef* I2Cx, FunctionalState NewState); //配置ACK位
5、主发送
void I2C_WaiteEvent(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT) //超时退出机制,避免大量死循环等待
{
uint32_t Time;
Time=10000;
while(I2C_CheckEvent(I2Cx,I2C_EVENT)!=SUCCESS)
{
Time--;
if(Time==0)
{
break;
}
}
}
I2C_GenerateSTART(I2C2,ENABLE);
I2C_WaiteEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT); //检查EV5事件
I2C_Send7bitAddress(I2C2,uint8_t Address,I2C_Direction_Transmitter); //第二个参数写入发送给设备的地址
I2C_WaiteEvent(I2C2,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED); //检查EV6事件
I2C_SendData(I2C2,uint8_t Data); //第二个参数写入发送设备寄存器的地址
I2C_WaiteEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTING); //检查EV8事件
I2C_SendData(I2C2,uint8_t Data); //发送数据
I2C_WaiteEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTED); //检查EV8_2事件
I2C_GenerateSTOP(I2C2,ENABLE);
6、主接收
接收最后一个字节之前,要提前设置ACK和STOP
uint8_t Data;
I2C_GenerateSTART(I2C2,ENABLE);
I2C_WaiteEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT); //检查EV5事件
I2C_Send7bitAddress(I2C2,uint8_t Address,I2C_Direction_Transmitter); //第二个参数写入发送给设备的地址
I2C_WaiteEvent(I2C2,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED); //检查EV6事件
I2C_SendData(I2C2,uint8_t Data); //第二个参数写入发送设备寄存器的地址
I2C_WaiteEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTING); //检查EV8事件
I2C_GenerateSTART(I2C2,ENABLE);
I2C_WaiteEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT); //检查EV5事件
I2C_Send7bitAddress(I2C2, uint8_t Address, I2C_Direction_Receiver); //第二个参数写入需要接收哪个寄存器的地址
I2C_WaiteEvent(I2C2,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED); //检查EV6事件
I2C_AcknowledgeConfig(I2C2,DISABLE); //ACK=0,不给应答
I2C_GenerateSTOP(I2C2,ENABLE);
I2C_WaiteEvent(I2C2,I2C_EVENT_MASTER_BYTE_RECEIVED); //检查EV7事件
Data=I2C_ReceiveData(I2C2);
I2C_AcknowledgeConfig(I2C2,ENABLE); //ACK=1,给应答
return Data;