你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

求个STM32F0 模拟I2C的程序例程

[复制链接]
zhy233090130 提问时间:2019-12-5 21:16 /
各位大牛,求一个STM32F0 模拟I2C的程序例程,求分享,谢谢!
收藏 评论11 发布时间:2019-12-5 21:16

举报

11个回答
老牛洋车 回答时间:2019-12-6 09:25:15
这个应该不难吧,关键是要调整好SCL的时序。
网络孤客 回答时间:2019-12-6 11:19:17
直接拷贝stm32f103的例程,改成自己的GPIO端口(注意使用相应库函数)。就行了。
废鱼 回答时间:2019-12-6 11:29:19
HAL库的I2C硬件驱动可以直接使用,建议使用硬件驱动。

点评

最好这样,否则做法太LOW,容易引起硬件时间上的冲突,除非你钱多非要将黄金当铁用  发表于 2019-12-8 13:37
zhy233090130 回答时间:2019-12-6 20:13:42
安 发表于 2019-12-6 11:29
HAL库的I2C硬件驱动可以直接使用,建议使用硬件驱动。

硬件上没有接I2C复用引脚,只能使用模拟的
zhy233090130 回答时间:2019-12-6 20:16:12
ldptest 发表于 2019-12-6 11:19
直接拷贝stm32f103的例程,改成自己的GPIO端口(注意使用相应库函数)。就行了。 ...

