?? ??? 大家好,我叫你。DW,每天分享一些我学到的新知识,期待和大家一起进步 ?? ??? 系列专栏:STM32 开发板:STM32F103
??如有写得不好的地方欢迎大家指正?? 2022年7月3日创作时间
I2C(Inter-Integrated Circuit BUS) 总线由集成电路总线组成NXP公司设计主要用于主控制器和从器件之间的主从通信。IIC和SPI严格来说,界面是人们定义的软硬结合体,分为物理层和协议层。
下面,我将逐一介绍如何使用这三个重要的知识点,因为它涉及到SDA选择输出和输入模式,首先配置其输出和输入模式。
//模式配置 out input void I2C_Mode(u8 addr){ GPIO_InitTypeDef GPIO_InitStructure; if(addr){ //out GPIO_InitStructure.GPIO_Pin = SDA;//PB0 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;///输出速率 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出 } else{ //Input GPIO_InitStructure.GPIO_Pin = SCL;//PB1 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//推挽输出 } GPIO_Init(I2C_PROT,&GPIO_InitStructure);///初始化引脚 }
1: 输出模式
0 :输入模式
1.当SCL高电平时,SDA线上由被定义为。
2.当SCL高电平时,SDA线上由被定义为。
时序图可以知道,SCL和SDA默认情况下是高电平,需要延迟4.7us以上,我给它5us延迟,然后把SDA拉低,再延迟5us,同时把SCL拉低,然后编写起始条件时序代码。
//起始 void I2C_Start(void){ I2C_Mode(Out); SCL_High; SDA_High; delay_us(5); SDA_Low; delay_us(5); SCL_Low; }
时序图可以知道,SCL默认状态为高电平,SDA默认状态为低电平,需要延迟4.7us以上,我给它5us的延迟,把SDA拉高,再延迟5us,然后编写结束条件时序代码。
//结束 void I2C_Stop(void){ I2C_Mode(Out); SDA_Low; delay_us(5); SCL_High; delay_us(5); SDA_High; }
每当主机发送机发送一个字节数据时,主机总是需要等待从机发出响应信号,以确认从机是否成功接收数据。从机响应主机所需的时钟仍由主机提供。响应出现在每个主机完成8个数据位传输后的时钟周期中,
从时序图可以看出,无论是响应状态还是非响应状态,SCL都是高电平,先把它们放在高电平上SCL拉高,然后延迟4us,再判断SDA的状态;
定义一个Time如果变量没有得到回应,它将被读取SDA数据位为1,发送停止信号,表示设备不存在,防止程序停止卡在此位置,然后返回非响应信号1;
如果读取到SDA数据位为0,表示响应,然后再次SCL拉低,延时4us,最后返回0,完成响应操作。
//非应答判断 u8 I2C_Write_Ack(void){ u8 Time; I2C_Mode(Input); SCL_High; delay_us(4); while(GPIO_ReadInputDataBit(I2C_PROT,SDA)){ if( Time>250){ I2C_Stop(); return 1;//1 非应答 } } SDA_Low;//0 应答 delay_us(4); return 0; }
在时,当SCL在低电平时,允许数据发生变化,此时可以编写数据。那么,如何操作呢?首先,我们需要改变它SCL拉下,然后保持4us;然后选择输出模式,然后从高位开始bit一个bit写数据。
//写字节 void I2C_Write_Byte(u8 data){ SCL_Low; delay_us(4); for(u8 i=0;i<8;i ){ I2C_Mode(Out); if((data<<i)&0x80) SDA_High; else SDA_Low; SCL_High; delay_us(4); SCL_Low; delay_us(4); } }
在选择输入模式,我们需要将SCL总线拉高,因为此时数据稳定有效,然后读取SDA如果数据SDA为高电平,data或上0x01.读完数据后,将SCL降低,最后返回dat。
//读数据
u8 I2C_Read_Data(void){
u8 data;
for(u8 i=0;i<8;i++){
I2C_Mode(Input);
SCL_High;
delay_us(4);
data<<=1;
if(GPIO_ReadInputDataBit(I2C_PROT,SDA) == SET){
data |= 0x01;
}
SCL_Low;
delay_us(4);
}
return data;
}
自此,三个部分的代码全部编写完毕,我们了解了这三张时序的原理和使用方法之后,接下来将告诉大家如何在这个基础上驱动具有I2C接口的OLED。
OLED简介
OLED通讯地址和寄存器地址
所有的I2C器件都会有硬件地址,即芯片的地址,由手册可以知道,。,故我们定义的OLED器件地址为
#define OLED 0X78
总线时序图
由总线时序图可以知道, 要想进行发数据或者命令的流程如下:
依据上述步骤,我们编写的代码如下:
void OLED_Write_Cmd_Data(u8 cmd,u8 data){
I2C_Start();
I2C_Write_Byte(OLED);
I2C_Write_Ack();
if(!cmd){
I2C_Write_Byte(0X00);
I2C_Write_Ack();
I2C_Write_Byte(data);
}
else{
I2C_Write_Byte(0X40);
I2C_Write_Ack();
I2C_Write_Byte(data);
}
I2C_Write_Ack();
I2C_Stop();
}
至此,最重要的部分的代码已经编写完毕,其他关于OLED的说明在第九篇文章中已有详细清楚:
9.[STM32]0.96寸OLED难理解?不妨来看看这个。好了一起来看看效果吧!
🌜🌜🌜🌜🌜🌜
参考资料:
1.STM32固件库手册
3.参考视频 参考文章 9.[STM32]0.96寸OLED难理解?不妨来看看这个
资料已上传,需要自取