CUBEIDE设置
使用硬件I2C与sgm芯片通讯,上面即配置硬件I2C,其他参数默认即可。
I2C通讯封装
封装实现
/** * @brief Manages error callback by re-initializing I2C. * @param Addr: I2C Address * @retval None */ static void I2Cx_Error(uint8_t Addr) { /* 恢复I2C寄存器为默认值 */ HAL_I2C_DeInit(&hi2c1); /* 重新初始化I2C外设 */ MX_I2C1_Init(); } /** * @brief 写寄存器,这是提供给上层的接口 * @param slave_addr: 从机地址 * @param reg_addr:寄存器地址 * @param len:写入的长度 * @param data_ptr:指向要写入的数据 * @retval 正常为0,不正常为非0 * HAL_OK = 0x00U, HAL_ERROR = 0x01U, HAL_BUSY = 0x02U, HAL_TIMEOUT = 0x03U */ int smg58031_i2c_writeregister(uint8_t slave_addr, uint8_t reg_addr, uint8_t len, uint8_t *data_ptr) { HAL_StatusTypeDef status = HAL_OK; status = HAL_I2C_Mem_Write(&hi2c1, slave_addr, reg_addr, I2C_MEMADD_SIZE_8BIT,data_ptr, len,I2Cx_FLAG_TIMEOUT); /* 检查通讯状态 */ if(status != HAL_OK) { /* 总线出错处理 */ I2Cx_Error(slave_addr); } while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY) { } /* 检查SENSOR是否就绪进行下一次读写操作 */ while (HAL_I2C_IsDeviceReady(&hi2c1, slave_addr, I2Cx_FLAG_TIMEOUT, I2Cx_FLAG_TIMEOUT) == HAL_TIMEOUT); /* 等待传输结束 */ while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY) { } return status; } /** * @brief 读寄存器,这是提供给上层的接口 * @param slave_addr: 从机地址 * @param reg_addr:寄存器地址 * @param len:要读取的长度 * @param data_ptr:指向要存储数据的指针 * @retval 正常为0,不正常为非0 */ int smg58031_i2c_readregister(uint8_t slave_addr, uint8_t reg_addr, uint8_t len, uint8_t *data_ptr) { HAL_StatusTypeDef status = HAL_OK; status =HAL_I2C_Mem_Read(&hi2c1,slave_addr,reg_addr,I2C_MEMADD_SIZE_8BIT,data_ptr,len,I2Cx_FLAG_TIMEOUT); /* 检查通讯状态 */ if(status != HAL_OK) { /* 总线出错处理 */ I2Cx_Error(slave_addr); } while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY) { } /* 检查SENSOR是否就绪进行下一次读写操作 */ while (HAL_I2C_IsDeviceReady(&hi2c1, slave_addr, I2Cx_FLAG_TIMEOUT, I2Cx_FLAG_TIMEOUT) == HAL_TIMEOUT); /* 等待传输结束 */ while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY) { } return status; }
对应头文件
#define I2Cx_FLAG_TIMEOUT ((uint32_t) 1000) //0x1100 #define I2Cx_LONG_TIMEOUT ((uint32_t) (300 * I2Cx_FLAG_TIMEOUT)) //was300 /** * @brief 读寄存器,这是提供给上层的接口 * @param slave_addr: 从机地址 * @param reg_addr:寄存器地址 * @param len:要读取的长度 * @param data_ptr:指向要存储数据的指针 * @retval 正常为0,不正常为非0 */ int smg58031_i2c_readregister(uint8_t slave_addr, uint8_t reg_addr, uint8_t len, uint8_t *data_ptr); /** * @brief 写寄存器,这是提供给上层的接口 * @param slave_addr: 从机地址 * @param reg_addr:寄存器地址 * @param len:写入的长度 * @param data_ptr:指向要写入的数据 * @retval 正常为0,不正常为非0 */ int smg58031_i2c_writeregister(uint8_t slave_addr, uint8_t reg_addr, uint8_t len, uint8_t *data_ptr);
这段代码是一个用于操作 I2C 总线的函数库。下面是对代码的详细分析:
I2Cx_Error 函数:
该函数用于处理 I2C 错误回调,通过重新初始化 I2C 外设来恢复错误。
首先,使用 HAL_I2C_DeInit 函数将 I2C1 外设的寄存器恢复为默认值。
然后,调用 MX_I2C1_Init 函数重新初始化 I2C1 外设。
smg58031_i2c_writeregister 函数:
这个函数用于向从机设备写入寄存器数据。
函数参数包括从机地址 slave_addr,寄存器地址 reg_addr,要写入的数据长度 len,以及指向要写入数据的指针 data_ptr。
首先,定义一个 HAL_StatusTypeDef 类型的变量 status 并初始化为 HAL_OK。
然后,调用 HAL_I2C_Mem_Write 函数向从机设备写入数据。
接下来,检查通信状态,如果状态不是 HAL_OK,则调用 I2Cx_Error 函数处理总线错误。
然后,使用 HAL_I2C_GetState 函数等待 I2C 状态变为 HAL_I2C_STATE_READY,表示传输完成。
继续使用 HAL_I2C_IsDeviceReady 函数等待从机设备准备就绪。
最后,再次使用 HAL_I2C_GetState 函数等待 I2C 状态变为 HAL_I2C_STATE_READY,确保传输结束。
最后,函数返回 status。
smg58031_i2c_readregister 函数:
这个函数用于从从机设备读取寄存器数据。
函数参数与 smg58031_i2c_writeregister 函数类似。
首先,定义一个 HAL_StatusTypeDef 类型的变量 status 并初始化为 HAL_OK。
然后,调用 HAL_I2C_Mem_Read 函数从从机设备读取数据。
接下来,检查通信状态,如果状态不是 HAL_OK,则调用 I2Cx_Error 函数处理总线错误。
然后,使用 HAL_I2C_GetState 函数等待 I2C 状态变为 HAL_I2C_STATE_READY,表示传输完成。
继续使用 HAL_I2C_IsDeviceReady 函数等待从机设备准备就绪。
最后,再次使用 HAL_I2C_GetState 函数等待 I2C 状态变为 HAL_I2C_STATE_READY,确保传输结束。
最后,函数返回 status。
总体而言,这段代码是一个简单的 I2C 总线操作函数库,提供了向从机设备写入寄存器数据和从从机设备读取寄存器数据的功能。在传输数据之前和之后,对通信状态进行了检查,并在出现错误时重新初始化 I2C 外设。
SGM58031通讯实现
头文件
#define I2C_ADC_ADDR 0x90 //adc模块的写地址 //#define I2C_ADC_ADDR 0x91 //adc模块的读地址 //输入电压 = AINP-AINN 默认AINP=AIN0 AINN=AIN1 //输出数据速率 = 100HZ,即10ms更新一次数据 /* SGM58031内部寄存器地址 */ #define Conversion_Register 0x00 //AD值转换寄存器,16bit数据,默认值0x0000,只读 #define Config_Register 0x01 //配置寄存器,默认0x8583,可读可写 #define Lo_Thresh_Register 0x02 //比较器阈值下限,默认0x8000 #define Hi_Thresh_Register 0x03 //比较器阈值上限,默认0x7FFF #define Config1_Register 0x04 //扩展配置寄存器,默认0x0000 #define ChipID_Register 0x05 //芯片ID,默认0x0080 #define GN_Trim1_Register 0x06 //增益修正,默认0x03FA extern uint8_t control_flag ; void set_adc_control(void); extern uint16_t smg58031_Data_index;//用于保存当前写入数据的索引 0~100 存ADC采采样值用 int read_adc_value(void);
通讯实现
uint8_t control_flag = 0; void set_adc_control(void){ int i = 1; uint8_t value_Config[2] = {0}; uint8_t read_value_Config[2] = {0}; uint8_t value_Config1[1] = {0}; uint8_t chip_id[2] = {0}; uint8_t id; /* Config_Register 0x01 * bit[15] 工作状态/单次激发转换开始对于写入状态: 0=无效果 1=开始单次转换(处于单次激发模式时) 对于读取状态: 0=芯片正在进行转换 1=芯片没有进行转换 此位报告芯片的状态。 只有当芯片处于断电状态时,才能写入此位。 * bit[14:12] = 100 AIN p = AIN0 和 AIN n =GND * bit[11:9] = 010 fs = +-2.048V * bit[8] = 0 连续转换模式 * bit[7:5] = 110 ADC输出数据速率 960HZ (DR_SEL = 1)或 800HZ(DR_SEL = 0) * * bit[4:0]=00011 * bit[4] 0=具有滞后的传统比较器(默认) 1=窗口比较器 * bit[3] 比较器极性 0=有效低(默认) 1=有效高 此位设置ALERT/RDY引脚的有效极性 * bit[2] 锁存比较器 0=非锁存比较器(默认) 1=锁存比较器 该位设置ALERT/RDY引脚在其输出设置后是否锁存,或者当ADC转换结果在上限和下限阈值限制内时是否复位。 * bit[1:0] 比较器队列和禁用功能 00=一次转换后断言 01=两次转换后断定 10=四次转换后确信 11=禁用比较器(默认) 这些位可以禁用比较器。 在alert/RDY引脚上输出警报之前,这些位可以将连续ADC转换所需的时间设置为超过阈值。 */ uint16_t value_Config_Register = 0x44c3;//默认0x8583h value_Config[0] = value_Config_Register >> 8; value_Config[1] = value_Config_Register; /* Config1_Register 0x04 * bit[6] 0=DR[2:0]=000~111转换率为6.25Hz、12.5Hz、25Hz、50Hz、100Hz、200Hz、400Hz和800Hz(默认) * 1=DR[2:0]=000~111转换速率为7.5Hz、15Hz、30Hz、60Hz、120Hz、240Hz、480Hz和960Hz */ uint16_t value_Config1_Register = 0x0040;//默认0x8583h value_Config1[1] = value_Config1_Register; while(i){ i = 0; i += smg58031_i2c_writeregister(I2C_ADC_ADDR, Config_Register, 2, value_Config); HAL_Delay(20); i += smg58031_i2c_writeregister(I2C_ADC_ADDR, Config1_Register, 2, value_Config1); HAL_Delay(20); i += smg58031_i2c_readregister(I2C_ADC_ADDR, ChipID_Register, 2, chip_id); HAL_Delay(20); id = (chip_id[0] << 3) | (chip_id[1] >> 5); // if(id == 0x90) i += smg58031_i2c_readregister(I2C_ADC_ADDR,Config_Register,2,read_value_Config); } control_flag = 1; } float voltage; int read_adc_value(void){ int i = 0; int data; uint16_t tmpHL; uint8_t buf[2]; if(control_flag == 1){ i = smg58031_i2c_readregister(I2C_ADC_ADDR,Conversion_Register,2,buf); if(i != 0){ return -1; } tmpHL= (buf[0] << 8) | buf[1]; // tmpHL= (buf[1] << 8) | buf[0]; voltage = (float) (tmpHL * (2.048 / 32768)); return 0; } return -1; }
这段代码涉及到对 ADC(模数转换器)芯片的控制和读取功能。下面是对代码的详细分析:
set_adc_control 函数:
这个函数用于设置 ADC 控制寄存器的值。
首先,定义了一些变量,包括 value_Config、read_value_Config、value_Config1、chip_id 和 id。
然后,根据注释中的说明,给这些变量赋予相应的数值。
在一个循环中,通过调用 smg58031_i2c_writeregister 函数将 value_Config 和 value_Config1 的值写入对应的寄存器。
紧接着,通过调用 smg58031_i2c_readregister 函数读取 chip_id 的值,并将其转换为 id。
最后,打印相关信息,将 control_flag 置为 1,表示设置控制成功。
read_adc_value 函数:
这个函数用于读取 ADC 转换寄存器的值并进行一些处理。
首先,定义一些变量,包括 data、tmpHL 和 buf。
在 control_flag 为 1 的条件下,通过调用 smg58031_i2c_readregister 函数读取转换寄存器的值,并将结果存储在 buf 中。
接下来,将 buf 中的两个字节按位拼接成一个 16 位的值 tmpHL。
根据公式将 tmpHL 转换为电压值 voltage。
将电压值转换为整型 data,并打印相关信息。
更新 smg58031_Data 数组中的值,并将其打印到串口。
更新 smg58031_Data_index 的值,循环覆盖保存的值。
最后,根据操作的结果返回相应的值。
这段代码主要实现了对 ADC 芯片的控制和读取功能。在 set_adc_control 函数中,通过写入寄存器的方式设置了 ADC 的配置参数。在 read_adc_value 函数中,通过读取寄存器的方式获取了 ADC 的转换结果,并将结果转换为电压值,并保存到数组中。