[软件资料] 分享个自己写的硬件IIC通讯方法

[复制链接]
 楼主| yuyy1989 发表于 2023-6-7 14:27 | 显示全部楼层 |阅读模式
本帖最后由 yuyy1989 于 2023-6-7 15:01 编辑

鉴于官方库的IIC方法有数组越界的问题,并且不太满足我的使用需求,自己重写了一下,有需要的可以参考一下,已经和DHTC12通信测试过 微信图片_20230607142458.jpg


  1. #include "yuyy_hard_iic.h"
  2. #include "cw32f030_gpio.h"
  3. #include "cw32f030_rcc.h"
  4. #include "cw32f030_i2c.h"

  5. #define YUYY_HARD_IIC(x) x==2?CW_I2C2:CW_I2C1

  6. void yuyy_hard_iic_init(void)
  7. {
  8.     __RCC_GPIOB_CLK_ENABLE();
  9.     __RCC_I2C1_CLK_ENABLE();
  10.     GPIO_InitTypeDef GPIO_InitStructure;
  11.     PB10_AFx_I2C1SCL();
  12.     PB11_AFx_I2C1SDA();
  13.     GPIO_InitStructure.Pins = GPIO_PIN_10 | GPIO_PIN_11;
  14.     GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_OD; //
  15.     GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
  16.     GPIO_Init(CW_GPIOB, &GPIO_InitStructure);
  17.    
  18.     I2C_InitTypeDef I2C_InitStruct;
  19.     I2C_InitStruct.I2C_BaudEn = ENABLE;
  20.     I2C_InitStruct.I2C_Baud = 9;  //100K=(8000000/(8*(1+9))
  21.     I2C_InitStruct.I2C_FLT = ENABLE;
  22.     I2C_InitStruct.I2C_AA = DISABLE;
  23.     I2C1_DeInit();
  24.     I2C_Master_Init(CW_I2C1,&I2C_InitStruct);//初始化模块
  25.     I2C_Cmd(CW_I2C1,ENABLE);  //模块使能
  26. }

  27. uint8_t yuyy_hard_iic_sendregaddr(uint8_t iicx,uint8_t devaddr,uint16_t regaddr,uint8_t regaddrlen)
  28. {
  29.     uint8_t err = 0,u8State,retry = 0,sendlen = 0;
  30.     I2C_GenerateSTART(YUYY_HARD_IIC(iicx), ENABLE);
  31.     while(1)
  32.     {
  33.         while(0 == I2C_GetIrq(YUYY_HARD_IIC(iicx)));
  34.         u8State = I2C_GetState(YUYY_HARD_IIC(iicx));
  35.         switch(u8State)
  36.         {
  37.             case 0x08:   //发送完START信号
  38.             case 0x10:   //发送完重复起始信号
  39.                 I2C_GenerateSTART(YUYY_HARD_IIC(iicx), DISABLE);
  40.                 I2C_Send7bitAddress(YUYY_HARD_IIC(iicx), (devaddr<<1),I2C_Direction_Transmitter);   //发送从机地址
  41.                 break;
  42.             case 0x18:   //发送完SLA+W信号
  43.             case 0x28:   //发送完1字节数据:发送EEPROM中memory地址也会产生,发送后面的数据也会产生
  44.                 if(sendlen < regaddrlen)
  45.                 {
  46.                     if(sendlen == 0 && regaddrlen == 2)
  47.                         I2C_SendData(YUYY_HARD_IIC(iicx),(regaddr>>8)&0xFF);
  48.                     else
  49.                         I2C_SendData(YUYY_HARD_IIC(iicx),regaddr&0xFF);
  50.                 }
  51.                 sendlen++;
  52.                 break;
  53.             case 0x20:   //发送完SLA+W后从机返回NACK
  54.             case 0x38:   //主机在发送 SLA+W 阶段或者发送数据阶段丢失仲裁  或者  主机在发送 SLA+R 阶段或者回应 NACK 阶段丢失仲裁
  55.                 if(retry < 3)
  56.                 {
  57.                     sendlen = 0;
  58.                     I2C_GenerateSTART(YUYY_HARD_IIC(iicx), ENABLE);
  59.                 }
  60.                 else
  61.                     err = 1;
  62.                 retry++;
  63.                 break;
  64.             case 0x30:   //发送完一个数据字节后从机返回NACK
  65.                 err = 1;
  66.                 break;
  67.             default:
  68.                 err = 1;
  69.                 break;
  70.         }
  71.         if(err > 0 || sendlen == regaddrlen)
  72.         {
  73.             if(err > 0)
  74.                         {
  75.                 I2C_GenerateSTOP(YUYY_HARD_IIC(iicx), ENABLE);
  76.                         }
  77.                 I2C_ClearIrq(YUYY_HARD_IIC(iicx));
  78.             break;
  79.         }
  80.         I2C_ClearIrq(YUYY_HARD_IIC(iicx));
  81.     }
  82.     return err;
  83. }

  84. uint8_t yuyy_hard_iic_senddatas(uint8_t iicx,uint8_t devaddr,uint16_t regaddr,uint8_t regaddrlen,uint8_t *datas,uint8_t datalen)
  85. {
  86.         uint8_t err = 0,u8State = 0,sendlen = 0;
  87.     err = yuyy_hard_iic_sendregaddr(iicx,devaddr,regaddr,regaddrlen);
  88.     if(err == 0)
  89.         {
  90.                 while(1)
  91.         {
  92.             while(0 == I2C_GetIrq(YUYY_HARD_IIC(iicx)));
  93.             u8State = I2C_GetState(YUYY_HARD_IIC(iicx));
  94.             switch(u8State)
  95.             {
  96.                 case 0x18:   //发送完SLA+W信号
  97.                 case 0x28:   //发送完1字节数据:发送EEPROM中memory地址也会产生,发送后面的数据也会产生
  98.                     if(sendlen < datalen)
  99.                     {
  100.                         I2C_SendData(YUYY_HARD_IIC(iicx),datas[sendlen]);
  101.                     }
  102.                     sendlen++;
  103.                     break;
  104.                 case 0x20:   //发送完SLA+W后从机返回NACK
  105.                 case 0x38:   //主机在发送 SLA+W 阶段或者发送数据阶段丢失仲裁  或者  主机在发送 SLA+R 阶段或者回应 NACK 阶段丢失仲裁
  106.                     err = 1;
  107.                     break;
  108.                 case 0x30:   //发送完一个数据字节后从机返回NACK
  109.                     err = 1;
  110.                     break;
  111.                 default:
  112.                     err = 1;
  113.                     break;
  114.             }
  115.             if(err > 0 || sendlen > datalen)
  116.             {
  117.                 I2C_GenerateSTOP(YUYY_HARD_IIC(iicx), ENABLE);
  118.                 I2C_ClearIrq(YUYY_HARD_IIC(iicx));
  119.                 break;
  120.             }
  121.             I2C_ClearIrq(YUYY_HARD_IIC(iicx));
  122.         }
  123.         }
  124.     return err;
  125. }
  126. uint8_t yuyy_hard_iic_readdatas(uint8_t iicx,uint8_t devaddr,uint16_t regaddr,uint8_t regaddrlen,uint8_t *datas,uint8_t datalen)
  127. {
  128.         uint8_t err = 0,u8State = 0,retry = 0,i = 0;
  129.     if(regaddrlen > 0)
  130.     {
  131.         err = yuyy_hard_iic_sendregaddr(iicx,devaddr,regaddr,regaddrlen);
  132.         while(0 == I2C_GetIrq(YUYY_HARD_IIC(iicx)));
  133.         I2C_GenerateSTOP(YUYY_HARD_IIC(iicx), ENABLE);
  134.         I2C_ClearIrq(YUYY_HARD_IIC(iicx));
  135.     }
  136.     if(err == 0)
  137.     {
  138.         I2C_GenerateSTART(YUYY_HARD_IIC(iicx), ENABLE);
  139.         while(1)
  140.         {
  141.             while(0 == I2C_GetIrq(YUYY_HARD_IIC(iicx)));
  142.             u8State = I2C_GetState(YUYY_HARD_IIC(iicx));
  143.             switch(u8State)
  144.             {
  145.                 case 0x28:
  146.                     I2C_GenerateSTART(YUYY_HARD_IIC(iicx), ENABLE);
  147.                     break;
  148.                 case 0x08:   //发送完START信号
  149.                 case 0x10:   //发送完重复起始信号
  150.                     I2C_GenerateSTART(YUYY_HARD_IIC(iicx), DISABLE);
  151.                     I2C_Send7bitAddress(YUYY_HARD_IIC(iicx), (devaddr<<1),I2C_Direction_Receiver);   //发送从机地址+R字节
  152.                 case 0x40:   //发送完SLA+R信号,开始接收数据
  153.                     if(datalen>1)
  154.                         I2C_AcknowledgeConfig(YUYY_HARD_IIC(iicx),ENABLE);
  155.                     break;
  156.                 case 0x50:   //接收完一字节数据,在接收最后1字节数据之前设置AA=0;
  157.                     datas[i++] = I2C_ReceiveData(YUYY_HARD_IIC(iicx));
  158.                     if(i==datalen-1)
  159.                         I2C_AcknowledgeConfig(YUYY_HARD_IIC(iicx),DISABLE);
  160.                     break;
  161.                 case 0x58:   //接收到一个数据字节,且NACK已回复
  162.                     datas[i++] = I2C_ReceiveData(YUYY_HARD_IIC(iicx));
  163.                     break;
  164.                 case 0x38:   //主机在发送 SLA+W 阶段或者发送数据阶段丢失仲裁  或者  主机在发送 SLA+R 阶段或者回应 NACK 阶段丢失仲裁
  165.                     //I2C_GenerateSTART(YUYY_HARD_IIC(iicx), ENABLE);
  166.                     err = 1;
  167.                     break;
  168.                 case 0x48:   //发送完SLA+R后从机返回NACK
  169.                     if(retry < 3)
  170.                     {
  171.                         I2C_GenerateSTART(YUYY_HARD_IIC(iicx), ENABLE);
  172.                     }
  173.                     else
  174.                         err = 2;
  175.                     retry++;
  176.                     break;
  177.                 default:
  178.                     err = u8State;
  179.                     break;
  180.             }
  181.             if(i==datalen || err > 0)
  182.             {
  183.                 I2C_GenerateSTOP(YUYY_HARD_IIC(iicx), ENABLE);
  184.                 I2C_ClearIrq(YUYY_HARD_IIC(iicx));
  185.                 break;
  186.             }
  187.             I2C_ClearIrq(YUYY_HARD_IIC(iicx));
  188.         }
  189.     }
  190.     return err;
  191. }


