I2C介绍
I2C 是很常见的一种总线协议,I2C 使用两条线在主控制器和从机之间进行数据通信。一条是 SCL(串行时钟线),另外一条是 SDA(串行数据线)。
主器件用于启动总线传送数据,并产生时钟以开放传送的器件,此时任何被寻址的器件均被认为是从器件.在总线上主和从、发和收的关系不是恒定的,而取决于此时数据传送方向。如果主机要发送数据给从器件,则主机首先寻址从器件,然后主动发送数据至从器件,最后由主机终止数据传送;如果主机要接收从器件的数据,首先由主器件寻址从器件.然后主机接收从器件发送的数据,最后由主机终止接收过程。在这种情况下.主机负责产生定时时钟和终止数据传送。
(1)物理层:
(2)协议层:
(3) I2C种类:
I2C分为软件I2C和硬件I2C:
模拟I2C一般是用GPIO管脚,用软件控制管脚状态以模拟I2C通信波形。
硬件I2C对应芯片上的I2C外设,有相应I2C驱动电路,其所使用的I2C管脚也是专用。
1.硬件I2C的效率要远高于软件的,而软件I2C由于不受管脚限制,接口比较灵活。
2.模拟I2C 是通过GPIO,软件模拟寄存器的工作方式,而硬件(固件)I2C是直接调用内部寄存器进行配置。如果要从具体硬件上来看,可以去看下芯片手册。因为固件I2C的端口是固定的,所以会有所区别。
本示例采用软件I2C。
I2C通信——eeprom读写
(1)电路图:
(2) Cubemx配置:
(3)部分代码原理:
写:I2CSendByte(0xa0);
读:I2CSendByte(0xa1);
(4)代码:
使用蓝桥杯提供的I2C库(直接添加该文件)
I2C.c(部分):
//读函数
uchar eeprom_read(uchar addr)
{
uchar dat;
I2CStart();
I2CSendByte(0xa0); //程序联系芯片
I2CWaitAck();
I2CSendByte(addr); //发送读取地址
I2CWaitAck();
I2CStop();
//读回真实数据
I2CStart();
I2CSendByte(0xa1); //正式开始读
I2CWaitAck();
dat=I2CReceiveByte(); //开始接收
I2CWaitAck();
I2CStop();
return dat;
}
//写函数
void eeprom_write(uchar addr,uchar dat)
{
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(addr);
I2CWaitAck();
I2CSendByte(dat);
I2CWaitAck();
I2CStop();
}
main.c(部分):
//按一下按键,就可以把当前数据存到eeprom中
if(key[3].single_flag==1) //eeprom芯片一个位只能存一个8位的数
{ //所以要把uint型拆成高8位和低8位
uchar frq_h=frq1>>8; //右移
uchar frq_l=frq1&0xff;
eeprom_write(1,frq_h); //存到eeprom的两个区域
HAL_Delay(10);
eeprom_write(2,frq_l);
key[3].single_flag=0;
}
//显示部分
sprintf(text,"FRQ1=%d",frq1);
OLED_ShowString(0,0,(uint8_t*)text);
uint eep_temp=(eeprom_read(1)<<8)+(eeprom_read(2));
sprintf(text,"FRQ_eep=%d",eep_temp);
OLED_ShowString(0,4,(uint8_t*)text);
最终效果
按一下按键,就可以把当前数据存到eeprom中