关于学习炸鸡佬智能手表 应用硬件IIC1来取代原来软件模拟的IIC ...

打印 上一主题 下一主题

主题 985|帖子 985|积分 2955

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
一、用完软件模拟IIC,虽然实现了一个通用接口,只要是IO口都可以用,但是既然引脚用到了PB6和PB7,这俩都是自带硬件外设IIC的,不消白不消。这里我也给出硬件IIC的实现,不得不说HAL库封装的真好

1.硬件IIC

这里我加入一个编译宏,在main.h中,实现可以切换软硬件IIC
硬件IIC速度不要太快,我开始跳到400000的时间触摸是无效的。
其他的设置都在CubeMx生成的iic文件中。这里利用句柄的情势也可以切换差别的iic。
因为我只利用了IIC1 这里也可以再添加一个参数指明利用的是IIC几。
  1. #include "iic_hal_hard.h"
  2. #include "main.h"
  3. #if IICSOFT  == 0
  4. /* I2C1 init function */
  5. void MX_I2C1_Init(I2C_HandleTypeDef *hi2cx)
  6. {
  7.   hi2cx->Instance = I2C1;
  8.   hi2cx->Init.ClockSpeed = 100000;
  9.   hi2cx->Init.DutyCycle = I2C_DUTYCYCLE_2;
  10.   hi2cx->Init.OwnAddress1 = 0;
  11.   hi2cx->Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
  12.   hi2cx->Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
  13.   hi2cx->Init.OwnAddress2 = 0;
  14.   hi2cx->Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
  15.   hi2cx->Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
  16.   if (HAL_I2C_Init(hi2cx) != HAL_OK)
  17.   {
  18.     Error_Handler();
  19.   }
  20. }
  21. void IICInit(I2C_HandleTypeDef *hi2cx)
  22. {
  23.                 MX_I2C1_Init(hi2cx);
  24. }
  25. uint8_t IIC_Write_One_Byte(I2C_HandleTypeDef *hi2cx, uint8_t daddr,uint8_t reg,uint8_t data)
  26. {
  27.         HAL_StatusTypeDef status;
  28.         status = HAL_I2C_Mem_Write(hi2cx, daddr << 1, reg, I2C_MEMADD_SIZE_8BIT, &data, 1, 1000);
  29.         if (status == HAL_OK)
  30.         {
  31.                         return SUCCESS;
  32.         }else
  33.         {
  34.                   return ERROR;
  35.         }
  36. }
  37. uint8_t IIC_Write_Multi_Byte(I2C_HandleTypeDef *hi2cx, uint8_t daddr,uint8_t reg,uint8_t length,uint8_t buff[])
  38. {
  39.         HAL_StatusTypeDef status;
  40.         status = HAL_I2C_Mem_Write(hi2cx, daddr << 1, reg, I2C_MEMADD_SIZE_8BIT, buff, length, 1000);
  41.         if (status == HAL_OK)
  42.         {
  43.                         return SUCCESS;// 数据写入寄存器成功
  44.         }
  45.         else
  46.         {
  47.                          return ERROR;// 数据写入失败,可能是从机无应答、通信错误等原因
  48.         }
  49. }
  50. uint8_t IIC_Read_One_Byte(I2C_HandleTypeDef *hi2cx, uint8_t daddr,uint8_t reg)
  51. {
  52.         HAL_StatusTypeDef status;
  53.         uint8_t RxBuff;
  54.         status = HAL_I2C_Mem_Read(hi2cx, daddr << 1, reg, I2C_MEMADD_SIZE_8BIT, &RxBuff, 1, 1000);
  55.         if (status == HAL_OK)
  56.         {
  57.                         return RxBuff;
  58.         }else
  59.         {
  60.                 return ERROR;
  61.         }
  62.        
  63. }
  64. uint8_t IIC_Read_Multi_Byte(I2C_HandleTypeDef *hi2cx, uint8_t daddr, uint8_t reg, uint8_t length, uint8_t buff[])
  65. {
  66.         HAL_StatusTypeDef status;
  67.        
  68.         status = HAL_I2C_Mem_Read(hi2cx, daddr << 1, reg, I2C_MEMADD_SIZE_8BIT, buff, length, 1000);
  69.         if (status == HAL_OK)
  70.         {
  71.                         return SUCCESS;
  72.         }else
  73.         {
  74.                 return ERROR;
  75.         }
  76. }
  77. #endif
