/**
******************************************************************************
* @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****/