当前位置:网站首页>21.[STM32]I2C协议弄不懂,深挖时序图带你编写底层驱动
21.[STM32]I2C协议弄不懂,深挖时序图带你编写底层驱动
2022-07-05 15:18:00 【依点_DW】
作者简介:大家好啊,我叫DW,每天分享一些我新学到的知识,期待和大家一起进步
系列专栏:STM32
开发板:STM32F103如有写得不好的地方欢迎大家指正
创作时间:2022年7月3日
I2C(Inter-Integrated Circuit BUS) 为集成电路总线,该总线由NXP公司设计,多用于主控制器和从器件间的主从通信。IIC和SPI接口严格的说他们都是人们所定义的软硬结合体,分为物理层和协议层。
SDA(Serial data)是数据线,它是用来传输数据的。
SCL(Serial clock line)是时钟线,它是控制数据发送的时序的 。
I2C最重要的三个点为:
1.起始与结束条件
2.应答和非应答
3.数据的有效性
下面,我将一一介绍如何使用这三个重要的知识点,由于涉及到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拉低,那么就完成了起始条件时序代码的编写。
这里要注意,SDA选择输出模式
//起始
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,那么就完成了结束条件时序代码的编写。
这里要注意,SDA选择输出模式
向SDA总线写:输出模式
向SDA总线读:输入模式
//结束
void I2C_Stop(void){
I2C_Mode(Out);
SDA_Low;
delay_us(5);
SCL_High;
delay_us(5);
SDA_High;
}
应答与非应答
每当主机向从机发送完一个字节的数据,主机总是需要等待从机给出一个应答信号,以确认从机是否成功接收到了数据,从机应答主机所需要的时钟仍是主机提供的,应答出现在每一次主机完成8个数据位传输后紧跟着的时钟周期,低电平0表示应答,1表示非应答。
由时序图可以知道,不管是应答状态下,还是非应答状态下,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写数据。
注意:I2C从高位开始写数据。
//写字节
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拉低,最后返回data。
data<<=1;//从低位开始读数据,不断左移,低位将变成高位。
//读数据
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简介
2.通信接口: 3-wire SPI, 4-wire SPI, I2C
3.屏幕类型: OLED
4.控制芯片: SSD1306
5.分辨率: 128*64(Pixel)
6.外形尺寸: 128*64(Pixel)
7.显示颜色: 黄蓝(双色块屏)
8.工作温度: -20°C ~ 70°C
9.存储温度: -30°C ~ 80°C
10.视角: >160
注意事项:OLED 显示屏不同于 LCD,OLED 上电是没有反应的,需要程序驱动才会有显示!
接线方式:
SDA --- PC0
SCL --- PC1
VCC --- 5V
GND --- 地
OLED通讯地址和寄存器地址
所有的I2C器件都会有硬件地址,即芯片的地址,由手册可以知道,b7~b2为固定不变的,b1(SA0)一般选择0,bo(R/W)用于确定I2C总接口的操作模式,R/w # = 1,它处于读模式。R/w # = 0,它处于写模式。一般只向OLED写数据,因此其地址为:0111 1000(0x78) ,故我们定义的OLED器件地址为
#define OLED 0X78
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();
}
0:写命令
1:写数据
至此,最重要的部分的代码已经编写完毕,其他关于OLED的说明在第九篇文章中已有详细清楚:
9.[STM32]0.96寸OLED难理解?不妨来看看这个。好了一起来看看效果吧!
为了方便下次查找,记得点点关注哦。
本章结束,我们下一章见
参考资料:
1.STM32固件库手册
2.正点原子STM32不完全手册_库函数版本
3.参考视频 参考文章 9.[STM32]0.96寸OLED难理解?不妨来看看这个
资料已上传,需要自取
边栏推荐
- Good article inventory
- Garbage collection mechanism of PHP (theoretical questions of PHP interview)
- I spring web upload
- 超越PaLM!北大碩士提出DiVeRSe,全面刷新NLP推理排行榜
- Data communication foundation - routing communication between VLANs
- How to introduce devsecops into enterprises?
- Your childhood happiness was contracted by it
- Bugku alert
- Bugku's Ping
- Database learning - Database Security
猜你喜欢
sql server学习笔记
Data communication foundation ACL access control list
Aike AI frontier promotion (7.5)
RepLKNet:不是大卷积不好,而是卷积不够大,31x31卷积了解一下 | CVPR 2022
百亿按摩仪蓝海,难出巨头
市值蒸发超百亿美元,“全球IoT云平台第一股”赴港求生
First PR notes
Bugku's eyes are not real
Lesson 4 knowledge summary
Detailed explanation of C language branch statements
随机推荐
go学习 ------jwt的相关知识
力扣今日题-729. 我的日程安排表 I
Bugku's Eval
SQL injection sqllabs (basic challenges) 1-10
Object. defineProperty() - VS - new Proxy()
queryRunner. Query method
lv_ font_ Conv offline conversion
Nine hours, nine people, nine doors problem solving Report
What are the domestic formal futures company platforms in 2022? How about founder metaphase? Is it safe and reliable?
Bugku easy_ nbt
Leetcode: Shortest Word Distance II
爱可可AI前沿推介(7.5)
Xiao Sha's arithmetic problem solving Report
【 note 】 résoudre l'erreur de code IDE golang
Data communication foundation - routing communication between VLANs
Virtual base class (a little difficult)
Usage and usage instructions of JDBC connection pool
Optional parameters in the for loop
超越PaLM!北大碩士提出DiVeRSe,全面刷新NLP推理排行榜
Database learning - Database Security