bestwell 发表于 2023-6-10 14:00 | 显示全部楼层
硬件II2C和软件I2C有什么区别
uptown 发表于 2023-6-10 15:36 | 显示全部楼层
设备其地址如何定义?               
beacherblack 发表于 2023-6-10 15:42 | 显示全部楼层
使用单片机自带的IIC模块或外接IIC芯片,连接到需要进行通讯的从设备。在程序中初始化IIC模块,并设置时钟速率、总线地址等参数。
sesefadou 发表于 2023-6-10 15:57 | 显示全部楼层
需要考虑其他因素,如数据缓冲区的大小、中断处理函数的编写等。
kmzuaz 发表于 2023-6-10 16:09 | 显示全部楼层
硬件I2C能与软件I2C一起用一个I2C通道么
macpherson 发表于 2023-6-10 16:32 | 显示全部楼层
常见的串行通信协议,可以实现在多个设备之间进行高效稳定的数据传输。
tabmone 发表于 2023-6-10 16:43 | 显示全部楼层
硬件i2c缺陷解决方法               
bartonalfred 发表于 2023-6-10 16:51 | 显示全部楼层
在进行硬件IIC通信时,需要确保主设备和从设备在速率、地址等参数设置相同
sheflynn 发表于 2023-6-10 17:43 | 显示全部楼层
硬件IIC通讯是一种基于I2C总线的通信方式,可以实现单片机与多个设备之间的数据交换。
51xlf 发表于 2023-6-10 17:50 | 显示全部楼层
两个单片机用IIC通讯,从机的函数要怎么写
 楼主| yuyy1989 发表于 2023-6-10 19:18 | 显示全部楼层
