目录
I2C硬件实现协议:
硬件I2C:
引脚选择:PB6 --SCL ;PB7 --SDA
I2C 初始化结构体:
I2C配置代码:
I2C作为主设备发送数据:
I2C发送(写)数据代码:
I2C软件模拟协议:
I2C软件通信:
1、空闲状态:
2、开始信号:
3、停止信号:
4、应答信号:
5、数据的有效性:
各个信号产生的时间间隔:
起始信号:
停止信号:
应答信号ACK:
等待应答:
I2C写字节:
I2C硬件实现协议:
由STM32的IIC片上外设专门负责实现IIC通讯协议,只要配置好该外设,它就会自动根据协议要求产生通讯信号,收发数据并缓存起来,CPU只要检测该外设的状态和访问数据寄存器,就能完成数据收发。这种由硬件外设处理IIC协议的方式减轻了CPU的工作,且使软件设计更加简单。 STM32的IIC外设可用作通讯的主机及从机,支持100Kbit/s和400Kbits/s的速率,支持7位、10位设备地址,支持DMA数据传输,并具有数据校验功能。
硬件I2C:
引脚选择:PB6 --SCL ;PB7 --SDA
I2C 初始化结构体:
I2C配置代码:
void I2C_init(void)
{
I2C_InitTypeDef I2C_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE);
RCC_APB1PeriphClockCmd( RCC_APB1Periph_I2C1, ENABLE );
//PB6 --SCL ;PB7 --SDA
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; //复用开漏
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
I2C_DeInit(I2C1);
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; //应答使能
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; //地址长
度,选择7位(可为7或10)
I2C_InitStructure.I2C_ClockSpeed = 400000 ;
//时钟占空比,可选low/high=2:0或16:9,这里我们选择2:0
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2 ;
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_OwnAddress1 = 0X30 ; //自身IIC设备地址
I2C_Init(I2C1,&I2C_InitStructure );
I2C_Cmd(I2C1,ENABLE);
}
注意:I2C_OwnAddress1是STM32设备本身的地址,一般STM32作为主设备,可以不用关心这个地址设置,随意设置个数就行,但是如果STM32作为从设备使用时,必须进行配置。
I2C_Send7bitAddress(I2Cx, address, direction)这个address指的是外设器件从设备地址,比如挂载EEPROM时,通常是0xA0.这个地址不能和 I2C_OwnAddress1混淆。
I2C作为主设备发送数据:
I2C发送(写)数据代码:
代码逻辑就是根据I2C主设备发送数据的时序来编写的。
void I2C_WriteByte(uint8_t addr,uint8_t data)
{
//FlagStatus bitstatus = RESET
while (I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY)); //检查I2C总线是否繁忙
I2C_GenerateSTART(I2C1, ENABLE); //打开I2C1
//ErrorStatus status = ERROR, ERROR是个枚举类型,值为0
while( !I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); //EV5,主模式
I2C_Send7bitAddress(I2C1,OLED_ADDRESS, I2C_Direction_Transmitter); //配置STM32的IIC设备自己的地址,每个连接到IIC总线上的设备都有一个自己的地址,作为主机也不例外。
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); //EV6
I2C_SendData(I2C1, addr); //寄存器地址
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING)); //EV8,等待发送数据
完成
I2C_SendData(I2C1, data); //发送数据
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING)); //判断是否发送完成,
EV8,等待发送数据完成
I2C_GenerateSTOP( I2C1, ENABLE); //关闭I2C总线
}
I2C软件模拟协议:使用CPU直接控制通讯引脚的电平,产生出符合通讯协议标准的逻辑。
I2C软件通信:
1、空闲状态:
IIC总线的SDA和SCL两条信号线同时处于高电平时,规定位总线的空闲状态。此时各个器件的输出级场效应管均处在截止状态,即释放总线,由两条信号线各自的上拉电阻把电平拉高。
I2C时序图:
2、开始信号:当SCL为高电平期间,SDA有高到低的跳变;启动信号是一种电平跳变时序信号,而不是一个电平信号。
3、停止信号:当SCL为高电平期间,SDA由低到高的跳变;停止信号也是一种高电平跳变时序信号,而不是一个电平信号( 起始信号和停止信号一般由主机产生)
4、应答信号: 发送器每发送一个字节,就在时钟脉冲9期间释放数据线,由接收器反馈一个应答信号。应答信号为低电平时,规定为有效应答位(ACK简称应答位),应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。
5、数据的有效性: IIC总线进行数据传输时,时钟信号为高电平期间,数据线上的数据必须保持稳定,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。SDA数据线在SCL的每个时钟周期传输一位数据。(数据在SCL的上升沿到来之前就需准备好。并在下降沿到来之前必须稳定 )
各个信号产生的时间间隔:
文章来源:https://www.toymoban.com/news/detail-792904.html
起始信号:
void I2C_Start(void)
{
I2C_SDA_H;//把数据线拉高
I2C_SCL_H;//把时钟线拉高
delay_us(5);//延时5微秒,要求大于4.7微秒
I2C_SDA_L; //拉低,产生下降沿
delay_us(5);//这个过程大于4.7微秒
}
停止信号:
void I2C_Stop(void)
{
I2C_SCL_L;
I2C_SDA_L;
I2C_SCL_H;
delay_us(5);
I2C_SDA_H;
delay_us(5);
}
应答信号ACK:低电平0表示应答,1表示非应答
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* 函数名:SendAck
* 参数:
* 返回:
* 描述:应答
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
#define IIC_DELAY_TIME 10
static void SendAck(u8 _type){
IIC_SCL_LOW();
DelayUs(IIC_DELAY_TIME);
if(_type == 0)
IIC_SDA_LOW();
else
IIC_SDA_HIGH();
DelayUs(IIC_DELAY_TIME);
IIC_SCL_HIGH();
DelayUs(IIC_DELAY_TIME);
IIC_SCL_LOW();
DelayUs(IIC_DELAY_TIME);
}
等待应答:
static unsigned char IIC_Wait_Ack(void)
{
unsigned char ack;
OLED_SCLK_CLr(); //时钟线置低
delay_us(1);
OLED_SDIN_Set(); //信号线置高
delay_us(1);
OLED_SCLK_Set(); //时钟线置高
delay_us(1);
if(OLED_READ_SDIN()) //读取SDA的电平
ack = IIC_NO_ACK; //如果为1,则从机没有应答
else
ack = IIC_ACK; //如果为0,则从机应答
OLED_SCLK_CLr();//时钟线置低
delay_us(1);
return ack; //返回读取到的应答信息
}
I2C写字节:
static void Write_IIC_Byte(unsigned char IIC_Byte)
{
unsigned char i; //定义变量
for(i=0;i<8;i++) //for循环8次
{
OLED_SCLK_CLr(); //时钟线置低,为传输数据做准备
delay_us(1);
if(IIC_Byte & 0x80) //读取最高位
OLED_SDIN_Set();//最高位为1
else
OLED_SDIN_CLr(); //最高位为0
IIC_Byte <<= 1; //数据左移1位
delay_us(1);
OLED_SCLK_Set(); //时钟线置高,产生上升沿,把数据发送出去
delay_us(1);
}
OLED_SCLK_CLr(); //时钟线置低
delay_us(1);
while(IIC_Wait_Ack()); //从机应答
}
有需要可以加QQ:2404513972文章来源地址https://www.toymoban.com/news/detail-792904.html
到了这里,关于stm32之IIC通讯(详细图解附代码)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!