查看: 1078|回复: 0

[经验] 分享C2000上使用GPIO模拟I2C通信

[复制链接]

该用户从未签到

发表于 2020-12-22 23:49:02 | 显示全部楼层 |阅读模式
分享到:

I2C作为一种简单的数字通讯方式,仅需要两根数据线就可以完成近距离主机(Master)与从机(Slave)之间的通讯,节省了MCU引脚以及额外的逻辑芯片,简化了PCB布板难度,因此得到了广泛的应用。近年来,TI也推出了越来越多支持I2C通讯功能的芯片,大大简化了芯片与MCU之间的通讯,方便了系统的设计。

     但在实际应用中,针对性能要求较低的应用场合,通常选择外设较为简单的低端主控MCU,可能并不具备I2C接口。对于此类应用,可以通过MCU的IO口进行I2C模拟,与被控器件建立通讯,达到发送控制指令、读取内部寄存器的目的。即使在I2C接口缺失的情况下也能够充分发挥器件的全部功能。

     本文基于C2000提供了一种利用GPIO模拟I2C控制被控芯片的解决方案,并附有完整例程。对于绝大多数采用标准I2C通信协议以及部分采用SMBus的芯片均具有参考意义。基于其它MCU的方案也可参考该例程进行移植。
在C2000中,可以通过以下代码实现起始信号的发送。其中SCL及SDA分别代表用C2000 GPIO模拟的SDA及SCL总线,具体定义请参考例程部分。

  1. <p style="line-height: 28px; color: rgb(51, 51, 51); font-family: " microsoft="" yahei";"=""><span style="font-size: 16px;">void I2C_Start(void)  
  2. {  
  3.     Delay(I2CDelay);  
  4.     SCL_High();   // Set the SCL  
  5.     SDA_High();   // Set the SDA  
  6.     Delay(I2CDelay);  
  7.     SDA_Low();    // Clear the SDA while SCL is high indicates the start signal  
  8.     Delay(I2CDelay);  
  9.     SCL_Low();    // Clear the SCL to get ready to transmit
  10. }  
  11.      可以参考以下代码实现结束信号的发送:</span></p><p style="line-height: 28px; color: rgb(51, 51, 51); font-family: " microsoft="" yahei";"=""><span style="font-size: 16px;">void I2C_Finish(void)  
  12. {  
  13.     SDA_Low();    // Clear the SDA  
  14.     SCL_Low();    // Clear the SCL  
  15.     Delay(I2CDelay);  
  16.     SCL_High();   // Set the SCL  
  17.     Delay(I2CDelay);  
  18.     SDA_High();   // Set the SDA while SCL is high indicates the finish signal  
  19. }  
  20. 1.2 数据位及地址位</span></p><p style="line-height: 28px; color: rgb(51, 51, 51); font-family: " microsoft="" yahei";"=""><span style="font-size: 16px;">       I2C通讯的数据位通常由1-8的数据构成,在主机进行数据的发送以及读取期间,SCL总线时钟信号时钟仍由主机发出,每个SCL高电平期间对应一位数据。在SCL高电平期间,都应该保持SDA上的数据正确,因此在实际的应用中,通常使得SDA的高电平脉宽宽于SCL。</span></p><p style="line-height: 28px; color: rgb(51, 51, 51); font-family: " microsoft="" yahei";"=""><span style="font-size: 16px;">       地址位的发送与数据位类似,实际的操作中可以将设备的7位地址位+1位读写位作为一个8位字节进行整体的发送。以BQ25703A为例,默认设备地址为0x6B(7bit)。则在进行读操作时,所要发送的字节为0xD7(1101011b+1b);进行写操作时,所要发送的整体字节为0XD6 (1101011b+0b)。</span></p><p style="line-height: 28px; color: rgb(51, 51, 51); font-family: " microsoft="" yahei";"=""><span style="font-size: 16px;">       数据位及地址位的发送均可参考以下发送一个8位byte的实现方法:</span></p><p style="line-height: 28px; color: rgb(51, 51, 51); font-family: " microsoft="" yahei";"=""><span style="font-size: 16px;">void I2C_Send_Byte(unsigned char txd)  
  21. {  
  22.     int t;  
  23.     SDA_Output();   // Config SDA GPIO as output  
  24.     SCL_Low();      // Clear the SCL to get ready to transmit  
  25.     txd&=0X00FF;    // Get the lower 8 bits  
  26.     for(t=0;t<8;t++)  
  27.         {  
  28.             SDA_Data_Register = (txd&0x80)>>7;  // Send the LSB  
  29.             txd<<=1;  
  30.             Delay(I2CDelay/2);  
  31.            SCL_High();   // Set the SCL  
  32.            Delay(I2CDelay);  
  33.            SCL_Low();    // Clear the SCL  
  34.            Delay(I2CDelay/2);  
  35.         }
  36. }  </span></p>