复制代码
HAL库封装的,我觉得没有这个中心IIC接口层也可以实现触摸IC的驱动编写。
2 硬件IIC头文件

  1. #ifndef __IIC_HAL_HARD_H
  2. #define __IIC_HAL_HARD_H
  3. #include "stm32f4xx_hal.h"
  4. #include "main.h"
  5. //PB6 PB7 IIC1外设
  6. #if IICSOFT == 0
  7. extern I2C_HandleTypeDef hi2c1;
  8. void IICInit(I2C_HandleTypeDef *hi2cx);
  9. uint8_t IIC_Write_One_Byte(I2C_HandleTypeDef *hi2cx, uint8_t daddr,uint8_t reg,uint8_t data);
  10. uint8_t IIC_Write_Multi_Byte(I2C_HandleTypeDef *hi2cx, uint8_t daddr,uint8_t reg,uint8_t length,uint8_t buff[]);
  11. uint8_t IIC_Read_One_Byte(I2C_HandleTypeDef *hi2cx, uint8_t daddr,uint8_t reg);
  12. uint8_t IIC_Read_Multi_Byte(I2C_HandleTypeDef *hi2cx, uint8_t daddr, uint8_t reg, uint8_t length, uint8_t buff[]);
  13. #endif
  14. #endif
复制代码
3 修改后的软件IIC

  1. #include "iic_hal.h"
  2. #include "delay.h"
  3. #if IICSOFT == 1
  4. //SCL 低电平期间 SDA可以任意改变电位 高电平不允许改动 因为要采样
  5. // SDA输入模式
  6. void SDA_Input_Mode(iic_bus_t* bus)
  7. {
  8.          GPIO_InitTypeDef GPIO_InitStructure = {0};
  9.          
  10.          GPIO_InitStructure.Pin = bus->IIC_SDA_PIN;
  11.          GPIO_InitStructure.Pull = GPIO_MODE_INPUT;
  12.          GPIO_InitStructure.Pull = GPIO_PULLUP;
  13.          GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
  14.          HAL_GPIO_Init(bus->IIC_SDA_PORT,&GPIO_InitStructure);
  15. }
  16. // SDA输出模式
  17. void SDA_Output_Mode(iic_bus_t* bus)
  18. {
  19.          GPIO_InitTypeDef GPIO_InitStructure = {0};
  20.          
  21.          GPIO_InitStructure.Pin = bus->IIC_SDA_PIN;
  22.          GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;//下次不要这样搞,还是用MX来配置后复制,不然容易错
  23.          GPIO_InitStructure.Pull = GPIO_NOPULL;
  24.          GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
  25.          HAL_GPIO_Init(bus->IIC_SDA_PORT,&GPIO_InitStructure);
  26. }
  27. //SDA输出一个位
  28. void SDA_Output(iic_bus_t *bus, uint8_t val)
  29. {
  30.         if(val)
  31.         HAL_GPIO_WritePin(bus->IIC_SDA_PORT,bus->IIC_SDA_PIN,GPIO_PIN_SET);
  32.         else
  33.         HAL_GPIO_WritePin(bus->IIC_SDA_PORT,bus->IIC_SDA_PIN,GPIO_PIN_RESET);
  34.        
  35. }
  36. //SCL输出一个位
  37. void SCL_Output(iic_bus_t *bus, uint8_t val)
  38. {
  39.         if(val)
  40.         HAL_GPIO_WritePin(bus->IIC_SCL_PORT,bus->IIC_SCL_PIN,GPIO_PIN_SET);
  41.         else
  42.         HAL_GPIO_WritePin(bus->IIC_SCL_PORT,bus->IIC_SCL_PIN,GPIO_PIN_RESET);
  43. }
  44. //SDA输入一位 读一位
  45. uint8_t SDA_Input(iic_bus_t *bus)
  46. {
  47.         //我觉得这里可以直接返回读到得值 不用判断了
  48.         return (uint8_t)HAL_GPIO_ReadPin(bus->IIC_SDA_PORT,bus->IIC_SDA_PIN) ;
  49. }
  50. //从这个严格定义的角度来说,最后将 SCL 拉低这一步不属于起始信号本身的部分
  51. //将 SCL 拉低是为了按照 I2C 通信的正确时序,
  52. //把总线状态调整到适合后续数据传输的起始位置
  53. void IICStart(iic_bus_t *bus)
  54. {
  55.         //当 SCL 为高电平时,SDA 从高电平向低电平跳变
  56.         SDA_Output(bus,1);
  57.         delay_us(2);
  58.         SCL_Output(bus,1);
  59.         delay_us(1);
  60.         SDA_Output(bus,0);
  61.         delay_us(1);
  62.         SCL_Output(bus,0);
  63.         delay_us(1); //
  64.        
  65. }
  66. //严格来说,I2C 协议中定义的停止信号是当 SCL 为高电平时,
  67. //SDA 从低电平向高电平跳变
  68. //为了确保正确的时序过渡:在 I2C 通信中,
  69. //数据的传输和各种信号的产生都是按照严格的时序进行的
  70. void IICStop(iic_bus_t *bus)
  71. {
  72.         //当 SCL 为高电平时,SDA 从低电平向高电平跳变
  73.         SCL_Output(bus,0);
  74.         delay_us(2);
  75.         SDA_Output(bus,0);
  76.         delay_us(1);
  77.         SCL_Output(bus,1);
  78.         delay_us(1); //释放总线
  79.         SDA_Output(bus,1);
  80.         delay_us(1);
  81.        
  82. }
  83. uint8_t IICWaitAck(iic_bus_t *bus)
  84. {       
  85.         uint8_t cErrTime = 5;
  86.         SDA_Input_Mode(bus);//将数据线变成输入模式 接受从机的应答
  87.         SCL_Output(bus,1);// 拉高时钟线
  88.         while(SDA_Input(bus))//读到的数一直是1的话就是没有应答
  89.         {
  90.                 cErrTime--;//读5次都没有结果就是没有应答 表示接受结束
  91.                 delay_us(1);
  92.                 if(0 == cErrTime)
  93.                 {
  94.                         SDA_Output_Mode(bus);
  95.                         IICStop(bus);
  96.                         return ERROR;
  97.                 }
  98.         }
  99.         //如果给了应答 就是读到了0
  100.         SDA_Output_Mode(bus);//转换成输出模式
  101.         SCL_Output(bus,0);//拉低时钟线 为下一个时序做准备
  102.         delay_us(2);
  103.         return SUCCESS;
  104. }
  105. void IICSendAck(iic_bus_t *bus)
  106. {
  107.           SDA_Output(bus,0);//我记得是低电平放上数据
  108.                 delay_us(1);
  109.     SCL_Output(bus,1);
  110.                 delay_us(1);
  111.     SCL_Output(bus,0);
  112.                 delay_us(2);
  113. }
  114. void IICSendNotAck(iic_bus_t *bus)
  115. {
  116.         //我记得是低电平放上数据等时钟线高电平稳定采样 且此时不允许修改数据
  117.                 SDA_Output(bus,1);
  118.                 delay_us(1);
  119.     SCL_Output(bus,1);
  120.                 delay_us(1);
  121.     SCL_Output(bus,0);
  122.                 delay_us(2);
  123. }
  124. void IICSendByte(iic_bus_t *bus, uint8_t cSendByte)
  125. {
  126.           uint8_t i;
  127.                 for(i=0;i<8;i++)
  128.                 {
  129.                         SCL_Output(bus,0);
  130.                         delay_us(2);
  131.                         SDA_Output(bus,((cSendByte >> (7 - i)) & 0x01));
  132.                         delay_us(1);
  133.                         SCL_Output(bus,1);
  134.                         delay_us(1);
  135.                 }
  136.                 SCL_Output(bus,0);
  137.                 delay_us(2);
  138. }
  139. uint8_t IICReceiveByte(iic_bus_t *bus)
  140. {
  141.         uint8_t i, cR_Byte=0;
  142.         uint8_t bit=0;
  143.         SDA_Input_Mode(bus);//接受字节 改成输入模式
  144.         for(i=0;i<8;i++)
  145.         {
  146.                 SCL_Output(bus,0); //拉低时钟线 等待从机放数据
  147.                 delay_us(2);
  148.                 SCL_Output(bus,1);//拉高时钟线 可以采样了
  149.                 delay_us(1);
  150.                 bit = SDA_Input(bus);
  151.                 cR_Byte |= bit << (7-i);
  152.         }
  153.         SCL_Output(bus,0);//拉低时钟线
  154.         SDA_Output_Mode(bus);//改变为输出模式 只有读数据才是输入模式
  155.         return cR_Byte;
  156. }
  157. void IICInit(iic_bus_t *bus)
  158. {
  159.                  GPIO_InitTypeDef GPIO_InitStructure = {0};
  160.                 //bus->CLK_ENABLE();
  161.                
  162.     GPIO_InitStructure.Pin = bus->IIC_SDA_PIN ;
  163.                 //上面给的是开漏 这里变成推挽搞不懂 ,推挽就不用变输入模式了
  164.     GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
  165.     GPIO_InitStructure.Pull = GPIO_NOPULL;
  166.     GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
  167.     HAL_GPIO_Init(bus->IIC_SDA_PORT, &GPIO_InitStructure);
  168.                
  169.                 GPIO_InitStructure.Pin = bus->IIC_SCL_PIN ;
  170.     HAL_GPIO_Init(bus->IIC_SCL_PORT, &GPIO_InitStructure);
  171. }
  172. //返回1表示失败
  173. uint8_t IIC_Write_One_Byte(iic_bus_t *bus, uint8_t daddr,uint8_t reg,uint8_t data)
  174. {
  175.                 IICStart(bus);//开始信号
  176.                 IICSendByte(bus,(daddr << 1));//写从机地址
  177.                 if(IICWaitAck(bus)) //无应答停止传输
  178.                 {
  179.                         IICStop(bus);
  180.                         //printf("%d\r\n",IICWaitAck(bus)); 第一次初始化器件的时候会非应答
  181.                         return 1;
  182.                 }
  183.                 IICSendByte(bus,reg);
  184.                 IICWaitAck(bus);
  185.                 IICSendByte(bus,data);
  186.                 IICWaitAck(bus);
  187.                 IICStop(bus);
  188.                 delay_us(1);
  189.                 return 0;
  190.           
  191. }
  192. uint8_t IIC_Write_Multi_Byte(iic_bus_t *bus, uint8_t daddr,uint8_t reg,uint8_t length,uint8_t buff[])
  193. {
  194.                 uint8_t i;
  195.                 uint8_t* dataPtr = buff;
  196.                 IICStart(bus);//开始信号
  197.                 IICSendByte(bus,(daddr << 1));//写从机地址
  198.                 if(IICWaitAck(bus)) //无应答停止传输
  199.                 {
  200.                         IICStop(bus);
  201.                         return 1;
  202.                 }
  203.                 IICSendByte(bus,reg);
  204.                 IICWaitAck(bus);
  205.                 for(i=0;i<length;i++)
  206.                 {
  207.                         //IICSendByte(bus,buff[i]);            
  208.                         IICSendByte(bus,*dataPtr++);//利用指针指向缓存区 先解引用给首个元素赋值 再指向下一个字节
  209.                         IICWaitAck(bus);
  210.                 }
  211.                 IICStop(bus);
  212.                 delay_us(1);
  213.                 return 0;
  214. }
  215. uint8_t IIC_Read_One_Byte(iic_bus_t *bus, uint8_t daddr,uint8_t reg)
  216. {
  217.                 uint8_t cR_Byte=0;
  218.           IICStart(bus);//开始信号
  219.                 IICSendByte(bus,(daddr << 1));//写从机地址
  220.                 IICWaitAck(bus);
  221.                 IICSendByte(bus,reg);
  222.                 IICWaitAck(bus);
  223.        
  224.                 IICStart(bus);//开始信号
  225.                 IICSendByte(bus,(daddr << 1)| 1);//读操作
  226.                 IICWaitAck(bus);
  227.                 cR_Byte = IICReceiveByte(bus);
  228.                 IICSendNotAck(bus);
  229.                 IICStop(bus);
  230.                 return cR_Byte;
  231. }
  232. uint8_t IIC_Read_Multi_Byte(iic_bus_t *bus, uint8_t daddr, uint8_t reg, uint8_t length, uint8_t buff[])
  233. {
  234.                 uint8_t i;
  235.                 uint8_t* dataPtr = buff;
  236.                 IICStart(bus);//开始信号
  237.                 IICSendByte(bus,(daddr << 1)&0xFE );//写从机地址
  238.                 IICWaitAck(bus);
  239.                 IICSendByte(bus,reg);
  240.                 IICWaitAck(bus);
  241.        
  242.        
  243.                 IICStart(bus);//开始信号
  244.                 IICSendByte(bus,(daddr << 1)| 1);//读操作
  245.                 IICWaitAck(bus);
  246.                 for(i=0;i<length;i++)
  247.                 {
  248.                         //buff[i] = IICReceiveByte(bus);
  249.                         *dataPtr++ = IICReceiveByte(bus);//右++ 先操作后自加
  250.                         if(i<length-1)
  251.                                 IICSendAck(bus);
  252.                         else
  253.                                 IICSendNotAck(bus);
  254.                 }
  255.                
  256.                 IICStop(bus);
  257.                 return 0;
  258. }
  259. #endif
