mirror of
https://github.com/No-Chicken/Power-Pico.git
synced 2026-04-03 13:02:36 +08:00
更换串口为USB
This commit is contained in:
@@ -22,7 +22,22 @@
|
||||
|
||||
/* USER CODE BEGIN 0 */
|
||||
|
||||
ADC_Packet adc_packet;
|
||||
#include "tim.h"
|
||||
#include "usb_device.h"
|
||||
#include "gate.h"
|
||||
|
||||
// DMA 双缓冲原始数据 [200行][5列]
|
||||
uint16_t adc_raw_buffer[ADC_TIMES * 2][ADC_CHANNELS];
|
||||
// USB 发送缓冲区 (Ping-Pong 双缓冲防止发送冲突)
|
||||
USB_ADC_Packet_t usb_packet_buffer[2];
|
||||
// 统计实例
|
||||
Data_Monitor_t g_data_monitor = {0};
|
||||
// 物理切换防抖计数器
|
||||
static uint8_t high_overload_cnt = 0;
|
||||
static uint8_t low_underload_cnt = 0;
|
||||
static uint8_t is_transition_next = 0; // 标记下一包是否为过渡数据
|
||||
// 用于监视数据更新的计数器
|
||||
static uint32_t monitor_chunk_counter = 0;
|
||||
|
||||
/* USER CODE END 0 */
|
||||
|
||||
@@ -201,4 +216,233 @@ void HAL_ADC_MspDeInit(ADC_HandleTypeDef* adcHandle)
|
||||
|
||||
/* USER CODE BEGIN 1 */
|
||||
|
||||
// 内部调用的数据更新函数,mV 和 10nA 累加
|
||||
static void Data_Monitor_Update(uint16_t vol_adc, uint16_t cur_adc, uint16_t ref_adc, uint8_t range)
|
||||
{
|
||||
// 1. 计算电压 (mV)
|
||||
// V = (ADC_Value / 4095) * 3.0V * (10k + 1k) / 1k
|
||||
// mV = ADC_Value * (3000.0 / 4095 * 11)
|
||||
float voltage_mv = (float)vol_adc * (3000.0f / 4095.0f * 11.0f);
|
||||
|
||||
// 2. 计算电流 (单位: 10nA)
|
||||
// I_uA = ADC_Value * SCALE_XXX
|
||||
// I_10nA = I_uA * 100
|
||||
uint64_t current_10na = 0;
|
||||
switch (range) {
|
||||
case LOW_CUR:
|
||||
current_10na = (uint64_t)((float)(cur_adc-ref_adc) * SCALE_LOW * 100.0f);
|
||||
break;
|
||||
case MID_CUR:
|
||||
current_10na = (uint64_t)((float)(cur_adc-ref_adc) * SCALE_MID * 100.0f);
|
||||
break;
|
||||
case HIGH_CUR:
|
||||
current_10na = (uint64_t)((float)(cur_adc-ref_adc) * SCALE_HIGH * 100.0f);
|
||||
break;
|
||||
}
|
||||
|
||||
// 3. 累加数据 (此函数在中断上下文中被调用,Data_Monitor_Get_Values会处理中断保护)
|
||||
g_data_monitor.sum_vol_mv += (uint64_t)voltage_mv;
|
||||
g_data_monitor.sum_cur_resolution_10na += current_10na;
|
||||
g_data_monitor.count++;
|
||||
}
|
||||
|
||||
// 内部调用的计算函数,计算平均值并重置累加器
|
||||
static void Data_Monitor_Calculate_Average(void)
|
||||
{
|
||||
// 关中断保护,确保在计算和重置期间 g_data_monitor 不被修改
|
||||
__disable_irq();
|
||||
|
||||
if (g_data_monitor.count > 0)
|
||||
{
|
||||
// 计算平均值并存储到结构体的新成员中
|
||||
g_data_monitor.avg_vol_v = (float)g_data_monitor.sum_vol_mv / g_data_monitor.count / 1000.0f;
|
||||
g_data_monitor.avg_cur_ua = (float)g_data_monitor.sum_cur_resolution_10na / g_data_monitor.count / 100.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 如果在此期间没有有效数据(例如,一直处于档位切换中)
|
||||
g_data_monitor.avg_vol_v = 0.0f;
|
||||
g_data_monitor.avg_cur_ua = 0.0f;
|
||||
}
|
||||
|
||||
// 重置累加器,为下一个计算周期做准备
|
||||
g_data_monitor.sum_vol_mv = 0;
|
||||
g_data_monitor.sum_cur_resolution_10na = 0;
|
||||
g_data_monitor.count = 0;
|
||||
|
||||
__enable_irq();
|
||||
}
|
||||
|
||||
// 外部调用的获取函数,单位 V 和 uA
|
||||
void Data_Monitor_Get_Values(float *out_vol_v, float *out_cur_ua)
|
||||
{
|
||||
// 直接返回已经计算好的平均值,无需关中断,因为读取 float 是原子操作
|
||||
*out_vol_v = g_data_monitor.avg_vol_v;
|
||||
*out_cur_ua = g_data_monitor.avg_cur_ua;
|
||||
}
|
||||
|
||||
// 外部调用的清除函数,重置所有统计数据
|
||||
void Data_Monitor_Clear(void)
|
||||
{
|
||||
__disable_irq();
|
||||
g_data_monitor.sum_vol_mv = 0;
|
||||
g_data_monitor.sum_cur_resolution_10na = 0;
|
||||
g_data_monitor.count = 0;
|
||||
g_data_monitor.avg_vol_v = 0.0f;
|
||||
g_data_monitor.avg_cur_ua = 0.0f;
|
||||
__enable_irq();
|
||||
}
|
||||
|
||||
// 处理 ADC 数据块的核心函数,负责数据选择、切换决策和USB发送
|
||||
static void Process_ADC_Chunk(uint16_t *chunk_ptr, uint8_t packet_idx)
|
||||
{
|
||||
USB_ADC_Packet_t *pkg = &usb_packet_buffer[packet_idx];
|
||||
|
||||
// 填充包头
|
||||
pkg->header[0] = PACKET_HEADER_0;
|
||||
pkg->header[1] = PACKET_HEADER_1;
|
||||
pkg->timestamp = GetMicrosecondCounter();
|
||||
pkg->data_count = ADC_TIMES;
|
||||
|
||||
// 获取当前物理档位
|
||||
uint8_t current_hw_range = Gate_get_status();
|
||||
uint8_t req_switch_range = current_hw_range; // 初始化请求切换的档位
|
||||
|
||||
// 如果上一包触发了切换,本包数据是在切换期间采集的“脏数据”,必须丢弃
|
||||
if (is_transition_next) {
|
||||
is_transition_next = 0; // 清除标志
|
||||
high_overload_cnt = 0; // 清除计数器,为下一次干净数据做准备
|
||||
low_underload_cnt = 0;
|
||||
// 直接返回,不处理也不发送任何数据
|
||||
return;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
// 遍历采样点
|
||||
for (i = 0; i < ADC_TIMES; i++)
|
||||
{
|
||||
uint16_t *sample_row = chunk_ptr + (i * ADC_CHANNELS);
|
||||
uint16_t raw_vol = sample_row[IDX_VOL];
|
||||
uint16_t raw_low = sample_row[IDX_LOW];
|
||||
uint16_t raw_mid = sample_row[IDX_MID];
|
||||
uint16_t raw_hig = sample_row[IDX_HIGH];
|
||||
uint16_t raw_ref = sample_row[IDX_REF];
|
||||
|
||||
// --- 基于当前物理档位,进行独立的切换决策 ---
|
||||
switch (current_hw_range)
|
||||
{
|
||||
case LOW_CUR:
|
||||
// 在LOW档,只关心raw_low是否过载
|
||||
if (abs(raw_low-raw_ref) >= THRESH_HIGH) {
|
||||
high_overload_cnt++;
|
||||
if (high_overload_cnt >= THRESH_TIMES) {
|
||||
req_switch_range = MID_CUR; // 请求升到MID档
|
||||
}
|
||||
} else {
|
||||
high_overload_cnt = 0;
|
||||
}
|
||||
// LOW档不存在欠载问题
|
||||
low_underload_cnt = 0;
|
||||
break;
|
||||
|
||||
case MID_CUR:
|
||||
// 在MID档,判断raw_mid是否过载或欠载
|
||||
if (abs(raw_mid-raw_ref) >= THRESH_HIGH) { // 过载
|
||||
high_overload_cnt++;
|
||||
if (high_overload_cnt >= THRESH_TIMES) {
|
||||
req_switch_range = HIGH_CUR; // 请求升到HIGH档
|
||||
}
|
||||
} else {
|
||||
high_overload_cnt = 0;
|
||||
}
|
||||
|
||||
if (abs(raw_mid-raw_ref) < THRESH_LOW) { // 欠载
|
||||
low_underload_cnt++;
|
||||
if (low_underload_cnt >= THRESH_TIMES) {
|
||||
req_switch_range = LOW_CUR; // 请求降到LOW档
|
||||
}
|
||||
} else {
|
||||
low_underload_cnt = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case HIGH_CUR:
|
||||
// 在HIGH档,只关心raw_hig是否欠载
|
||||
if (abs(raw_hig-raw_ref) < THRESH_LOW) { // 注意:这里用raw_hig判断
|
||||
low_underload_cnt++;
|
||||
if (low_underload_cnt >= THRESH_TIMES) {
|
||||
req_switch_range = MID_CUR; // 请求降到MID档
|
||||
}
|
||||
} else {
|
||||
low_underload_cnt = 0;
|
||||
}
|
||||
// HIGH档不存在过载问题
|
||||
high_overload_cnt = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
// 如果已经做出切换决定,立即跳出循环
|
||||
if (req_switch_range != current_hw_range) {
|
||||
break;
|
||||
}
|
||||
|
||||
// --- 数据选择与填充 ---
|
||||
// 根据采集本数据块时的硬件档位(current_hw_range)来选择有效的电流ADC值
|
||||
uint16_t final_cur = 0;
|
||||
switch (current_hw_range) {
|
||||
case LOW_CUR: final_cur = raw_low; break;
|
||||
case MID_CUR: final_cur = raw_mid; break;
|
||||
case HIGH_CUR: final_cur = raw_hig; break;
|
||||
}
|
||||
|
||||
// 填充USB数据包的当前采样点
|
||||
pkg->samples[i].range = current_hw_range;
|
||||
pkg->samples[i].vol_adc = raw_vol;
|
||||
pkg->samples[i].cur_adc = final_cur;
|
||||
pkg->samples[i].ref_adc = raw_ref;
|
||||
|
||||
// 更新用于屏幕显示的统计数据
|
||||
Data_Monitor_Update(raw_vol, final_cur, raw_ref, current_hw_range);
|
||||
}
|
||||
|
||||
// 更新包中实际有效的数据点数量
|
||||
pkg->data_count = i;
|
||||
|
||||
// --- 循环结束后,执行物理切换 ---
|
||||
if (req_switch_range != current_hw_range)
|
||||
{
|
||||
flow_route_selection(req_switch_range); // 执行物理切换
|
||||
is_transition_next = 1; // 标记下一包是过渡数据
|
||||
high_overload_cnt = 0; // 切换后清零计数器
|
||||
low_underload_cnt = 0;
|
||||
}
|
||||
|
||||
// USB 发送 (非阻塞)
|
||||
CDC_Transmit_FS((uint8_t*)pkg, sizeof(USB_ADC_Packet_t));
|
||||
|
||||
//
|
||||
monitor_chunk_counter++;
|
||||
if (monitor_chunk_counter >= MONITOR_UPDATE_CHUNK_COUNT)
|
||||
{
|
||||
monitor_chunk_counter = 0; // 重置计数器
|
||||
Data_Monitor_Calculate_Average(); // 执行计算
|
||||
}
|
||||
}
|
||||
|
||||
/* --- DMA 回调函数 --- */
|
||||
|
||||
void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef* hadc)
|
||||
{
|
||||
// 处理前半段 (Buffer 行 0 ~ 99)
|
||||
// 传入 &adc_raw_buffer[0][0]
|
||||
Process_ADC_Chunk(&adc_raw_buffer[0][0], 0);
|
||||
}
|
||||
|
||||
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
|
||||
{
|
||||
// 处理后半段 (Buffer 行 100 ~ 199)
|
||||
// 传入 &adc_raw_buffer[ADC_TIMES][0]
|
||||
Process_ADC_Chunk(&adc_raw_buffer[ADC_TIMES][0], 1);
|
||||
}
|
||||
|
||||
/* USER CODE END 1 */
|
||||
|
||||
Reference in New Issue
Block a user