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

求个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管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版