活动任务三是使用INA219对测量5V,12V负载电压电流并显示在OLED。首先对硬件部分进行介绍。
# 硬件连接
开发板上的I2C3的SCL为PA8,SDA为PC9。
INA219模块的接口是I2C,连接开发板I2C3和模块的对应管脚,实现开发板与模块之间的硬件连接。另外,连接开关电源、稳压模块、继电器、OLED屏幕和负载。
连接12V负载的连接图如下,
检测负载的效果如下
# INA219驱动移植
INA219的驱动使用现有的libdriver中的INA219驱动。
https://gitee.com/libdriver/ina219
驱动库的代码分布如下,在移植时,复制驱动源码到工程中,参考驱动接口中的模板实现MCU平台上的通讯接口,参考示例程序使用驱动函数获取INA219的信息。
使用上述驱动库,需要完成几个接口函数,针对开发板的实现如下
#include "driver_ina219_interface.h" #include <stdarg.h> #include <main.h> /** * @brief interface iic bus init * @return status code * - 0 success * - 1 iic init failed * @note none */ uint8_t ina219_interface_iic_init(void) { return 0; } /** * @brief interface iic bus deinit * @return status code * - 0 success * - 1 iic deinit failed * @note none */ uint8_t ina219_interface_iic_deinit(void) { return 0; } /** * @brief interface iic bus read * @param[in] addr iic device write address * @param[in] reg iic register address * @param[out] *buf pointer to a data buffer * @param[in] len length of the data buffer * @return status code * - 0 success * - 1 read failed * @note none */ uint8_t ina219_interface_iic_read(uint8_t addr, uint8_t reg, uint8_t *buf, uint16_t len) { HAL_StatusTypeDef ret; ret=HAL_I2C_Mem_Read(&hi2c3, addr, reg, 1, buf, len, HAL_MAX_DELAY); if(ret!=HAL_OK) return 1; return 0; } /** * @brief interface iic bus write * @param[in] addr iic device write address * @param[in] reg iic register address * @param[in] *buf pointer to a data buffer * @param[in] len length of the data buffer * @return status code * - 0 success * - 1 write failed * @note none */ uint8_t ina219_interface_iic_write(uint8_t addr, uint8_t reg, uint8_t *buf, uint16_t len) { HAL_StatusTypeDef ret; ret=HAL_I2C_Mem_Write(&hi2c3, addr, reg, 1, buf, len, HAL_MAX_DELAY); if(ret!=HAL_OK) return 1; return 0; } /** * @brief interface delay ms * @param[in] ms time * @note none */ void ina219_interface_delay_ms(uint32_t ms) { HAL_Delay(ms); }
在工程中添加驱动相关的代码文件,并且在工程的路径中添加存放代码的文件夹路径。
这样,就可以在工程中调用驱动库中的函数来使用INA219检测设备的功率信息。
# INA219驱动使用
在工程中,封装INA219的初始化过程和功率信息的操作为以下两个函数:
uint8_t ina219_basic_init(ina219_address_t addr_pin, double r) { uint8_t res; uint16_t calibration; /* link interface function */ DRIVER_INA219_LINK_INIT(&gs_handle, ina219_handle_t); DRIVER_INA219_LINK_IIC_INIT(&gs_handle, ina219_interface_iic_init); DRIVER_INA219_LINK_IIC_DEINIT(&gs_handle, ina219_interface_iic_deinit); DRIVER_INA219_LINK_IIC_READ(&gs_handle, ina219_interface_iic_read); DRIVER_INA219_LINK_IIC_WRITE(&gs_handle, ina219_interface_iic_write); DRIVER_INA219_LINK_DELAY_MS(&gs_handle, ina219_interface_delay_ms); DRIVER_INA219_LINK_DEBUG_PRINT(&gs_handle, ina219_interface_debug_print); /* set addr pin */ res = ina219_set_addr_pin(&gs_handle, addr_pin); if (res != 0) { return 1; } /* set the r */ res = ina219_set_resistance(&gs_handle, r); if (res != 0) { return 1; } /* init */ res = ina219_init(&gs_handle); if (res != 0) { return 1; } /* set bus voltage range */ res = ina219_set_bus_voltage_range(&gs_handle, INA219_BASIC_DEFAULT_BUS_VOLTAGE_RANGE); if (res != 0) { (void)ina219_deinit(&gs_handle); return 1; } /* set bus voltage adc mode */ res = ina219_set_bus_voltage_adc_mode(&gs_handle, INA219_BASIC_DEFAULT_BUS_VOLTAGE_ADC_MODE); if (res != 0) { (void)ina219_deinit(&gs_handle); return 1; } /* set shunt voltage adc mode */ res = ina219_set_shunt_voltage_adc_mode(&gs_handle, INA219_BASIC_DEFAULT_SHUNT_VOLTAGE_ADC_MODE); if (res != 0) { (void)ina219_deinit(&gs_handle); return 1; } /* set shunt bus voltage continuous */ res = ina219_set_mode(&gs_handle, INA219_MODE_SHUNT_BUS_VOLTAGE_CONTINUOUS); if (res != 0) { (void)ina219_deinit(&gs_handle); return 1; } /* set pga */ res = ina219_set_pga(&gs_handle, INA219_BASIC_DEFAULT_PGA); if (res != 0) { (void)ina219_deinit(&gs_handle); return 1; } /* calculate calibration */ res = ina219_calculate_calibration(&gs_handle, (uint16_t *)&calibration); if (res != 0) { (void)ina219_deinit(&gs_handle); return 1; } /* set calibration */ res = ina219_set_calibration(&gs_handle, calibration); if (res != 0) { (void)ina219_deinit(&gs_handle); return 1; } return 0; } /** * @brief basic example read * @param[out] *mV pointer to a mV buffer * @param[out] *mA pointer to a mA buffer * @param[out] *mW pointer to a mW buffer * @return status code * - 0 success * - 1 read failed * @note none */ uint8_t ina219_basic_read(float *mV, float *mA, float *mW) { uint8_t res; int16_t s_raw; uint16_t u_raw; /* read bus voltage */ res = ina219_read_bus_voltage(&gs_handle, (uint16_t *)&u_raw, mV); if (res != 0) { return 1; } /* read current */ res = ina219_read_current(&gs_handle, (int16_t *)&s_raw, mA); if (res != 0) { return 1; } /* read power */ res = ina219_read_power(&gs_handle, (uint16_t *)&u_raw, mW); if (res != 0) { return 1; } return 0; }
在主函数中调用定义的INA219初始化函数以及功率信息读取函数来获取功率信息。
ina219_basic_init(INA219_ADDRESS_0, 0.01); ina219_interface_delay_ms(1000); ina219_basic_read(&mV, &mA, &mW);
将获取到到的功率信息显示在OLED屏幕上
float mV; float mA,mA_sum,mA_ave; float mW; static ina219_handle_t gs_handle; /**< ina219 handle */ static char V_info[32]; static char I_info[32]; static char W_info[32]; while (1) { u8g2_ClearDisplay(&myDisplay); /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ sprintf(V_info,"电压:%.2fmV",mV); sprintf(I_info,"电流:%.2fmA",mA_ave); sprintf(W_info,"功率:%.2fmW",mW); u8g2_DrawUTF8(&myDisplay,0,16,"功率检测和显示"); u8g2_DrawUTF8(&myDisplay,0,32,V_info); u8g2_DrawUTF8(&myDisplay,0,48,I_info); u8g2_DrawUTF8(&myDisplay,0,64,W_info); u8g2_SendBuffer(&myDisplay); }
# 实际效果演示
选择一个路由器作为12负载,在连接后INA219采集到功率数据如下图所示。
配套的电机工作电压为3V,电机和其他部分连接如下。
读取到的功率信息如下所示。
# 总结
使用现有的libdriver驱动INA219,在使用时只需要实现不同MCU的通讯接口就可以使用函数库的功能,可以快速上手,对于初期开发是有参考价值的,后续可在此基础上进行驱动的优化。