复制代码

1.3 ACK/NACK指令

     Acknowledge(ACK)以及Not Acknowledge(NACK)指令通常发生在一个byte发送结束之后,用于标志一个byte发送的成功或失败。特别需要注意的是,即使是在ACK时钟周期期间,SCL总线时钟信号也是由主机产生的。

     ACK: 当一次发送结束,主机释放SDA总线。若发送成功,从机在第9个时钟周期内拉低SDA总线,并在整个高电平期间保持。

     NACK: 当一次发送结束,主机释放SDA总线。若发送失败,在第9个时钟周期内SDA始终处于高电平。

     在通讯中作为主机的MCU通常只需要实现NACK的发送以及ACK信号的等待,具体可参考以下程序:

  1. <p style="line-height: 28px; color: rgb(51, 51, 51); font-family: " microsoft="" yahei";"=""><span style="font-size: 16px;">void I2C_NAck(void)  
  2. {  
  3.     SCL_Low();     // Clear the SCL to get ready to transmit  
  4.     SDA_Low() ;    // Clear the SDA  
  5.     Delay(I2CDelay);  
  6.     SCL_High();    // Set the SCL  
  7.     Delay(I2CDelay);  
  8.     SCL_Low();      // Clear the SCL  
  9.     Delay(I2CDelay);
  10. }  </span>
  11. </p><p style="line-height: 28px; color: rgb(51, 51, 51); font-family: " microsoft="" yahei";"=""><span style="font-size: 16px;">Uint16 I2C_Wait_Ack(void)  
  12. {  
  13.     int ErrTime=0;  
  14.     int ReadAck=0;  
  15.     SDA_Input();  // Config SDA GPIO as Input
  16.     Delay(I2CDelay);  
  17.     SCL_High();   // Set the SCL and wait for ACK  
  18.     while(1)  
  19.     {  
  20.          ReadAck = SDA_Data_Register ;  // Read the input  
  21.          if(ReadAck)  
  22.         {   
  23.              ErrTime++;  
  24.              if(ErrTime>ErrLimit)  
  25.             {  
  26.                  //Error handler:Set error flag, retry or stop.  
  27.                 //Define by users  
  28.                  return 1;  
  29.              }  
  30.         }  
  31.          if(ReadAck==0)  // Receive a ACK
  32.          {  
  33.              Delay(I2CDelay);  
  34.             SCL_Low();   // Clear the SCL for Next Transmit  
  35.              return 0;  
  36.          }  
  37.      }
  38. } </span></p>
复制代码

   基于以上几个基本的I2C通讯操作,就可以发送一个完整I2C数据帧,实现基本的I2C通讯功能,构建了利用GPIO口模拟I2C进行芯片控制的基础。


回复

使用道具 举报

您需要登录后才可以回帖 注册/登录

本版积分规则

关闭

站长推荐上一条 /4 下一条



手机版|小黑屋|与非网

GMT+8, 2024-11-23 08:36 , Processed in 0.107044 second(s), 15 queries , MemCache On.

ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

苏公网安备 32059002001037号

Powered by Discuz! X3.4

Copyright © 2001-2024, Tencent Cloud.