51xlf 发表于 2023-6-10 17:50
两个单片机用IIC通讯,从机的函数要怎么写

官方有作为从机的例程的
chenqianqian 发表于 2023-6-11 19:24 来自手机 | 显示全部楼层
硬件IIC就是调用官方接口函数
OKAKAKO 发表于 2023-6-11 21:09 | 显示全部楼层
IIC通讯改写其实就是对于收发数据进行更多的存储和转换,自带的库函数需要自己进行转换
小夏天的大西瓜 发表于 2023-6-16 16:28 | 显示全部楼层
模拟I2C一般是用GPIO管脚,用软件控制管脚状态以模拟I2C通信波形。
硬件I2C对应芯片上的I2C外设,有相应I2C驱动电路,其所使用的I2C管脚也是专用。
lulugl 发表于 2023-6-21 08:23 | 显示全部楼层
我最近在学习I2C的用法,感觉官方的示例,好象不是很好用,感谢分享。
lulugl 发表于 2023-6-21 08:25 | 显示全部楼层
可以分享一下你的整个工程,我学习一下吗?或者发我邮箱。
nawu 发表于 2023-7-4 16:00 | 显示全部楼层
官方的iic在进行什么操作的时候有越界的可能呢
tpgf 发表于 2023-7-4 16:49 | 显示全部楼层
自己写的iic通讯 其最大通讯速率受限于什么呢
gwsan 发表于 2023-7-4 17:07 | 显示全部楼层
tpgf 发表于 2023-7-4 16:49
自己写的iic通讯 其最大通讯速率受限于什么呢

我觉得一个是主频 一个是io的反应速度
您需要登录后才可以回帖 登录 | 注册

本版积分规则

认证:同飞软件研发工程师
简介:制冷系统单片机软件开发,使用PID控制温度

161

主题

815

帖子

10

粉丝
快速回复 在线客服 返回列表 返回顶部