锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

21.[STM32]I2C协议弄不懂,深挖时序图带你编写底层驱动

时间:2023-09-08 06:07:00 集成电路2sa1013

??
???
大家好,我叫你。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<

读数据选择输入模式,我们需要将SCL总线拉高,因为此时数据稳定有效,然后读取SDA如果数据SDA为高电平,data或上0x01.读完数据后,将SCL降低,最后返回dat。

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简介

 

1.工作电压: 3.3V/5V
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难理解?不妨来看看这个

资料已上传,需要自取

锐单商城拥有海量元器件数据手册IC替代型号,打造电子元器件IC百科大全!

相关文章