单片机
返回首页

stm32软件模拟I2C

2017-09-12 来源:eefocus

一  概述

  很多人都知道stm32的硬件I2C存在BUG,现在我们通过软件模拟时序的办法来实现I2C。


  使用软件模拟I2C主要是方便程序的移植,只需要更改一下相应的IO端口即可。


二 软件模拟实现

1 起始信号


  1. void i2c_Start(void)  

  2. {  

  3.     macI2C_SDA_1();  //首先确保SDA和SCL都是高电平  

  4.     macI2C_SCL_1();  

  5.     i2c_Delay();  

  6.     macI2C_SDA_0();  //先拉低SDA  

  7.     i2c_Delay();  

  8.     macI2C_SCL_0();  //在拉低SCL  

  9.     i2c_Delay();  

  10. }  


2 总线产生停止信号


  1. void i2c_Stop(void)  

  2. {  

  3.       

  4.     macI2C_SDA_0();  //首先确保SDA是低电平  

  5.     macI2C_SCL_1();  //先拉高SCL  

  6.     i2c_Delay();  

  7.     macI2C_SDA_1();  //在拉高SDA  

  8. }  

3 CPU向I2C总线设备发送8bits的数据


  1. void i2c_SendByte(uint8_t _ucByte)  

  2. {  

  3.     uint8_t i;  

  4.   

  5.     for (i = 0; i < 8; i++)  

  6.     {         

  7.         if (_ucByte & 0x80)  

  8.         {  

  9.             macI2C_SDA_1();  

  10.         }  

  11.         else  

  12.         {  

  13.             macI2C_SDA_0();    

  14.         }  

  15.         i2c_Delay();  

  16.         macI2C_SCL_1();  

  17.         i2c_Delay();      

  18.         macI2C_SCL_0();  

  19.         if (i == 7)  

  20.         {  

  21.              macI2C_SDA_1(); // 8位数据发送完毕后,主机释放SDA,以检测从机应答  

  22.         }  

  23.         _ucByte <<= 1;  //左移1个bit  

  24.         i2c_Delay();  

  25.     }  

  26. }  

4 CPU从I2C总线读取8个bits的数据


  1. uint8_t i2c_ReadByte(void)  

  2. {  

  3.     uint8_t i;  

  4.     uint8_t value;  

  5.   

  6.     /*读取到的第一个bit为bit7*/  

  7.     value = 0;  

  8.     for (i = 0; i < 8; i++)  

  9.     {  

  10.         value <<= 1;  

  11.         macI2C_SCL_1();  

  12.         i2c_Delay();  

  13.         if (macI2C_SDA_READ())  

  14.         {  

  15.             value++;  

  16.         }  

  17.         macI2C_SCL_0();  

  18.         i2c_Delay();  

  19.     }  

  20.     return value;  

  21. }  

5 CPU产生一个时钟,并且读取器件的ACK应答信号


  1. uint8_t i2c_WaitAck(void)  

  2. {  

  3.     uint8_t re;  

  4.   

  5.     macI2C_SDA_1();  //CPU释放SDA总线  

  6.     i2c_Delay();  

  7.     macI2C_SCL_1();  //CPU驱动SCL=1,此时器件会返回ACK应答  

  8.     i2c_Delay();  

  9.     if (macI2C_SDA_READ())  //CPU读取SDA口线状态  

  10.     {  

  11.         re = 1;  

  12.     }  

  13.     else  

  14.     {  

  15.         re = 0;  

  16.     }  

  17.     macI2C_SCL_0();  

  18.     i2c_Delay();  

  19.     return re;  

  20. }  

6 CPU产生一个ACK信号



  1. void i2c_Ack(void)  

  2. {  

  3.     macI2C_SDA_0();   

  4.     i2c_Delay();  

  5.     macI2C_SCL_1();   

  6.     i2c_Delay();  

  7.     macI2C_SCL_0();  

  8.     i2c_Delay();  

  9.     macI2C_SDA_1();   

  10. }  

7 CPU产生一个NACK信号(NACK即无应答信号)


  1. void i2c_NAck(void)  

  2. {  

  3.     macI2C_SDA_1();  //CPU驱动SDA产生1  

  4.     i2c_Delay();  

  5.     macI2C_SCL_1();  //CPU驱动SCL产生1  

  6.     i2c_Delay();  

  7.     macI2C_SCL_0();  

  8.     i2c_Delay();      

  9. }  

8 I2C总线位延时



  1. static void i2c_Delay(void)  

  2. {  

  3.     uint8_t i;  

  4.     for (i = 0; i < 10; i++);  

  5. }  

对于I2C总线延时来说,不同的单片机写法是不相同的,参考野火的程序,当CPU主频为72MHz时,在内部Flash运行,同时MDK不做优化的情况下



循环次数为10时,SCL频率为205KHz

循环次数为7时,SCL频率为347KHz,SCL高电平时间为1.5us,SCL低电平时间为2.87us

后记:关于I2C通信,我还是有几处地方没有搞明白,这里的程序只是写好了具体的底层封装,对于不同的外设,如AT24C02,MPU6050,应用起来肯定是不相同的,等搞明白其他的一些问题后,我会继续补充这篇文章。



参考资料

1 http://blog.csdn.net/subkiller/article/details/6854910  《I2C总线协议》

2 《手把手教你学51单片机》

3 野火stm32指南者开发板程序



进入单片机查看更多内容>>
相关视频
  • RISC-V嵌入式系统开发

  • SOC系统级芯片设计实验

  • 云龙51单片机实训视频教程(王云,字幕版)

  • 2022 Digi-Key KOL 系列: 你见过1GHz主频的单片机吗?Teensy 4.1开发板介绍

  • TI 新一代 C2000™ 微控制器:全方位助力伺服及马达驱动应用

  • MSP430电容触摸技术 - 防水Demo演示

精选电路图
  • CCD图像传感器在微光电视系统中的应用

  • 非常简单的150W功放电路图

  • 一个简单的警笛电路图

  • 优化电路板布局的简单方法

  • 使用NE555和磁簧开关的橱柜照明电路

  • 一种构建12V和230V双直流电源的简单方法

    相关电子头条文章