更换串口为USB

This commit is contained in:
不吃油炸鸡
2026-02-07 13:29:07 +08:00
parent d542bdec20
commit b3dc8fc67b
44 changed files with 13221 additions and 7516 deletions

View File

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

View File

@@ -62,6 +62,7 @@ const osThreadAttr_t defaultTask_attributes = {
void StartDefaultTask(void *argument);
extern void MX_USB_DEVICE_Init(void);
void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */
/* Hook prototypes */
@@ -128,6 +129,8 @@ void MX_FREERTOS_Init(void) {
/* USER CODE END Header_StartDefaultTask */
void StartDefaultTask(void *argument)
{
/* init code for USB_DEVICE */
MX_USB_DEVICE_Init();
/* USER CODE BEGIN StartDefaultTask */
/* Infinite loop */
for(;;)

View File

@@ -46,6 +46,7 @@ void MX_GPIO_Init(void)
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOH_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();

View File

@@ -24,7 +24,7 @@
#include "i2c.h"
#include "spi.h"
#include "tim.h"
#include "usart.h"
#include "usb_device.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
@@ -99,7 +99,6 @@ int main(void)
MX_ADC1_Init();
MX_TIM1_Init();
MX_TIM4_Init();
MX_USART6_UART_Init();
MX_SPI2_Init();
MX_I2C1_Init();
MX_TIM2_Init();
@@ -147,13 +146,12 @@ void SystemClock_Config(void)
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLM = 8;
RCC_OscInitStruct.PLL.PLLN = 100;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 25;
RCC_OscInitStruct.PLL.PLLN = 192;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 4;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)

View File

@@ -390,7 +390,6 @@ void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* tim_baseHandle)
/**
* @brief 更新并获取64位的总微秒数 (核心函数)
* @note 此函数应该被经常性调用, 以处理32位计数器的溢出并累加到64位变量中。
* 来处理32位计数器的溢出并累加到64位变量中。
*/
void UpdateMicrosecondCounter(void)
{

View File

@@ -1,179 +0,0 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file usart.c
* @brief This file provides code for the configuration
* of the USART instances.
******************************************************************************
* @attention
*
* Copyright (c) 2025 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "usart.h"
/* USER CODE BEGIN 0 */
#include "stdio.h"
// memeory for receive string
uint8_t uart_receive_buf[USART_RX_BUFFER_SIZE + 1];
uint8_t uart_receive_flag = 0; // flag for receive complete
/* USER CODE END 0 */
UART_HandleTypeDef huart6;
DMA_HandleTypeDef hdma_usart6_rx;
DMA_HandleTypeDef hdma_usart6_tx;
/* USART6 init function */
void MX_USART6_UART_Init(void)
{
/* USER CODE BEGIN USART6_Init 0 */
/* USER CODE END USART6_Init 0 */
/* USER CODE BEGIN USART6_Init 1 */
/* USER CODE END USART6_Init 1 */
huart6.Instance = USART6;
huart6.Init.BaudRate = 1500000;
huart6.Init.WordLength = UART_WORDLENGTH_8B;
huart6.Init.StopBits = UART_STOPBITS_1;
huart6.Init.Parity = UART_PARITY_NONE;
huart6.Init.Mode = UART_MODE_TX_RX;
huart6.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart6.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart6) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN USART6_Init 2 */
/* USER CODE END USART6_Init 2 */
}
void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(uartHandle->Instance==USART6)
{
/* USER CODE BEGIN USART6_MspInit 0 */
/* USER CODE END USART6_MspInit 0 */
/* USART6 clock enable */
__HAL_RCC_USART6_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/**USART6 GPIO Configuration
PA11 ------> USART6_TX
PA12 ------> USART6_RX
*/
GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF8_USART6;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* USART6 DMA Init */
/* USART6_RX Init */
hdma_usart6_rx.Instance = DMA2_Stream1;
hdma_usart6_rx.Init.Channel = DMA_CHANNEL_5;
hdma_usart6_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_usart6_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_usart6_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_usart6_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_usart6_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_usart6_rx.Init.Mode = DMA_NORMAL;
hdma_usart6_rx.Init.Priority = DMA_PRIORITY_LOW;
hdma_usart6_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
if (HAL_DMA_Init(&hdma_usart6_rx) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(uartHandle,hdmarx,hdma_usart6_rx);
/* USART6_TX Init */
hdma_usart6_tx.Instance = DMA2_Stream6;
hdma_usart6_tx.Init.Channel = DMA_CHANNEL_5;
hdma_usart6_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_usart6_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_usart6_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_usart6_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_usart6_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_usart6_tx.Init.Mode = DMA_NORMAL;
hdma_usart6_tx.Init.Priority = DMA_PRIORITY_LOW;
hdma_usart6_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
if (HAL_DMA_Init(&hdma_usart6_tx) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(uartHandle,hdmatx,hdma_usart6_tx);
/* USART6 interrupt Init */
HAL_NVIC_SetPriority(USART6_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(USART6_IRQn);
/* USER CODE BEGIN USART6_MspInit 1 */
/* USER CODE END USART6_MspInit 1 */
}
}
void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle)
{
if(uartHandle->Instance==USART6)
{
/* USER CODE BEGIN USART6_MspDeInit 0 */
/* USER CODE END USART6_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_USART6_CLK_DISABLE();
/**USART6 GPIO Configuration
PA11 ------> USART6_TX
PA12 ------> USART6_RX
*/
HAL_GPIO_DeInit(GPIOA, GPIO_PIN_11|GPIO_PIN_12);
/* USART6 DMA DeInit */
HAL_DMA_DeInit(uartHandle->hdmarx);
HAL_DMA_DeInit(uartHandle->hdmatx);
/* USART6 interrupt Deinit */
HAL_NVIC_DisableIRQ(USART6_IRQn);
/* USER CODE BEGIN USART6_MspDeInit 1 */
/* USER CODE END USART6_MspDeInit 1 */
}
}
/* USER CODE BEGIN 1 */
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart6, (uint8_t *)&ch, 1, 0xffff);
return ch;
}
//串口6发送
void UART6_TX_Send(uint8_t *buffer, uint16_t length)
{
HAL_UART_Transmit(&huart6, buffer, length, 1);
}
/* USER CODE END 1 */