STM32硬件IIC使用
概述
虽然STM32的硬件IIC据说有设计缺陷,但是经过我的实践,至少STM32F103的硬件IIC是没问题的。这里给出STM32的硬件IIC的使用以及编程思路。
1.STM32硬件IIC引脚
在这里给出STM32F103的硬件IIC引脚,方便查阅使用
2.STM32硬件IIC使用流程
STM32的硬件IIC我认为是非常具有借鉴意义的,它使用了事件组的一个流程。以stm32为主设备,iic设备为从设备为例,主设备需要先向从设备发送开始信号,这个是iic协议所规定的,之后iic总线上的应答信号会转化成EV5事件(一个标志量)。没错,STM32把一次完整的IIC数据传输依据IIC总线上的应答给拆分成了5个事件,每个事件代表一个传输事件完成。这是我第一次在freertos外的设备上见到事件组。
如图所示,在STM32上,硬件IIC事件组共有9个,在以STM32为主设备的情况下,仅有5个事件需要注意。其中EV5代表IIC模式设置完成,EV6代表IIC发送或接收模式设置,EV7代表IIC接收完成,EV8代表发送中,EV8_2代表发送完成。
具体代码实现
在这里以STM32上的IIC1为例
IIC初始化
1.IIC以及GPIO时钟使能
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//打开GPIO时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);//打开IIC时钟
2.GPIO设置
GPIO_InitTypeDef IIC_Gpio;//定义GPIO结构体
IIC_Gpio.GPIO_Pin |= GPIO_Pin_6 | GPIO_Pin_7;//设置IIC引脚
IIC_Gpio.GPIO_Mode = GPIO_Mode_AF_OD;//设置GPIO模式为复用推挽输出
IIC_Gpio.GPIO_Speed = GPIO_Speed_50MHz;//设置GPIO速度为50MHz
GPIO_Init(GPIOB,&IIC_Gpio);//载入GPIO结构体
3.IIC设置
I2C_DeInit(I2C1);//初始化IIC1
I2C_InitTypeDef IIC_InitStruct;//定义IIC结构体
IIC_InitStruct.I2C_ClockSpeed = 400000;//设置IIC时钟为400KHz,STM32硬件IIC最大到400KHz
IIC_InitStruct.I2C_Mode = I2C_Mode_I2C;//设置IIC模式为I2C
IIC_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2;//设置IIC占空比为2
IIC_InitStruct.I2C_OwnAddress1 = 0x21;//设置IIC本机地址,可以随意设置,只要不与要通信的设备冲突即可
IIC_InitStruct.I2C_Ack = I2C_Ack_Enable;//设置IIC应答
IIC_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;//设置IIC应答地址长度
I2C_Init(I2C1,&IIC_InitStruct);//载入IIC结构体
4.IIC使能
I2C_Cmd(I2C1,ENABLE);
IIC发送
IIC发送单字节
I2C_GenerateSTART(I2C1,ENABLE);//生成开始信号
IIC_WaitEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT);//等待IIC模式设置开始即EV5事件
I2C_Send7bitAddress(I2C1,Address,I2C_Direction_Transmitter);//发送从设备地址+读写位
IIC_WaitEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);//等待IIC模式设置完成即EV6事件
I2C_SendData(I2C1,data);//发送数据
IIC_WaitEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED);//等待数据发送完成即EV8_2事件
I2C_GenerateSTOP(I2C1,ENABLE);//生成停止信号
IIC发送多字节
void IIC_SendBuff(uint8_t* str,uint16_t len)
{
I2C_GenerateSTART(I2C1,ENABLE);//生成开始信号
IIC_WaitEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT);//等待IIC模式设置开始即EV5事件
I2C_Send7bitAddress(I2C1,Address,I2C_Direction_Transmitter);//发送从设备地址+读写位
IIC_WaitEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);//等待IIC模式设置完成即EV6事件
while(len--)循环发送数据
{
I2C_SendData(I2C1,*str);
str++;
IIC_WaitEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED);
}
I2C_GenerateSTOP(I2C1,ENABLE);//生成停止信号
}