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

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;
		else
			SDA=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<8;i++)
	 {
		  SCL=1;
	      delay_us(3);
	      data<<=1;
		  data|=Read_SDA;
	      SCL=0;
		  delay_us(3);
	 }
	 return data;
}

误区解读:这里注意i<8,之前想当然的以为接收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.写完收工!

若是有错误,欢迎大家指正!有想法,欢迎大家一起探讨!
在这里插入图片描述

  • 7
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IT狼~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值