参考前面介绍的:
HC32_HC32F072FAUA_从零开始搭建空工程模板_江湖上都叫我秋博的博客-CSDN博客
HC32_keil工程的复制_重命名_以及函数、变量定义的正常跳转问题_江湖上都叫我秋博的博客-CSDN博客
复制一个新工程,重命名为I2C, 开启美妙的I2C通信之旅
路径:官网提供的驱动库及样例的压缩包解压后
xxx\hc32f072_ddl_Rev1.1.1\example\i2c\i2c_bl24c08_poll\MDK\i2c_bl24c08_poll.uvprojx
我们的MCU使用I2C是用来连接了一个加速度计芯片 KX023-1025。
读一下这个KX023-1025的手册。
上面那一大堆英语的翻译+原理图中我们看到了 ADDR引脚是接的地。可以推断出,对本芯片进行读取操作时,设备从地址为: 0x3D,对本芯片进行写入操作时,设备从地址为0x3C。
之前在我写的一篇博客中我也提到过,一般这种功能芯片,总有一个设备ID。我们I2C通信的第一站,就是读出这个设备ID。
参考链接:
传感器_芯片级传感器和功能芯片的使用和编程思路_江湖上都叫我秋博的博客-CSDN博客_传感器怎么编程的
内部地址为 0x0F。 可读可写,这就很妙了。 那我们就可以用这个地址进行读和写操作的验证了。
这个芯片内部的寄存器,默认值是0x15.
main.c
- #include "ddl.h"
- #include "uart.h"
- #include "gpio.h"
- #include "dac.h"
- #include "flash.h"
- #include "i2c.h"
-
- #include "user_gpio.h"
- #include "user_uart.h"
- #include "user_dac.h"
- #include "user_adc.h"
- #include "user_i2c.h"
-
- uint8_t Whoiam[10] = {0x2F};
- en_result_t I2CRet = Error;
-
- int32_t main(void)
- {
-
-
- sys_clk_init(); // 系统的时钟初始化 应该放在串口初始化之前 否则系统会出问题
- user_led_init();
- user_uart_init();
- user_dac_init();
- user_adc_init();
- user_i2c_init();
-
- I2C_SetFunc(M0P_I2C0,I2cStart_En); // 开始信号
-
- I2CRet = I2C_MasterWriteData(M0P_I2C0, 0x0F, &Whoiam[0], 1); // 往芯片内部的0x0F这个地址,写入0x2F
-
- Whoiam[0] = 0x00;
-
- delay1ms(100); // 延迟100ms
-
- I2CRet = I2C_MasterReadData(M0P_I2C0, 0x0F, &Whoiam[0], 1); // 从芯片内部的0x0F这个地址,读一个数据到Whoiam
-
- while(1)
- {
- }
- }
user_i2c.c
- #include "user_i2c.h"
- #include "i2c.h"
- #include "gpio.h"
-
- // I2C 引脚配置
- void i2c_gpio_config(void)
- {
-
- stc_gpio_cfg_t stcGpioCfg;
-
- DDL_ZERO_STRUCT(stcGpioCfg);
-
- Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio,TRUE); //开启GPIO时钟门控
-
- stcGpioCfg.enDir = GpioDirOut; // 端口方向配置->输出
- stcGpioCfg.enOD = GpioOdEnable; // 开漏输出
- stcGpioCfg.enPu = GpioPuEnable; // 端口上拉配置->使能
- stcGpioCfg.enPd = GpioPdDisable; // 端口下拉配置->禁止
-
- Gpio_Init(GpioPortB,GpioPin8,&stcGpioCfg); // 端口初始化
- Gpio_Init(GpioPortB,GpioPin9,&stcGpioCfg);
-
- Gpio_Init(GpioPortB,GpioPin1,&stcGpioCfg); // MCU_ncs
- Gpio_SetIO(GpioPortB, GpioPin1); // ★经实验,ncs脚要拉高才行
-
- Gpio_SetAfMode(GpioPortB,GpioPin8,GpioAf1); // 配置PB08为SCL
- Gpio_SetAfMode(GpioPortB,GpioPin9,GpioAf1); // 配置PB09为SDA
-
- }
-
- // I2C 模块配置
- void i2c_config(void)
- {
- stc_i2c_cfg_t stcI2cCfg;
-
- DDL_ZERO_STRUCT(stcI2cCfg); // 初始化结构体变量的值为0
-
- Sysctrl_SetPeripheralGate(SysctrlPeripheralI2c0,TRUE); // 开启I2C0时钟门控
-
- stcI2cCfg.u32Pclk = Sysctrl_GetPClkFreq(); // 获取PCLK时钟
- stcI2cCfg.u32Baud = 1000000; // 1MHz
- stcI2cCfg.enMode = I2cMasterMode; // 主机模式
- stcI2cCfg.u8SlaveAddr = 0x55; // 从地址,主模式无效
- stcI2cCfg.bGc = FALSE; // 广播地址应答使能关闭
- I2C_Init(M0P_I2C0,&stcI2cCfg); // 模块初始化
- }
-
- /**
- ******************************************************************************
- ** \brief 主机接收函数
- **
- ** \param u8Addr从机内存地址,pu8Data读数据存放缓存,u32Len读数据长度
- **
- ** \retval 读数据是否成功
- **
- ******************************************************************************/
-
-
- /**
- ******************************************************************************
- ** \brief 主机接收函数
- **
- ** \param u8Addr从机内存地址,pu8Data读数据存放缓存,u32Len读数据长度
- **
- ** \retval 读数据是否成功
- **
- ******************************************************************************/
- en_result_t I2C_MasterReadData(M0P_I2C_TypeDef* I2CX,uint8_t u8Addr,uint8_t *pu8Data,uint32_t u32Len)
- {
- en_result_t enRet = Error;
- uint8_t u8i=0,u8State;
-
- I2C_SetFunc(I2CX,I2cStart_En);
-
- while(1)
- {
- while(0 == I2C_GetIrq(I2CX))
- {}
- u8State = I2C_GetState(I2CX);
- switch(u8State)
- {
- case 0x08: ///< 已发送起始条件,将发送SLA+W
- I2C_ClearFunc(I2CX,I2cStart_En);
- I2C_WriteByte(I2CX,I2C_SLAVE_ADDR_Rd);
- break;
- case 0x18: ///< 已发送SLA+W,并接收到ACK
- I2C_WriteByte(I2CX,u8Addr); ///< 发送从机内存地址
- break;
- case 0x28: ///< 已发送数据,接收到ACK, 此处是已发送从机内存地址u8Addr并接收到ACK
- I2C_SetFunc(I2CX,I2cStart_En); ///< 发送重复起始条件
- break;
- case 0x10: ///< 已发送重复起始条件
- I2C_ClearFunc(I2CX,I2cStart_En);
- I2C_WriteByte(I2CX,I2C_SLAVE_ADDR_Rd|0x01);///< 发送SLA+R,开始从从机读取数据
- break;
- case 0x40: ///< 已发送SLA+R,并接收到ACK
- if(u32Len>1)
- {
- I2C_SetFunc(I2CX,I2cAck_En); ///< 使能主机应答功能
- }
- break;
- case 0x50: ///< 已接收数据字节,并已返回ACK信号
- pu8Data[u8i++] = I2C_ReadByte(I2CX);
- if(u8i==u32Len-1)
- {
- I2C_ClearFunc(I2CX,I2cAck_En); ///< 已接收到倒数第二个字节,关闭ACK应答功能
- }
- break;
- case 0x58: ///< 已接收到最后一个数据,NACK已返回
- pu8Data[u8i++] = I2C_ReadByte(I2CX);
- I2C_SetFunc(I2CX,I2cStop_En); ///< 发送停止条件
- break;
- case 0x38: ///< 在发送地址或数据时,仲裁丢失
- I2C_SetFunc(I2CX,I2cStart_En); ///< 当总线空闲时发起起始条件
- break;
- case 0x48: ///< 发送SLA+R后,收到一个NACK
- I2C_SetFunc(I2CX,I2cStop_En); ///< 发送停止条件
- I2C_SetFunc(I2CX,I2cStart_En); ///< 发送起始条件
- break;
- default:
- I2C_SetFunc(I2CX,I2cStart_En); ///< 其他错误状态,重新发送起始条件
- break;
- }
- I2C_ClearIrq(I2CX); ///< 清除中断状态标志位
- if(u8i==u32Len) ///< 数据全部读取完成,跳出while循环
- {
- break;
- }
- }
- enRet = Ok;
- return enRet;
- }
- /**
- ******************************************************************************
- ** \brief 主机发送函数
- **
- ** \param u8Addr从机内存地址,pu8Data写数据,u32Len写数据长度
- **
- ** \retval 写数据是否成功
- **
- ******************************************************************************/
- en_result_t I2C_MasterWriteData(M0P_I2C_TypeDef* I2CX,uint8_t u8Addr,uint8_t *pu8Data,uint32_t u32Len)
- {
- en_result_t enRet = Error;
- uint8_t u8i=0,u8State;
- I2C_SetFunc(I2CX,I2cStart_En);
- while(1)
- {
- while(0 == I2C_GetIrq(I2CX))
- {;}
- u8State = I2C_GetState(I2CX);
- switch(u8State)
- {
- case 0x08: ///< 已发送起始条件
- I2C_ClearFunc(I2CX,I2cStart_En);
- I2C_WriteByte(I2CX,I2C_SLAVE_ADDR_Wr); ///< 从设备地址发送
- break;
- case 0x18: ///< 已发送SLA+W,并接收到ACK
- I2C_WriteByte(I2CX,u8Addr); ///< 从设备内存地址发送
- break;
- case 0x28: ///< 上一次发送数据后接收到ACK
- I2C_WriteByte(I2CX,pu8Data[u8i++]); ///< 继续发送数据
- break;
- case 0x20: ///< 上一次发送SLA+W后,收到NACK
- case 0x38: ///< 上一次在SLA+读或写时丢失仲裁
- I2C_SetFunc(I2CX,I2cStart_En); ///< 当I2C总线空闲时发送起始条件
- break;
- case 0x30: ///< 已发送I2Cx_DATA中的数据,收到NACK,将传输一个STOP条件
- I2C_SetFunc(I2CX,I2cStop_En); ///< 发送停止条件
- break;
- default:
- break;
- }
- if(u8i>u32Len)
- {
- I2C_SetFunc(I2CX,I2cStop_En); ///< 此顺序不能调换,出停止条件
- I2C_ClearIrq(I2CX);
- break;
- }
- I2C_ClearIrq(I2CX); ///< 清除中断状态标志位
- }
- enRet = Ok;
- return enRet;
-
- }
-
-
- void user_i2c_init(void)
- {
- i2c_gpio_config();
- i2c_config();
- }
-
-
user_i2c.h
- #ifndef _USER_I2C_H_
- #define _USER_I2C_H_
-
- #include "ddl.h"
-
- #define I2C_SLAVE_ADDR_Rd 0x3D
- #define I2C_SLAVE_ADDR_Wr 0x3C
-
- void i2c_gpio_config(void);
- void i2c_config(void);
- void user_i2c_init(void);
-
- en_result_t I2C_MasterReadData(M0P_I2C_TypeDef* I2CX,uint8_t u8Addr, uint8_t *pu8Data,uint32_t u32Len);
- en_result_t I2C_MasterWriteData(M0P_I2C_TypeDef* I2CX,uint8_t u8Addr, uint8_t *pu8Data,uint32_t u32Len);
- #endif
-
我们往芯片内部的Who_AM_I这个寄存器写入了0x2F,然后再读取芯片内部的Who_AM_I寄存器的值,实验结果确实是0x2F,这说明我们的I2C通信成功了。
感谢您的阅读,欢迎留言讨论、收藏、点赞、分享。