能分享一下例程吗,感谢!!
老牛洋车 回答时间:2019-12-8 09:28:08
    下面是我基于G431的软件模拟I2C对AT24C32进行读写操作的代码,应该可以直接使用,最多就是调整一下延时函数,希望能帮到您。

  1. //#include "main.h"
  2. #include "i2c.h"
  3. //#include <stdio.h>

  4. /***************************************************
  5. 函数功能:毫秒延时
  6. 入口参数:延时毫秒
  7. ***************************************************/
  8. void delay_us(uint8_t us)  
  9. {
  10.     uint8_t x,y;
  11.     for(x=us;x>0;x--)   
  12.     for(y=20;y>0;y--);
  13. }

  14. /***************************************************
  15. 函数功能:软件I2C配置
  16. 入口参数:无
  17. ***************************************************/
  18. void SI2C_Config(void)            //引脚配置
  19. {
  20.     GPIO_InitTypeDef GPIO_InitStruct = {0};
  21.   
  22.     GPIO_InitStruct.Pin = SI2C_SCL | SI2C_SDA;   //SCL,SDA,RST输出模式、弱上拉
  23.     GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  24.     GPIO_InitStruct.Pull = GPIO_NOPULL;
  25.     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  26.     HAL_GPIO_Init(SI2C_PORT, &GPIO_InitStruct);
  27.        
  28. }


  29. /***************************************************
  30. 函数功能:DAT引脚配置
  31. 入口参数:x
  32. ***************************************************/
  33. void SI2C_PortConfig(uint8_t dir)              //DAT端口配置(根据需要配置成输出或输入模式)
  34. {
  35.         GPIO_InitTypeDef GPIO_InitStruct;
  36.     if(dir == 0){
  37.         GPIO_InitStruct.Pin = SI2C_SDA;        //SDA输出模式、弱上拉
  38.         GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  39.         GPIO_InitStruct.Pull = GPIO_NOPULL;
  40.         GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  41.         HAL_GPIO_Init(SI2C_PORT, &GPIO_InitStruct);
  42.         }
  43.         else{
  44.             GPIO_InitStruct.Pin = SI2C_SDA;        //SDA输入模式
  45.         GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  46.         HAL_GPIO_Init(SI2C_PORT, &GPIO_InitStruct);
  47.         }
  48.         HAL_GPIO_WritePin(SI2C_PORT,SI2C_SDA,GPIO_PIN_SET);
  49. }

  50. /******************************************************************************************************************************************
  51. * 函数名称: I2C_Start()
  52. * 功能说明:        产生I2C传输的Start信号
  53. * 输    入: 无
  54. * 输    出: 无
  55. ******************************************************************************************************************************************/
  56. void SI2C_Start(void)
  57. {
  58.     SDA_OUT;           //SDA输出
  59.     SDA_1;
  60.     SCL_1;             //scl = 1;
  61.         delay_us(7);
  62.         SDA_0;             //sda = 0;        scl为高时sda的下降沿表示“起始”
  63.         delay_us(5);
  64.         SCL_0;             //scl = 0;钳住I2C总线,准备发送或接收数据 START:when CLK is high,DATA change form high to low
  65. }

  66. /******************************************************************************************************************************************
  67. * 函数名称:        I2C_Stop()
  68. * 功能说明:        产生I2C传输的Stop信号
  69. * 输    入: 无
  70. * 输    出: 无
  71. ******************************************************************************************************************************************/
  72. void SI2C_Stop(void)
  73. {
  74.     SDA_OUT;
  75.     SCL_0;             // scl = 0;
  76.     SDA_0;             // STOP:when CLK is high DATA change form low to high
  77.     delay_us(5);
  78.     SCL_1;             // scl = 1;
  79.     delay_us(5);       
  80.     SDA_1;             // sda = 1;        sclk为高时sdat的上升沿表示“停止”
  81. }


  82. /******************************************************************************************************************************************
  83. * 函数名称: I2C_Send()
  84. * 功能说明:        向IIC总线发送一个字节的数据
  85. * 输    入: byte dat         要发送的数据
  86. * 输    出: 无
  87. ******************************************************************************************************************************************/
  88. void SI2C_Send(uint8_t dat)
  89. {
  90.         uint8_t i;
  91.         SDA_OUT;
  92.         SCL_0;               //拉低时钟开始数据传输
  93.         for(i=0;i<8;i++)
  94.         {
  95. //                if(((dat&0x80)>>7) == 1) SDA_1;//准备好SDA数据
  96.         if((dat>>(7-i))&0x01) SDA_1;
  97.                 else SDA_0;
  98. //                dat>>=1;
  99.                 delay_us(5);
  100.                 SCL_1;                         //拉高时钟等待从设备读取数据
  101.                 delay_us(9);
  102.                 SCL_0;                         //拉低时钟准备下一位数据
  103.                 delay_us(5);
  104.         }
  105. }


  106. /******************************************************************************************************************************************
  107. * 函数名称:        I2C_Receive()
  108. * 功能说明:        从IIC总线接收一个字节的数据
  109. * 输    入: 无
  110. * 输    出: byte                从IIC总线上接收到得数据
  111. * 注意事项: 无
  112. ******************************************************************************************************************************************/
  113. uint8_t SI2C_Receive(void)
  114. {
  115.         uint8_t i,dat;
  116.         SDA_IN;        //设置为输入       
  117.         for(i=0;i<8;i++)
  118.         {
  119.                 SCL_0;
  120.                 delay_us(7);
  121.                 SCL_1;
  122.                 dat<<=1;
  123.         if(1 == SDA_X)
  124.             dat|=0x01;
  125.                 delay_us(5);
  126.         }
  127.         return dat;

  128. /*
  129.         ui08 i = 0;
  130.         byte d = 0;
  131.         byte dat = 0;

  132.         for(i=0;i<8;i++)
  133.     {
  134.                 scl = 0;
  135.                 DELAY();
  136.                 sda = 1;                //本语句必须有:于IIC,是释放SDA线;于51单片机,则是由于51的IO不是真双向口,在读之前必须写0
  137.               DELAY();

  138.               scl = 1;
  139.                 DELAY();
  140.                 d = sda;
  141.               DELAY();

  142.                 dat |= (d<<(7-i));
  143.     }
  144.     return dat;
  145. */
  146. }

  147. /******************************************************************************************************************************************
  148. * 函数名称: I2CDoAck()
  149. * 功能说明:        在应答位位置产生应答,从而继续连续传输
  150. * 输    入: 无
  151. * 输    出: 无
  152. ******************************************************************************************************************************************/
  153. void SI2CDoAck(void)
  154. {
  155.     SCL_0;
  156.         SDA_OUT;
  157.     SDA_0;              //sda = 0;        /拉低数据线,即给于应答
  158.     delay_us(7);
  159.     SCL_1;              //scl = 1;
  160.            delay_us(7);
  161.     SCL_0;                    //scl = 0;
  162. }

  163. /******************************************************************************************************************************************
  164. * 函数名称: I2CNoAck()
  165. * 功能说明:        在应答位位置不产生应答,从而终止连续传输
  166. * 输    入: 无
  167. * 输    出: 无
  168. ******************************************************************************************************************************************/
  169. void SI2CNoAck(void)
  170. {
  171.     SCL_0;
  172.         SDA_OUT;
  173.     SDA_1;              // sda = 1;        不拉低数据线,即不给于应答
  174.     delay_us(7);
  175.     SCL_1;              // scl = 1;
  176.     delay_us(7);
  177.     SCL_0;              // scl = 0;
  178. }

  179. /******************************************************************************************************************************************
  180. * 函数名称: I2CIsAck()
  181. * 功能说明:        检测从机应答位
  182. * 输    入: 无
  183. * 输    出: uint8_t        0=ACK_OK 从机产生了应答;1=ACK_NO 从机没有产生应答
  184. ******************************************************************************************************************************************/
  185. uint8_t SI2CIsAck(void)
  186. {
  187.     uint8_t i;
  188.     SDA_OUT;
  189.     SDA_1;              // sda = 1; 释放数据线
  190.     delay_us(4);
  191.     SDA_IN;
  192.     SCL_1;              // scl = 1;
  193.     delay_us(4);
  194.         while(SDA_X){
  195.                 i++;
  196.                 if(i>250){
  197.                         SI2C_Stop();//数据线未被拉低,即未收到应答
  198.                         return 1;
  199.                 }
  200.         }
  201.     SCL_0;
  202.     return 0;
  203. }


