/** ****************************************************************************** * @file power_meter.c * @author Motor Control SDK Team, Yuwell Software XiangenWang * @brief Voice Recognition Module Initialization Section, including peripheral initialization and message node insertion, etc. * @version 1.0 * @changelog version 1.0 初始版本 2026.1.6 ****************************************************************************** * @attention * *

© Copyright (c) 2025 Yuwell Software Danyang.Jiangsu.China. * All rights reserved.

* * Redistribution and use in source and binary forms, with or without * modification, are permitted, provided that the following conditions are met: * * 1. Redistribution of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. Neither the name of Yuwell Software nor the names of other * contributors to this software may be used to endorse or promote products * derived from this software without specific written permission. * 4. This software, including modifications and/or derivative works of this * software, must execute solely and exclusively on microcontroller or * microprocessor devices manufactured by or for Yuwell Software. * 5. Redistribution and use of this software other than as permitted under * this license is void and will automatically terminate your rights under * this license. * * THIS SOFTWARE IS PROVIDED BY Yuwell Software AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT * SHALL Yuwell Software OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************** */ /* USER CODE END Header */ #include "power_meter.h" // 提供给外部的采样结果数据 EleC_V_data elec_v_data; #if COULOMBMETER_SET_FUNC_ENABLE /** * @brief 向BL0942指定寄存器写入24位数据 * @param addr: 寄存器地址(8位) * @param reg_data: 待写入的数据缓冲区指针,需传入3个字节,低位在前、高位在后 * @retval 无 * @note 1. 数据格式:共24bit,不足位补0,低位先行发送 * 2. 通信协议:UART发送帧格式为[写命令(BL0942_ADDR_W)+寄存器地址+3字节数据+校验和] * 3. 校验和计算:(写命令+地址+3字节数据)的低8位取反 * 4. 数据发送大小限定为3个字节,超出部分无效 */ static void coulombmeter_write_reg(uint8_t addr, uint8_t* reg_data) { uint8_t check_sum = 0; // 1. 下发命令字节 BL0942_ADDR_W COULOMBMETER_UART_TRANS_BYTE(BL0942_ADDR_W); // 2. 下发需要写寄存器的地址 COULOMBMETER_UART_TRANS_BYTE(addr); // 3. 发送需要往寄存器地址写入的数据 COULOMBMETER_UART_TRANS_BYTE(reg_data[0]); COULOMBMETER_UART_TRANS_BYTE(reg_data[1]); COULOMBMETER_UART_TRANS_BYTE(reg_data[2]); // 4. 发送校验和 check_sum = (BL0942_ADDR_W + addr + reg_data[0] + reg_data[1] + reg_data[2]); check_sum = ~(check_sum & 0xFF); COULOMBMETER_UART_TRANS_BYTE(check_sum); } #endif /** * @brief 从BL0942指定寄存器读取数据 * @param addr: 寄存器地址(8位) * @retval 无 * @note 1. 通信协议:UART发送帧格式为[读命令(BL0942_ADDR_R)+寄存器地址] * 2. 芯片收到读命令后,会在150us内通过UART返回4字节数据(3字节有效数据+1字节校验) * 3. 建议1s执行一次该函数,返回数据在UART接收中断中处理 */ static void coulombmeter_read_reg(uint8_t addr) { // 1. 下发命令字节 BL0942_ADDR_R COULOMBMETER_UART_TRANS_BYTE(BL0942_ADDR_R); // 2. 下发地址数据 COULOMBMETER_UART_TRANS_BYTE(addr); } /** * @brief 初始化库仑计(UART5)相关硬件 * @param 无 * @retval 无 * @note 1. 初始化内容:UART TX/RX引脚、UART通信参数、接收中断 * 2. UART参数:9600波特率、8位数据位、1位停止位、无校验、全双工 * 3. 中断配置:UART5接收缓冲区满中断,优先级设为2 * 4. 初始化后清空全局数据结构体elec_v_data */ void User_PowerMeter_Init(void) { FL_GPIO_InitTypeDef GPIO_InitStruct; // 初始化GPIO GPIO_InitStruct.pin = COULOMBMETER_UART_RX_GPIO_PIN; GPIO_InitStruct.mode = FL_GPIO_MODE_DIGITAL; GPIO_InitStruct.outputType = FL_GPIO_OUTPUT_PUSHPULL; GPIO_InitStruct.pull = FL_DISABLE; GPIO_InitStruct.remapPin = FL_DISABLE; GPIO_InitStruct.analogSwitch = FL_DISABLE; FL_GPIO_Init(COULOMBMETER_UART_RX_GPIO_PORT, &GPIO_InitStruct); GPIO_InitStruct.pin = COULOMBMETER_UART_TX_GPIO_PIN; FL_GPIO_Init(COULOMBMETER_UART_TX_GPIO_PORT, &GPIO_InitStruct); // 初始化串口参数 FL_UART_InitTypeDef UART_InitStruct = {0}; UART_InitStruct.baudRate = 9600; //波特率 UART_InitStruct.dataWidth = FL_UART_DATA_WIDTH_8B; //数据位数 UART_InitStruct.stopBits = FL_UART_STOP_BIT_WIDTH_1B; //停止位 UART_InitStruct.parity = FL_UART_PARITY_NONE; //奇偶校验 UART_InitStruct.transferDirection = FL_UART_DIRECTION_TX_RX; //接收-发送使能 FL_UART_Init(COULOMBMETER_USED_UART_NUM, &UART_InitStruct); NVIC_DisableIRQ(COULOMBMETER_IRQn); NVIC_SetPriority(COULOMBMETER_IRQn,2); //中断优先级配置 NVIC_EnableIRQ(COULOMBMETER_IRQn); // 开启接收中断 FL_UART_ClearFlag_RXBuffFull(COULOMBMETER_USED_UART_NUM); FL_UART_EnableIT_RXBuffFull(COULOMBMETER_USED_UART_NUM); // 清空结果 memset(&elec_v_data, 0, sizeof(elec_v_data)); } /** * @brief 刷新库仑计的电压/电流数据(轮询读取) * @param 无 * @retval 无 * @note 1. 推荐1s调用一次该函数,交替读取电压和电流有效值 * 2. 首次调用读取电流寄存器(Addr_I_RMS),第二次读取电压寄存器(Addr_V_RMS),循环交替 * 3. 触发读取后,会设置对应的等待状态,数据接收和解析在UART中断中完成 * 4. 最终解析后的电压/电流值存储在全局变量elec_v_data中 */ void User_Coulombmeter_Data_refresh(void) { static Bus_Mod mod = MOD_CURRENT_METER; if(mod == MOD_VOLTAGE_METER) { mod = MOD_CURRENT_METER; coulombmeter_read_reg(Addr_V_RMS); elec_v_data.bus_com_stm = BUS_COM_STATE_WAITE_VOLTAGE; // 转入等待电压数据状态 elec_v_data.current_index = 0; elec_v_data.voltage_raw = 0; }else{ mod = MOD_VOLTAGE_METER; coulombmeter_read_reg(Addr_I_RMS); elec_v_data.bus_com_stm = BUS_COM_STATE_WAITE_CURRENT; // 转入等待电压数据状态 elec_v_data.current_index = 0; elec_v_data.current_raw = 0; } } /** * @brief UART5中断服务函数(库仑计数据接收处理) * @param 无 * @retval 无 * @note 1. 仅处理接收缓冲区满中断(RXBuffFull) * 2. 根据当前通信状态(BUS_COM_STATE)分别处理电压/电流数据 * 3. 数据接收格式:3字节有效数据(低位在前)+1字节校验和 * 4. 校验和验证通过后,转换为实际电压(V)/电流(mA)值并更新全局变量 * 5. 接收中断标志通过读取RXBuff寄存器自动清除,需手动清除RXBuffFull标志 */ void UART5_IRQHandler(void) { // 接收中断处理 if(FL_UART_IsEnabledIT_RXBuffFull(COULOMBMETER_USED_UART_NUM) && FL_UART_IsActiveFlag_RXBuffFull(COULOMBMETER_USED_UART_NUM)) { if(elec_v_data.bus_com_stm == BUS_COM_STATE_WAITE_VOLTAGE) { //接收中断标志可通过读取rxreg寄存器清除 uint8_t tmp_data = 0; tmp_data = FL_UART_ReadRXBuff(COULOMBMETER_USED_UART_NUM); if(elec_v_data.current_index < 3) { elec_v_data.voltage_raw |= (tmp_data<<(elec_v_data.current_index*8)); } elec_v_data.voltage_array[elec_v_data.current_index++] = tmp_data; if(elec_v_data.current_index == 4) { uint8_t checkSum = ~((elec_v_data.voltage_array[0] + elec_v_data.voltage_array[1] + elec_v_data.voltage_array[2] + BL0942_ADDR_R + Addr_V_RMS)&0xFF); if(elec_v_data.voltage_array[3] == checkSum) { // 校验正确对数据进行赋值 elec_v_data.bus_com_stm = BUS_COM_STATE_IDLE; elec_v_data.bus_rms_voltage_V =elec_v_data.voltage_raw / Voltage_K; elec_v_data.voltage_raw = 0; elec_v_data.current_index = 0; } } }else if(elec_v_data.bus_com_stm == BUS_COM_STATE_WAITE_CURRENT) { uint8_t tmp_data = 0; tmp_data = FL_UART_ReadRXBuff(COULOMBMETER_USED_UART_NUM); if(elec_v_data.current_index < 3) { elec_v_data.current_raw |= (tmp_data<<(elec_v_data.current_index*8)); } elec_v_data.current_array[elec_v_data.current_index++] = tmp_data; if(elec_v_data.current_index == 4) { uint8_t checkSum = ~((elec_v_data.current_array[0] + elec_v_data.current_array[1] + elec_v_data.current_array[2] + BL0942_ADDR_R + Addr_I_RMS)&0xFF); if(elec_v_data.current_array[3] == checkSum) { // 校验正确对数据进行赋值 elec_v_data.bus_com_stm = BUS_COM_STATE_IDLE; elec_v_data.bus_rms_current_mA =elec_v_data.current_raw*100 / Current_K; elec_v_data.current_raw = 0; elec_v_data.current_index = 0; } } } FL_UART_ClearFlag_RXBuffFull(COULOMBMETER_USED_UART_NUM); } } /************************ (C) COPYRIGHT YUWELL *****END OF FILE****/