• HC32_HC32F072FAUA_I2C的使用


    1 首先你得有一个工程

    参考前面介绍的:

    HC32_HC32F072FAUA_从零开始搭建空工程模板_江湖上都叫我秋博的博客-CSDN博客

    HC32_keil工程的复制_重命名_以及函数、变量定义的正常跳转问题_江湖上都叫我秋博的博客-CSDN博客

    复制一个新工程,重命名为I2C, 开启美妙的I2C通信之旅

    2 看参考样例

    路径:官网提供的驱动库及样例的压缩包解压后

    xxx\hc32f072_ddl_Rev1.1.1\example\i2c\i2c_bl24c08_poll\MDK\i2c_bl24c08_poll.uvprojx

    3 原理图

    4 对I2C连接的外设做一个简单介绍

    我们的MCU使用I2C是用来连接了一个加速度计芯片 KX023-1025。

    读一下这个KX023-1025的手册。

     

    上面那一大堆英语的翻译+原理图中我们看到了 ADDR引脚是接的地。可以推断出,对本芯片进行读取操作时,设备从地址为: 0x3D,对本芯片进行写入操作时,设备从地址为0x3C。

    之前在我写的一篇博客中我也提到过,一般这种功能芯片,总有一个设备ID。我们I2C通信的第一站,就是读出这个设备ID。

    参考链接:

    传感器_芯片级传感器和功能芯片的使用和编程思路_江湖上都叫我秋博的博客-CSDN博客_传感器怎么编程的

     

     内部地址为 0x0F。 可读可写,这就很妙了。 那我们就可以用这个地址进行读和写操作的验证了。

    这个芯片内部的寄存器,默认值是0x15.

    5 我们的代码 

    main.c

    1. #include "ddl.h"
    2. #include "uart.h"
    3. #include "gpio.h"
    4. #include "dac.h"
    5. #include "flash.h"
    6. #include "i2c.h"
    7. #include "user_gpio.h"
    8. #include "user_uart.h"
    9. #include "user_dac.h"
    10. #include "user_adc.h"
    11. #include "user_i2c.h"
    12. uint8_t Whoiam[10] = {0x2F};
    13. en_result_t I2CRet = Error;
    14. int32_t main(void)
    15. {
    16. sys_clk_init(); // 系统的时钟初始化 应该放在串口初始化之前 否则系统会出问题
    17. user_led_init();
    18. user_uart_init();
    19. user_dac_init();
    20. user_adc_init();
    21. user_i2c_init();
    22. I2C_SetFunc(M0P_I2C0,I2cStart_En); // 开始信号
    23. I2CRet = I2C_MasterWriteData(M0P_I2C0, 0x0F, &Whoiam[0], 1); // 往芯片内部的0x0F这个地址,写入0x2F
    24. Whoiam[0] = 0x00;
    25. delay1ms(100); // 延迟100ms
    26. I2CRet = I2C_MasterReadData(M0P_I2C0, 0x0F, &Whoiam[0], 1); // 从芯片内部的0x0F这个地址,读一个数据到Whoiam
    27. while(1)
    28. {
    29. }
    30. }

    user_i2c.c

    1. #include "user_i2c.h"
    2. #include "i2c.h"
    3. #include "gpio.h"
    4. // I2C 引脚配置
    5. void i2c_gpio_config(void)
    6. {
    7. stc_gpio_cfg_t stcGpioCfg;
    8. DDL_ZERO_STRUCT(stcGpioCfg);
    9. Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio,TRUE); //开启GPIO时钟门控
    10. stcGpioCfg.enDir = GpioDirOut; // 端口方向配置->输出
    11. stcGpioCfg.enOD = GpioOdEnable; // 开漏输出
    12. stcGpioCfg.enPu = GpioPuEnable; // 端口上拉配置->使能
    13. stcGpioCfg.enPd = GpioPdDisable; // 端口下拉配置->禁止
    14. Gpio_Init(GpioPortB,GpioPin8,&stcGpioCfg); // 端口初始化
    15. Gpio_Init(GpioPortB,GpioPin9,&stcGpioCfg);
    16. Gpio_Init(GpioPortB,GpioPin1,&stcGpioCfg); // MCU_ncs
    17. Gpio_SetIO(GpioPortB, GpioPin1); // ★经实验,ncs脚要拉高才行
    18. Gpio_SetAfMode(GpioPortB,GpioPin8,GpioAf1); // 配置PB08为SCL
    19. Gpio_SetAfMode(GpioPortB,GpioPin9,GpioAf1); // 配置PB09为SDA
    20. }
    21. // I2C 模块配置
    22. void i2c_config(void)
    23. {
    24. stc_i2c_cfg_t stcI2cCfg;
    25. DDL_ZERO_STRUCT(stcI2cCfg); // 初始化结构体变量的值为0
    26. Sysctrl_SetPeripheralGate(SysctrlPeripheralI2c0,TRUE); // 开启I2C0时钟门控
    27. stcI2cCfg.u32Pclk = Sysctrl_GetPClkFreq(); // 获取PCLK时钟
    28. stcI2cCfg.u32Baud = 1000000; // 1MHz
    29. stcI2cCfg.enMode = I2cMasterMode; // 主机模式
    30. stcI2cCfg.u8SlaveAddr = 0x55; // 从地址,主模式无效
    31. stcI2cCfg.bGc = FALSE; // 广播地址应答使能关闭
    32. I2C_Init(M0P_I2C0,&stcI2cCfg); // 模块初始化
    33. }
    34. /**
    35. ******************************************************************************
    36. ** \brief 主机接收函数
    37. **
    38. ** \param u8Addr从机内存地址,pu8Data读数据存放缓存,u32Len读数据长度
    39. **
    40. ** \retval 读数据是否成功
    41. **
    42. ******************************************************************************/
    43. /**
    44. ******************************************************************************
    45. ** \brief 主机接收函数
    46. **
    47. ** \param u8Addr从机内存地址,pu8Data读数据存放缓存,u32Len读数据长度
    48. **
    49. ** \retval 读数据是否成功
    50. **
    51. ******************************************************************************/
    52. en_result_t I2C_MasterReadData(M0P_I2C_TypeDef* I2CX,uint8_t u8Addr,uint8_t *pu8Data,uint32_t u32Len)
    53. {
    54. en_result_t enRet = Error;
    55. uint8_t u8i=0,u8State;
    56. I2C_SetFunc(I2CX,I2cStart_En);
    57. while(1)
    58. {
    59. while(0 == I2C_GetIrq(I2CX))
    60. {}
    61. u8State = I2C_GetState(I2CX);
    62. switch(u8State)
    63. {
    64. case 0x08: ///< 已发送起始条件,将发送SLA+W
    65. I2C_ClearFunc(I2CX,I2cStart_En);
    66. I2C_WriteByte(I2CX,I2C_SLAVE_ADDR_Rd);
    67. break;
    68. case 0x18: ///< 已发送SLA+W,并接收到ACK
    69. I2C_WriteByte(I2CX,u8Addr); ///< 发送从机内存地址
    70. break;
    71. case 0x28: ///< 已发送数据,接收到ACK, 此处是已发送从机内存地址u8Addr并接收到ACK
    72. I2C_SetFunc(I2CX,I2cStart_En); ///< 发送重复起始条件
    73. break;
    74. case 0x10: ///< 已发送重复起始条件
    75. I2C_ClearFunc(I2CX,I2cStart_En);
    76. I2C_WriteByte(I2CX,I2C_SLAVE_ADDR_Rd|0x01);///< 发送SLA+R,开始从从机读取数据
    77. break;
    78. case 0x40: ///< 已发送SLA+R,并接收到ACK
    79. if(u32Len>1)
    80. {
    81. I2C_SetFunc(I2CX,I2cAck_En); ///< 使能主机应答功能
    82. }
    83. break;
    84. case 0x50: ///< 已接收数据字节,并已返回ACK信号
    85. pu8Data[u8i++] = I2C_ReadByte(I2CX);
    86. if(u8i==u32Len-1)
    87. {
    88. I2C_ClearFunc(I2CX,I2cAck_En); ///< 已接收到倒数第二个字节,关闭ACK应答功能
    89. }
    90. break;
    91. case 0x58: ///< 已接收到最后一个数据,NACK已返回
    92. pu8Data[u8i++] = I2C_ReadByte(I2CX);
    93. I2C_SetFunc(I2CX,I2cStop_En); ///< 发送停止条件
    94. break;
    95. case 0x38: ///< 在发送地址或数据时,仲裁丢失
    96. I2C_SetFunc(I2CX,I2cStart_En); ///< 当总线空闲时发起起始条件
    97. break;
    98. case 0x48: ///< 发送SLA+R后,收到一个NACK
    99. I2C_SetFunc(I2CX,I2cStop_En); ///< 发送停止条件
    100. I2C_SetFunc(I2CX,I2cStart_En); ///< 发送起始条件
    101. break;
    102. default:
    103. I2C_SetFunc(I2CX,I2cStart_En); ///< 其他错误状态,重新发送起始条件
    104. break;
    105. }
    106. I2C_ClearIrq(I2CX); ///< 清除中断状态标志位
    107. if(u8i==u32Len) ///< 数据全部读取完成,跳出while循环
    108. {
    109. break;
    110. }
    111. }
    112. enRet = Ok;
    113. return enRet;
    114. }
    115. /**
    116. ******************************************************************************
    117. ** \brief 主机发送函数
    118. **
    119. ** \param u8Addr从机内存地址,pu8Data写数据,u32Len写数据长度
    120. **
    121. ** \retval 写数据是否成功
    122. **
    123. ******************************************************************************/
    124. en_result_t I2C_MasterWriteData(M0P_I2C_TypeDef* I2CX,uint8_t u8Addr,uint8_t *pu8Data,uint32_t u32Len)
    125. {
    126. en_result_t enRet = Error;
    127. uint8_t u8i=0,u8State;
    128. I2C_SetFunc(I2CX,I2cStart_En);
    129. while(1)
    130. {
    131. while(0 == I2C_GetIrq(I2CX))
    132. {;}
    133. u8State = I2C_GetState(I2CX);
    134. switch(u8State)
    135. {
    136. case 0x08: ///< 已发送起始条件
    137. I2C_ClearFunc(I2CX,I2cStart_En);
    138. I2C_WriteByte(I2CX,I2C_SLAVE_ADDR_Wr); ///< 从设备地址发送
    139. break;
    140. case 0x18: ///< 已发送SLA+W,并接收到ACK
    141. I2C_WriteByte(I2CX,u8Addr); ///< 从设备内存地址发送
    142. break;
    143. case 0x28: ///< 上一次发送数据后接收到ACK
    144. I2C_WriteByte(I2CX,pu8Data[u8i++]); ///< 继续发送数据
    145. break;
    146. case 0x20: ///< 上一次发送SLA+W后,收到NACK
    147. case 0x38: ///< 上一次在SLA+读或写时丢失仲裁
    148. I2C_SetFunc(I2CX,I2cStart_En); ///< 当I2C总线空闲时发送起始条件
    149. break;
    150. case 0x30: ///< 已发送I2Cx_DATA中的数据,收到NACK,将传输一个STOP条件
    151. I2C_SetFunc(I2CX,I2cStop_En); ///< 发送停止条件
    152. break;
    153. default:
    154. break;
    155. }
    156. if(u8i>u32Len)
    157. {
    158. I2C_SetFunc(I2CX,I2cStop_En); ///< 此顺序不能调换,出停止条件
    159. I2C_ClearIrq(I2CX);
    160. break;
    161. }
    162. I2C_ClearIrq(I2CX); ///< 清除中断状态标志位
    163. }
    164. enRet = Ok;
    165. return enRet;
    166. }
    167. void user_i2c_init(void)
    168. {
    169. i2c_gpio_config();
    170. i2c_config();
    171. }

    user_i2c.h

    1. #ifndef _USER_I2C_H_
    2. #define _USER_I2C_H_
    3. #include "ddl.h"
    4. #define I2C_SLAVE_ADDR_Rd 0x3D
    5. #define I2C_SLAVE_ADDR_Wr 0x3C
    6. void i2c_gpio_config(void);
    7. void i2c_config(void);
    8. void user_i2c_init(void);
    9. en_result_t I2C_MasterReadData(M0P_I2C_TypeDef* I2CX,uint8_t u8Addr, uint8_t *pu8Data,uint32_t u32Len);
    10. en_result_t I2C_MasterWriteData(M0P_I2C_TypeDef* I2CX,uint8_t u8Addr, uint8_t *pu8Data,uint32_t u32Len);
    11. #endif

    我们往芯片内部的Who_AM_I这个寄存器写入了0x2F,然后再读取芯片内部的Who_AM_I寄存器的值,实验结果确实是0x2F,这说明我们的I2C通信成功了。

     感谢您的阅读,欢迎留言讨论、收藏、点赞、分享。

  • 相关阅读:
    【JUC】9.对象内存布局
    Kylin (四) --------- Kylin 4.0 查询引擎
    京东获得店铺的所有商品 API
    WebStorm 在Settings → File and Code Templates中 自定义一个用于创建Vue2.0的模板。
    Caché for UNIX®, Linux及macOS的安装及配置
    filebeat实现实时采集日志
    基于MySql,Redis,Mq,ES的高可用方案解析
    92、Redis ------- 使用 Lettuce 操作 Redis 的方法和步骤----(文字讲解无代码)
    信道状态信息(CSI)的信号变换
    查看linux开发板的CPU频率
  • 原文地址:https://blog.csdn.net/heqiunong/article/details/126227744