复制代码


  1. #include "i2c.h"
  2. #include "at24c32.h"

  3. /*************************************************************
  4. * 函数名:  at24cxx_Wite_Data(uint8_t addr,uint8_t data)
  5. * 输入参数:addr = 要写入的地址
  6. *           data = 要写入的数据
  7. * 输出参数:无
  8. *************************************************************/
  9. void at24cxx_Write_Data(uint16_t addr,uint8_t data) // 将数据data写入指定地址Addr
  10. {

  11.     SI2C_Start();                //开始I2C通讯
  12.     SI2C_Send(0xA0);             //发送EEPROM器件写入地址
  13.     SI2CIsAck();                 //等待应答
  14.     SI2C_Send(addr>>8);          //发送高8位地址
  15.     SI2CIsAck();                 //等待应答
  16.     SI2C_Send(addr%256);         //发送低8位地址
  17.     SI2CIsAck();                 //等待应答
  18.     SI2C_Send(data);             //发送数据
  19.     SI2CIsAck();                 //等待应答
  20.     SI2C_Stop();                 //结束I2C通讯
  21.     delay_us(4);
  22. }

  23. /*************************************************************
  24. * 函数名:  at24cxx_Read_Data(uint8_t addr)
  25. * 输入参数:addr = 要读取的地址
  26. * 输出参数:data = 读出的数据
  27. *************************************************************/
  28. uint8_t at24cxx_Read_Data(uint16_t addr)            // 读指定地址Addr里的数据Data
  29. {
  30.     uint8_t data=0x00;
  31.    
  32.     SI2C_Start();                //开始I2C通讯
  33.     SI2C_Send(0xA0);             //发送EEPROM器件地址
  34.     SI2CIsAck();                 //等待应答
  35.     SI2C_Send(addr>>8);          //发送高8位地址
  36.     SI2CIsAck();                 //等待应答
  37.     SI2C_Send(addr%256);         //发送低8位地址
  38.     SI2CIsAck();                 //等待应答

  39.     SI2C_Start();
  40.     SI2C_Send(0xA1);             //发送EEPROM器件读取地址
  41.     SI2CIsAck();
  42.    
  43.     data = SI2C_Receive();       //读一字节数据
  44.     SI2CDoAck();
  45.     SI2C_Stop();
  46.     delay_us(4);
  47.     return data;
  48. }

  49. /*************************************************************
  50. * 函数名:  at24cxx_Page_Write(uint8_t addr,uint8_t *buff,uint8_t size)
  51. * 输入参数:addr = 要写入的起始地址
  52. *           *buff= 要写入的数组指针
  53. *           size = 数组的长度
  54. * 输出参数:无
  55. *************************************************************/
  56. void at24cxx_Page_Write(uint16_t addr,uint8_t *buff,uint8_t size) // 将数据buff数组写入指定起的始地址Addr
  57. {
  58.     uint8_t i;
  59.        
  60.     SI2C_Start();                //开始I2C通讯
  61.     SI2C_Send(0xA0);             //发送EEPROM器件写入地址
  62.     SI2CIsAck();                 //等待应答
  63.     SI2C_Send(addr>>8);          //发送高8位地址
  64.     SI2CIsAck();                 //等待应答
  65.     SI2C_Send(addr%256);         //发送低8位地址
  66.     SI2CIsAck();                 //等待应答       
  67.         for(i=0; i<size; i++){
  68.         SI2C_Send(buff[i]);      //发送数据
  69.         SI2CIsAck();             //等待应答
  70.     }
  71.         SI2C_Stop();                 //结束I2C通讯
  72.     delay_us(4);
  73. }

  74. /*************************************************************
  75. * 函数名:  at24cxx_Page_Read(uint8_t addr)
  76. * 输入参数:addr = 要读取的地址
  77. * 输出参数:data = 读出的数据
  78. *************************************************************/
  79. uint8_t at24cxx_Page_Rea(uint16_t addr,uint8_t size)// 读指定起始地址Addr里的数据到buff
  80. {
  81.     uint8_t i,buff[size];
  82.    
  83.     SI2C_Start();                //开始I2C通讯
  84.     SI2C_Send(0xA0);             //发送EEPROM器件地址
  85.     SI2CIsAck();                 //等待应答
  86.     SI2C_Send(addr>>8);          //发送高8位地址
  87.     SI2CIsAck();                 //等待应答
  88.     SI2C_Send(addr%256);         //发送低8位地址
  89.     SI2CIsAck();                 //等待应答

  90.     SI2C_Start();
  91.     SI2C_Send(0xA1);             //发送EEPROM器件读取地址
  92.     SI2CIsAck();
  93.     for(i=0; i<size; i++){
  94.         buff[i] = SI2C_Receive();//读一字节数据
  95.         SI2CDoAck();
  96.     }
  97.         SI2C_Stop();
  98.     delay_us(4);
  99.     return *buff;
  100. }

复制代码
老牛洋车 回答时间:2019-12-8 09:30:26
zhy233090130 回答时间:2019-12-10 09:30:46
hujjj 发表于 2019-12-8 09:30
还希望您支持一下:
https://www.stmcu.org.cn/module/forum/thread-622444-1-1.html

这两天准备调试I2C,谢谢分享
老牛洋车 回答时间:2019-12-10 09:57:55
若调试不成功,则我再抽空在STM32F030开发板上测试,关键就是延时要符合要求,不同主频的单片机,延时会有差异,超出范围则会影响到I2C读写。

评分

参与人数 1蝴蝶豆 +2 收起 理由
STMCU + 2

查看全部评分

butterflyspring 回答时间:2019-12-11 16:04:30
如果有写入eeprom 的功能,注意每次写完之后延时5ms以上,或者用查询模式
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版