打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
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.写完收工!

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

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
SHT30使用的学习过程2 SHT30驱动程序
INA3221的使用教程(IIC)
C语言使用面向对象实现IIC驱动
IIC详解,包括原理、过程,最后一步步教你实现IIC
linux e2prom 驱动代码
超详细陀螺仪MPU6050模块输出姿态角(有完整版源码)
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服