复制代码
4 修改后的软件IIC头文件 (就是加了个宏编译)

  1. #ifndef __IIC_HAL_H
  2. #define __IIC_HAL_H
  3. #include "stm32f4xx_hal.h"
  4. #include "main.h"
  5. #if IICSOFT == 1
  6. typedef struct
  7. {
  8.         GPIO_TypeDef* IIC_SDA_PORT;
  9.         GPIO_TypeDef* IIC_SCL_PORT;
  10.         uint32_t IIC_SDA_PIN;
  11.         uint32_t IIC_SCL_PIN;
  12.         // void (*CLK_ENABLE)(void);
  13. }iic_bus_t;//IIC控制器
  14. void IICStart(iic_bus_t *bus);
  15. void IICStop(iic_bus_t *bus);
  16. uint8_t IICWaitAck(iic_bus_t *bus);
  17. void IICSendAck(iic_bus_t *bus);
  18. void IICSendNotAck(iic_bus_t *bus);
  19. void IICSendByte(iic_bus_t *bus, uint8_t cSendByte);
  20. uint8_t IICReceiveByte(iic_bus_t *bus);
  21. void IICInit(iic_bus_t *bus);
  22. uint8_t IIC_Write_One_Byte(iic_bus_t *bus, uint8_t daddr,uint8_t reg,uint8_t data);
  23. uint8_t IIC_Write_Multi_Byte(iic_bus_t *bus, uint8_t daddr,uint8_t reg,uint8_t length,uint8_t buff[]);
  24. uint8_t IIC_Read_One_Byte(iic_bus_t *bus, uint8_t daddr,uint8_t reg);
  25. uint8_t IIC_Read_Multi_Byte(iic_bus_t *bus, uint8_t daddr, uint8_t reg, uint8_t length, uint8_t buff[]);
  26. #endif
  27. #endif
复制代码


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

渣渣兔

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表