IIC通信协议代码分享及调试过程中的一些小误区分享

1.前奏

很久没有更新博客了,hiahia,之前忙着考研,现在却忙着找工作,哎咦呦~,但也没事,研没考上也可以好好学学我感兴趣的东西,用这些来找工作也挺好,做自己喜欢的事情,研究生还是想考,等快到暑假再看吧。这段时间重新把以前学的东西又巩固了一遍,和我想的一样,以前的基础果然不牢。这次感觉花的时间挺久的就是IIC协议了,经过这次自己敲代码写,对协议的理解更加深了。所以想分享给大家,主要是代码,虽然网上有很多,但是就是想把自己的代码分享出来,当然,其中也有一些走过的小误区,可以给大家做一个参考,也可以让自己以后回写协议的时候有一个回忆参考。

2.IIC协议简单说明

开始信号:SCL为高电平时,SDA为下降沿;
停止信号:SCL为高电平时,SDA为上升沿;
应答信号:发送完一个字节后,当SCL为高电平时,读出的SDA为低电平;
发送数据:把SDA数据一位一位准备好,SCL为上升沿时一位一位地写入数据,方向为高位低位
接收数据:SCL为下降沿时一位一位地读出数据,读取数据的方向为高位低位

3.代码分享与说明及小误区分享

我这里的代码因为是我自己写的,有的地方想尽量写简单,所以才会犯了我调试过程中的一些错误,这里面大家当做参考就好,如有和大家一样的错误,那就真是英雄所见略同啦,这里用的主控芯片是STM32F103ZET6。
开始信号:

//下降沿为开始信号void IIC_Start(void){ SDA_OUT(); SDA=1; SCL=1; delay_us(3); SDA=0; delay_us(3); SCL=0;}

小说明:这里的第二第三句SDA=1;SCL=1;最好不要变。
误区解读:若是SCL=1;SDA=1;我们不能确定在SCL=1之前SDA是高电平还是低电平,假如是低电平,那么这两条语句之后,SDA就会产生一个上升沿。

停止信号:

//上升沿为停止信号void IIC_End(void){ SDA_OUT(); SDA=0; SCL=1; delay_us(3); SDA=1; delay_us(3); SCL=0; delay_us(1);}

小说明:同理,这里的第二第三句SDA=0;SCL=1;不能变。
误区解读:若是SCL=1;SDA=0;我们不能确定在SCL=1之前SDA是高电平还是低电平,假如是高电平,那么这两条语句之后,SDA就会产生一个下降沿。这里我就是因为把这两句调换了,所以才一直接受不到数据,调试了很久,不知道是哪的问题,后来还是走在路上买东西一直想才终于搞明白了,然后才有了想法写一篇博客,hiahia~,开心开心。

应答信号:

//返回值为0表示应答成功,1表示非应答uint8_t IIC_Ack(void){ uint8_t count; SDA_IN(); SCL=0; delay_us(3); SCL=1; delay_us(2); while(Read_SDA==1) { count++; if(count>250) { IIC_End(); return 1; } } SCL=0; //释放时钟线 return 0;}

小说明:这里定义了一个count,为的就是防止SDA接收不到低电平程序卡炸在这里。第三句SCL=0; delay_us(3);是先释放总线,等待SDA的低电平信号,但是亲测过,不加这两句也可以。

发送数据:

//上升沿写入数据,从高位到低位写数据void IIC_Send_One_Byte(uint8_t data){ uint8_t i; SCL=0; SDA_OUT(); for(i=0;i<8;i++)     {    if((data&0x80)>>7)SDA=1;elseSDA=0;data<<=1;delay_us(3);SCL=1;delay_us(3);SCL=0;delay_us(2);   }}

小说明:先把SDA上的数据准备好,然后利用SCL上升沿发送,注意是先高位再低位发送就可以,逐位数据代码发送的算法也可以自己再想想。

接收数据:

//下降沿读出数据,从高位到低位读数据uint8_t IIC_Read_One_Byte(void){ uint8_t data=0; uint8_t i; SDA_IN(); for(i=0;i<7;i++) { SCL=1; delay_us(3); data|=Read_SDA; data<<=1; SCL=0; delay_us(3); } return data;}

误区解读:这里注意i<7,之前想当然地以为接收8位数据就是i<8了,后来在自己的脑海中模拟了一下这段程序才想明白。

向AT24C02指定地址写一个字节:

extern uint8_t num;void AT24C02_Write_One_Byte(uint8_t addr,uint8_t data){   IIC_Start(); IIC_Send_One_Byte(0xA0); if(IIC_Ack()==0) {    IIC_Send_One_Byte(addr);  if(IIC_Ack()==0){   IIC_Send_One_Byte(data); if(IIC_Ack()==0) {    IIC_End();  USART1_Send(num); }} } delay_ms(10);  //可以注释掉}

小说明:这里按照AT24C02的写字节操作来就好了

向AT24C02指定地址读一个字节:

uint8_t AT24C02_Read_One_Byte(uint8_t addr){ uint8_t data; IIC_Start(); IIC_Send_One_Byte(0xA0); if(IIC_Ack()==0) { IIC_Send_One_Byte(addr); if(IIC_Ack()==0){ IIC_Start(); IIC_Send_One_Byte(0xA1); if(IIC_Ack()==0) { data=IIC_Read_One_Byte(); IIC_End(); }} } delay_ms(10); //可以注释掉 return data;}

小说明:这里按照AT24C02的读指定地址操作来就好了

其他函数:

#define SCL PBout(6)#define SDA PBout(7)#define Read_SDA PBin(7)//转变SDA的输入输出模式#define SDA_IN()  {GPIOB->CRL&=0x0fffffff;GPIOB->CRL|=0x80000000;}#define SDA_OUT() {GPIOB->CRL&=0x0fffffff;GPIOB->CRL|=0x30000000;}void AT24C02_Init(void){ GPIO_InitTypeDef GPIO_Struct; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);   GPIO_Struct.GPIO_Mode=GPIO_Mode_Out_PP;    GPIO_Struct.GPIO_Pin=GPIO_Pin_6;           //IIC SCL GPIO_Struct.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOB,&GPIO_Struct); GPIO_Struct.GPIO_Pin=GPIO_Pin_7;           //IIC SDA  GPIO_Init(GPIOB,&GPIO_Struct); GPIO_SetBits(GPIOB,GPIO_Pin_6|GPIO_Pin_7); }int main(void){     AT24C02_Init();     delay_init();     key_init(); uart_init(115200); num=AT24C02_Read_One_Byte(0); USART1_Send(num); while(1) {       if(key0==0)  //°´¼ü°´Ï   {      delay_ms(10);          if(key0==0)  {   num+=2; AT24C02_Write_One_Byte(0,num);  }while(!key0);}  }}

4.实验现象:

小说明:按一次key0,num的值加2,然后显示在串口上位机上,一直连续重复出现的AC、AE、B2、B6我按过复位键之后显示的,由此可以检验AT24C02可以断电之后存储原来的数据,代码磨问题啦~

5.写完收工!

若是有错误,欢迎大家指正!有想法,欢迎大家一起探讨!

(0)

相关推荐

  • 【新提醒】基于HC32V103开发板的OLED显示驱动

    OLED屏是一种自身发光的显示器件,它有许多种类,如按色彩分,可分为单色屏.双色屏及彩色屏等:按尺寸分,可分为0.91'.0.96'屏等:按接口方式分,可分为I2C接口和SPI接口等. 其中,以I2C ...

  • IIC详解,包括原理、过程,最后一步步教你实现IIC

    IIC详解 1.I2C总线具有两根双向信号线,一根是数据线SDA,另一根是时钟线SCL 2.IIC总线上可以挂很多设备:多个主设备,多个从设备(外围 设备).上图中主设备是两个单片机,剩下的都是从设备 ...

  • 高通字库芯片GT20L16S1Y驱动 0.96寸 OLED 任意显示中文

    连续两个月的加班,给ODM客户生产温控器订单,今天终于顺利发货,对于工程师出身的我,终于可以对着电脑,消停几天,研究技术,分享技术了,闲话少说,直接进入正题: 半年前有个老客户介绍个中央某院的项目,我 ...

  • 基于51单片机的PCF8591电压测量

    基于51单片机的PCF8591电压测量 这个笔记记录好久了.因为想突破ADS1115在STC89下的使用,但一直没有太清晰的眉目和充裕的时间.不知道为什么各种资料里,ADS1115很少有介绍差分的,而 ...

  • PLC调试过程中的八大坑,搞电气的你都经历了么?

    发现更多电气知识 电气达人 电气达人 电气人择一业,终一生! 13篇原创内容 公众号 各种品牌PLC都具有自我诊断功能,但PLC修理的技巧在于,充分运用该功能进行分析,然后精确寻找问题所在.整理了当P ...

  • PLC调试过程中的八大坑,你都经历过吗?

    发现更多电气知识 电气达人 各种品牌PLC都具有自我诊断功能,但PLC修理的技巧在于,充分运用该功能进行分析,然后精确寻找问题所在.整理了当PLC呈现反常报警时,PLC修理人员需要了解的8种常见错误类 ...

  • 今天跟大家分享绘画过程中的一个小细节,小处的背景处理。

    今天跟大家分享绘画过程中的一个小细节,小处的背景处理。

  • PLC调试过程中的八大坑,你都经历了么?

    跟我学PLC 91篇原创内容 公众号 各种品牌PLC都具有自我诊断功能,但PLC修理的技巧在于,充分运用该功能进行分析,然后精确寻找问题所在.整理了当PLC呈现反常报警时,PLC修理人员需要了解的8种 ...

  • 变频器调试过程中的常见问题解析!

    变频器 1. 在变频器低转速时带不动电机怎么办? 变频器在VF控制中,变频器的输出电压是随控制频率的降低而不断减小的,因此转速越低变频器的输出电压就越小,输出的力矩也在逐渐减小,当力矩小于电机启动力矩 ...

  • PLC调试过程中的这些坑,你都经历过么?

    限时领取-三菱PLC全套学习资料! (点击上方红字,免费领资料) 各种品牌PLC都具有自我诊断功能,但PLC修理的技巧在于,充分运用该功能进行分析,然后精确寻找问题所在.整理了当PLC呈现反常报警时, ...

  • 如何避免工业自动化调试过程中遇到的危险?

    在工业自动化领域,特别是在调试过程中,有一些影响我们所遇危险的特别因素.通常情况下,工业的发展主要是在办公室环境下实现的,而实际的调试过程却在工厂实施. 有时,第一次见到一个地方时,一切都是陌生的.工 ...

  • 厨房是整个装修过程中最重要的!分享厨房装修的一些经验和教训

    对于经常在家做饭的人来说,厨房装修是整个装修工程的重中之重,也是最复杂的地方,好的厨房装修可以让厨房烹饪告别无趣.无序和疲劳,让下厨变成一件轻松.有意思的事情.我们家的厨房,可以说是我们家里装修最成功 ...

  • 高血压患者在治疗过程中的4个误区,尽早了解,避免耽误病情

    现如今,高血压已经发展成了一种比较常见的慢性病,而且发病年龄也有年轻化的趋势.当患上高血压以后,患者就会出现头晕.手麻.胸闷等症,症状严重时甚至会引发肾脏某些疾病的发生.所以一旦发现自己患有高血压以后 ...