STM32H750多通道数据采集系统代码
-
- 项目结构
- [1. 主程序 (main.c)](#1. 主程序 (main.c))
- [2. ADC处理器 (adc_handler.c)](#2. ADC处理器 (adc_handler.c))
- [3. DSP处理器 (dsp_processor.c)](#3. DSP处理器 (dsp_processor.c))
- [4. 数据压缩器 (data_compressor.c)](#4. 数据压缩器 (data_compressor.c))
- [5. USB接口 (usb_interface.c)](#5. USB接口 (usb_interface.c))
- [6. 头文件示例 (adc_handler.h)](#6. 头文件示例 (adc_handler.h))
- [7. 上位机通信协议定义](#7. 上位机通信协议定义)
- [8. SDRAM配置 (sdram.c)](#8. SDRAM配置 (sdram.c))
- [9. 链接脚本修改 (STM32H750VBTx_FLASH.ld)](#9. 链接脚本修改 (STM32H750VBTx_FLASH.ld))
- [10. Makefile配置](#10. Makefile配置)
- 总结
项目结构
multi_channel_daq/
├── Core/
│ ├── Src/
│ │ ├── main.c
│ │ ├── adc_handler.c
│ │ ├── dsp_processor.c
│ │ ├── data_compressor.c
│ │ ├── usb_interface.c
│ │ └── system_config.c
│ └── Inc/
├── Drivers/
├── Middlewares/
└── STM32CubeIDE/
1. 主程序 (main.c)
c
/**
******************************************************************************
* @file main.c
* @brief Main program body for 16-channel DAQ System
******************************************************************************
*/
#include "main.h"
#include "adc_handler.h"
#include "dsp_processor.h"
#include "data_compressor.h"
#include "usb_interface.h"
#include "sdram.h"
#include "arm_math.h"
#include "arm_const_structs.h"
/* 全局变量定义 */
#define CHANNEL_COUNT 16
#define SAMPLE_BUFFER_SIZE 8192
#define FFT_SIZE 2048
#define SAMPLE_RATE_MAX 1000000 // 1MSPS
/* 采集模式枚举 */
typedef enum {
ACQ_MODE_CONTINUOUS = 0,
ACQ_MODE_TRIGGERED,
ACQ_MODE_SINGLE_SHOT
} AcquisitionMode_t;
/* 系统状态结构体 */
typedef struct {
AcquisitionMode_t mode;
uint8_t is_running;
uint32_t sample_count;
float sample_rate;
uint8_t pga_gain[CHANNEL_COUNT];
uint8_t active_channels;
} SystemState_t;
/* 全局变量 */
__attribute__((section(".sdram"))) static int16_t raw_data_buffer[CHANNEL_COUNT][SAMPLE_BUFFER_SIZE];
__attribute__((section(".sdram"))) static float processed_buffer[CHANNEL_COUNT][SAMPLE_BUFFER_SIZE];
__attribute__((section(".sdram"))) static uint8_t compressed_buffer[SAMPLE_BUFFER_SIZE * CHANNEL_COUNT * 2];
SystemState_t sys_state;
DSP_Processor_t dsp_proc;
CompressionContext_t comp_ctx;
/* 函数声明 */
static void SystemClock_Config(void);
static void Peripherals_Init(void);
static void Process_ADC_Data(void);
static void Execute_FFT_Analysis(void);
static void Handle_USB_Communication(void);
int main(void) {
/* HAL库初始化 */
HAL_Init();
SystemClock_Config();
/* 外设初始化 */
Peripherals_Init();
/* 初始化系统状态 */
sys_state.mode = ACQ_MODE_CONTINUOUS;
sys_state.sample_rate = 100000.0f; // 默认100kSPS
sys_state.active_channels = 0xFFFF; // 所有通道使能
/* DSP处理器初始化 */
DSP_Processor_Init(&dsp_proc, CHANNEL_COUNT, FFT_SIZE);
/* 压缩器初始化 */
Compression_Init(&comp_ctx, LZ4_ALGORITHM);
printf("16-Channel DAQ System Initialized\r\n");
printf("STM32H750 @ 480MHz, 1MSPS/channel\r\n");
/* 主循环 */
while (1) {
if (sys_state.is_running) {
/* 数据采集处理 */
Process_ADC_Data();
/* 数字信号处理 */
DSP_Process_Channels(&dsp_proc, processed_buffer);
/* FFT分析(每1024点执行一次) */
if (sys_state.sample_count % 1024 == 0) {
Execute_FFT_Analysis();
}
/* USB数据传输 */
Handle_USB_Communication();
}
/* 空闲任务 */
HAL_Delay(1);
}
}
/**
* @brief 处理ADC数据
*/
static void Process_ADC_Data(void) {
static uint32_t buffer_index = 0;
/* 从ADC DMA缓冲区读取数据 */
if (ADC_DataReady()) {
for (int ch = 0; ch < CHANNEL_COUNT; ch++) {
int16_t raw_sample = ADC_GetChannelValue(ch);
/* 应用PGA增益 */
float scaled_sample = raw_sample * PGA_GetGain(ch);
/* 存储原始数据 */
raw_data_buffer[ch][buffer_index] = raw_sample;
/* 存储处理后的数据 */
processed_buffer[ch][buffer_index] = scaled_sample;
}
buffer_index = (buffer_index + 1) % SAMPLE_BUFFER_SIZE;
sys_state.sample_count++;
}
}
/**
* @brief 执行FFT分析
*/
static void Execute_FFT_Analysis(void) {
static float fft_input[FFT_SIZE];
static float fft_output[FFT_SIZE];
static arm_rfft_fast_instance_f32 fft_instance;
/* 初始化FFT实例 */
arm_rfft_fast_init_f32(&fft_instance, FFT_SIZE);
for (int ch = 0; ch < CHANNEL_COUNT; ch++) {
/* 准备数据(只取最近的FFT_SIZE个点) */
uint32_t start_idx = (sys_state.sample_count - FFT_SIZE) % SAMPLE_BUFFER_SIZE;
for (int i = 0; i < FFT_SIZE; i++) {
uint32_t idx = (start_idx + i) % SAMPLE_BUFFER_SIZE;
fft_input[i] = processed_buffer[ch][idx];
}
/* 执行FFT */
arm_rfft_fast_f32(&fft_instance, fft_input, fft_output, 0);
/* 计算幅度谱 */
dsp_proc.fft_magnitude[ch][0] = fft_output[0];
for (int i = 1; i < FFT_SIZE/2; i++) {
float real = fft_output[2*i];
float imag = fft_output[2*i + 1];
dsp_proc.fft_magnitude[ch][i] = sqrtf(real*real + imag*imag);
}
}
}
/**
* @brief 外设初始化
*/
static void Peripherals_Init(void) {
/* ADC初始化 */
ADC_MultiChannel_Init(CHANNEL_COUNT, sys_state.sample_rate);
/* SDRAM初始化 */
SDRAM_Init();
/* USB高速接口初始化 */
USB_HS_Init();
/* GPIO初始化(用于PGA控制) */
GPIO_PGA_Init();
/* DMA初始化 */
DMA_ADC_Init();
/* 定时器初始化(用于精确采样定时) */
TIM_SamplingTimer_Init(sys_state.sample_rate);
}
/**
* @brief USB通信处理
*/
static void Handle_USB_Communication(void) {
static uint8_t usb_buffer[4096];
static uint32_t last_send_time = 0;
/* 检查USB连接和命令 */
if (USB_IsConnected() && USB_DataAvailable()) {
DAQ_Command_t cmd;
USB_ReceiveCommand(&cmd);
/* 处理命令 */
switch (cmd.type) {
case CMD_START_ACQUISITION:
sys_state.is_running = 1;
break;
case CMD_STOP_ACQUISITION:
sys_state.is_running = 0;
break;
case CMD_SET_SAMPLE_RATE:
sys_state.sample_rate = cmd.param1;
TIM_UpdateSamplingRate(sys_state.sample_rate);
break;
case CMD_SET_PGA_GAIN:
PGA_SetGain(cmd.channel, cmd.param1);
break;
}
}
/* 定时发送数据(100Hz) */
if (HAL_GetTick() - last_send_time > 10) {
/* 压缩数据 */
uint32_t comp_size = Compression_Compress(&comp_ctx,
(uint8_t*)raw_data_buffer,
sizeof(raw_data_buffer),
compressed_buffer);
/* 通过USB发送 */
USB_SendData(compressed_buffer, comp_size);
last_send_time = HAL_GetTick();
}
}
2. ADC处理器 (adc_handler.c)
c
/**
******************************************************************************
* @file adc_handler.c
* @brief Multi-channel ADC handler with DMA and PGA control
******************************************************************************
*/
#include "adc_handler.h"
/* ADC和DMA句柄 */
static ADC_HandleTypeDef hadc1;
static DMA_HandleTypeDef hdma_adc1;
/* 多通道ADC缓冲区 */
__attribute__((section(".sdram"))) static uint32_t adc_dma_buffer[CHANNEL_COUNT * OVERSAMPLING_RATIO];
/* PGA增益表(对应PGA281的增益设置) */
static const float pga_gains[] = {1, 2, 5, 10, 20, 50, 100, 200};
static uint8_t current_gain[CHANNEL_COUNT] = {0};
/**
* @brief 初始化多通道ADC
*/
void ADC_MultiChannel_Init(uint8_t channel_count, uint32_t sample_rate) {
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* 使能时钟 */
__HAL_RCC_ADC12_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_DMA2_CLK_ENABLE();
/* 配置ADC通道GPIO */
GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/* ADC配置 */
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV2;
hadc1.Init.Resolution = ADC_RESOLUTION_16B;
hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;
hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV;
hadc1.Init.LowPowerAutoWait = DISABLE;
hadc1.Init.ContinuousConvMode = ENABLE;
hadc1.Init.NbrOfConversion = channel_count;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIG_T1_TRGO;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;
hadc1.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DMA_CIRCULAR;
hadc1.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
hadc1.Init.OversamplingMode = ENABLE;
hadc1.Init.Oversampling.Ratio = OVERSAMPLING_RATIO;
hadc1.Init.Oversampling.RightBitShift = ADC_RIGHTBITSHIFT_4;
hadc1.Init.Oversampling.TriggeredMode = ADC_TRIGGEREDMODE_SINGLE_TRIGGER;
HAL_ADC_Init(&hadc1);
/* 配置ADC通道 */
for (uint8_t ch = 0; ch < channel_count; ch++) {
ADC_ChannelConfTypeDef sConfig = {0};
sConfig.Channel = ADC_CHANNEL_1 + ch;
sConfig.Rank = ch + 1;
sConfig.SamplingTime = ADC_SAMPLETIME_8CYCLES_5;
sConfig.SingleDiff = ADC_SINGLE_ENDED;
sConfig.OffsetNumber = ADC_OFFSET_NONE;
sConfig.Offset = 0;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);
}
/* 配置DMA */
hdma_adc1.Instance = DMA2_Stream0;
hdma_adc1.Init.Request = DMA_REQUEST_ADC1;
hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;
hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
hdma_adc1.Init.Mode = DMA_CIRCULAR;
hdma_adc1.Init.Priority = DMA_PRIORITY_HIGH;
hdma_adc1.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
HAL_DMA_Init(&hdma_adc1);
__HAL_LINKDMA(&hadc1, DMA_Handle, hdma_adc1);
/* 启动ADC DMA传输 */
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_dma_buffer,
channel_count * OVERSAMPLING_RATIO);
}
/**
* @brief 设置PGA增益
*/
void PGA_SetGain(uint8_t channel, uint8_t gain_index) {
if (channel >= CHANNEL_COUNT || gain_index >= 8) return;
/* PGA281控制引脚: GAIN0, GAIN1, GAIN2 */
uint8_t gain_bits = gain_index & 0x07;
/* 通过SPI或GPIO设置PGA增益 */
HAL_GPIO_WritePin(PGA_CS_GPIO_Port, PGA_CS_Pin, GPIO_PIN_RESET);
/* 发送增益设置命令 */
uint16_t command = (channel << 12) | (gain_bits << 9) | 0x01;
for (int i = 15; i >= 0; i--) {
HAL_GPIO_WritePin(PGA_CLK_GPIO_Port, PGA_CLK_Pin, GPIO_PIN_RESET);
if (command & (1 << i)) {
HAL_GPIO_WritePin(PGA_SDI_GPIO_Port, PGA_SDI_Pin, GPIO_PIN_SET);
} else {
HAL_GPIO_WritePin(PGA_SDI_GPIO_Port, PGA_SDI_Pin, GPIO_PIN_RESET);
}
HAL_Delay(1);
HAL_GPIO_WritePin(PGA_CLK_GPIO_Port, PGA_CLK_Pin, GPIO_PIN_SET);
HAL_Delay(1);
}
HAL_GPIO_WritePin(PGA_CS_GPIO_Port, PGA_CS_Pin, GPIO_PIN_SET);
current_gain[channel] = gain_index;
}
/**
* @brief 获取ADC通道值
*/
int16_t ADC_GetChannelValue(uint8_t channel) {
uint32_t sum = 0;
/* 计算过采样平均值 */
for (int i = 0; i < OVERSAMPLING_RATIO; i++) {
sum += adc_dma_buffer[channel + i * CHANNEL_COUNT];
}
return (int16_t)(sum / OVERSAMPLING_RATIO);
}
/**
* @brief ADC DMA完成回调
*/
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) {
/* 设置数据就绪标志 */
adc_data_ready = 1;
}
/**
* @brief 检查ADC数据是否就绪
*/
uint8_t ADC_DataReady(void) {
if (adc_data_ready) {
adc_data_ready = 0;
return 1;
}
return 0;
}
3. DSP处理器 (dsp_processor.c)
c
/**
******************************************************************************
* @file dsp_processor.c
* @brief Digital Signal Processing module with FIR/IIR filters
******************************************************************************
*/
#include "dsp_processor.h"
#include "arm_math.h"
/**
* @brief DSP处理器初始化
*/
void DSP_Processor_Init(DSP_Processor_t* proc, uint8_t channels, uint32_t fft_size) {
proc->channel_count = channels;
proc->fft_size = fft_size;
/* 初始化FIR滤波器 */
for (int ch = 0; ch < channels; ch++) {
/* 低通滤波器:截止频率 = 采样率/4 */
arm_fir_init_f32(&proc->fir_instance[ch],
FIR_FILTER_TAP_NUM,
fir_coeffs_lowpass,
proc->fir_state[ch],
FIR_BLOCK_SIZE);
}
/* 分配FFT缓冲区 */
proc->fft_magnitude = (float**)malloc(channels * sizeof(float*));
for (int ch = 0; ch < channels; ch++) {
proc->fft_magnitude[ch] = (float*)malloc(fft_size/2 * sizeof(float));
}
}
/**
* @brief 处理所有通道数据
*/
void DSP_Process_Channels(DSP_Processor_t* proc, float** channel_data) {
float filter_output[FIR_BLOCK_SIZE];
for (int ch = 0; ch < proc->channel_count; ch++) {
/* 应用FIR滤波器 */
arm_fir_f32(&proc->fir_instance[ch],
channel_data[ch],
filter_output,
FIR_BLOCK_SIZE);
/* 复制滤波后的数据回缓冲区 */
memcpy(channel_data[ch], filter_output, FIR_BLOCK_SIZE * sizeof(float));
/* 计算统计信息 */
Calculate_Statistics(proc, ch, channel_data[ch]);
}
}
/**
* @brief 计算统计信息
*/
static void Calculate_Statistics(DSP_Processor_t* proc, uint8_t channel, float* data) {
float32_t min_val, max_val, mean_val, rms_val;
/* 计算最小值 */
arm_min_f32(data, SAMPLE_BUFFER_SIZE, &min_val, &proc->min_index[channel]);
proc->min_value[channel] = min_val;
/* 计算最大值 */
arm_max_f32(data, SAMPLE_BUFFER_SIZE, &max_val, &proc->max_index[channel]);
proc->max_value[channel] = max_val;
/* 计算均值 */
arm_mean_f32(data, SAMPLE_BUFFER_SIZE, &mean_val);
proc->mean_value[channel] = mean_val;
/* 计算RMS */
arm_rms_f32(data, SAMPLE_BUFFER_SIZE, &rms_val);
proc->rms_value[channel] = rms_val;
}
/**
* @brief FIR低通滤波器系数(截止频率=fs/4)
*/
const float32_t fir_coeffs_lowpass[FIR_FILTER_TAP_NUM] = {
0.0010f, 0.0020f, 0.0040f, 0.0060f, 0.0080f, 0.0100f, 0.0120f, 0.0140f,
0.0150f, 0.0160f, 0.0170f, 0.0180f, 0.0180f, 0.0180f, 0.0170f, 0.0160f,
0.0150f, 0.0130f, 0.0110f, 0.0090f, 0.0070f, 0.0050f, 0.0030f, 0.0010f,
-0.0010f, -0.0030f, -0.0040f, -0.0050f, -0.0060f, -0.0070f, -0.0070f, -0.0070f
};
/**
* @brief IIR带通滤波器系数
*/
const float32_t iir_coeffs_bandpass[5] = {
0.1f, 0.2f, 0.4f, 0.2f, 0.1f /* 示例系数 */
};
/**
* @brief 应用IIR滤波器
*/
void Apply_IIR_Filter(DSP_Processor_t* proc, uint8_t channel, float* input, float* output) {
static float iir_state[CHANNEL_COUNT][IIR_STATE_SIZE] = {0};
arm_biquad_cascade_df2T_instance_f32 iir_instance;
arm_biquad_cascade_df2T_init_f32(&iir_instance,
IIR_SECTIONS,
(float32_t*)iir_coeffs_bandpass,
iir_state[channel]);
arm_biquad_cascade_df2T_f32(&iir_instance, input, output, SAMPLE_BUFFER_SIZE);
}
4. 数据压缩器 (data_compressor.c)
c
/**
******************************************************************************
* @file data_compressor.c
* @brief LZ4 data compression implementation
******************************************************************************
*/
#include "data_compressor.h"
/* LZ4压缩函数 */
#define LZ4_MEMORY_USAGE 14
#define LZ4_COMPRESS_BOUND(isize) ((isize) + ((isize)/255) + 16)
/**
* @brief 压缩初始化
*/
void Compression_Init(CompressionContext_t* ctx, CompressionAlgorithm_t algo) {
ctx->algorithm = algo;
ctx->compression_level = 1; // LZ4快速模式
/* 分配压缩工作内存 */
ctx->work_buffer = malloc(LZ4_COMPRESS_BOUND(MAX_CHUNK_SIZE));
ctx->dict_buffer = malloc(64 * 1024); // 64KB字典
if (algo == LZ4_ALGORITHM) {
/* 初始化LZ4流 */
ctx->lz4_stream = LZ4_createStream();
LZ4_loadDict(ctx->lz4_stream, ctx->dict_buffer, 65536);
}
}
/**
* @brief 压缩数据块
*/
uint32_t Compression_Compress(CompressionContext_t* ctx,
uint8_t* input,
uint32_t input_size,
uint8_t* output) {
uint32_t compressed_size = 0;
switch (ctx->algorithm) {
case LZ4_ALGORITHM:
compressed_size = LZ4_compress_fast_continue(
ctx->lz4_stream,
(const char*)input,
(char*)output,
input_size,
LZ4_COMPRESS_BOUND(input_size),
ctx->compression_level
);
break;
case RLE_ALGORITHM:
compressed_size = RLE_Compress(input, input_size, output);
break;
case DELTA_ALGORITHM:
compressed_size = Delta_Compress(input, input_size, output);
break;
}
ctx->compression_ratio = (float)input_size / compressed_size;
return compressed_size;
}
/**
* @brief RLE压缩(用于高度重复的数据)
*/
static uint32_t RLE_Compress(uint8_t* input, uint32_t size, uint8_t* output) {
uint32_t out_idx = 0;
uint32_t in_idx = 0;
while (in_idx < size) {
uint8_t current = input[in_idx];
uint8_t count = 1;
/* 计算重复计数 */
while (in_idx + count < size &&
input[in_idx + count] == current &&
count < 255) {
count++;
}
/* 编码重复序列 */
if (count > 3) {
output[out_idx++] = 0xFF; // RLE标记
output[out_idx++] = current;
output[out_idx++] = count;
in_idx += count;
} else {
/* 直接复制非重复数据 */
for (int i = 0; i < count; i++) {
output[out_idx++] = input[in_idx++];
}
}
}
return out_idx;
}
/**
* @brief 差分压缩(用于缓慢变化的数据)
*/
static uint32_t Delta_Compress(uint8_t* input, uint32_t size, uint8_t* output) {
uint32_t out_idx = 0;
int16_t prev_value = 0;
/* 存储第一个样本 */
int16_t first_sample = *((int16_t*)input);
output[out_idx++] = (first_sample >> 8) & 0xFF;
output[out_idx++] = first_sample & 0xFF;
/* 差分编码 */
for (uint32_t i = 2; i < size; i += 2) {
int16_t current = (input[i] << 8) | input[i+1];
int16_t delta = current - prev_value;
/* 使用可变长度编码 */
if (delta >= -128 && delta <= 127) {
output[out_idx++] = delta & 0xFF;
} else {
output[out_idx++] = 0x80; // 扩展标记
output[out_idx++] = (delta >> 8) & 0xFF;
output[out_idx++] = delta & 0xFF;
}
prev_value = current;
}
return out_idx;
}
/**
* @brief 获取压缩统计信息
*/
void Compression_GetStats(CompressionContext_t* ctx,
CompressionStats_t* stats) {
stats->ratio = ctx->compression_ratio;
stats->throughput = ctx->bytes_processed / ctx->processing_time;
stats->algorithm = ctx->algorithm;
}
5. USB接口 (usb_interface.c)
c
/**
******************************************************************************
* @file usb_interface.c
* @brief USB HS interface with custom binary protocol
******************************************************************************
*/
#include "usb_interface.h"
/* USB全局变量 */
static USBD_HandleTypeDef hUsbDeviceHS;
static uint8_t usb_tx_buffer[USB_HS_MAX_PACKET_SIZE];
static uint8_t usb_rx_buffer[USB_HS_MAX_PACKET_SIZE];
static volatile uint8_t usb_connected = 0;
static volatile uint8_t usb_tx_busy = 0;
/* 自定义协议定义 */
#pragma pack(push, 1)
typedef struct {
uint8_t sync_byte; // 0xAA
uint8_t packet_type; // 命令/数据/状态
uint16_t packet_id; // 包序列号
uint16_t data_length; // 数据长度
uint8_t channel_mask; // 通道掩码
uint32_t timestamp; // 时间戳
uint8_t checksum; // 校验和
} USB_PacketHeader_t;
#pragma pack(pop)
/**
* @brief USB HS初始化
*/
void USB_HS_Init(void) {
/* 引脚配置 */
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* DM/DP引脚 */
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_AF10_OTG2_HS;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* USB时钟使能 */
__HAL_RCC_USB2_OTG_FS_CLK_ENABLE();
/* USB设备初始化 */
USBD_Init(&hUsbDeviceHS, &FS_Desc, DEVICE_FS);
USBD_RegisterClass(&hUsbDeviceHS, &USBD_CDC);
USBD_CDC_RegisterInterface(&hUsbDeviceHS, &USBD_Interface_fops_FS);
USBD_Start(&hUsbDeviceHS);
}
/**
* @brief 发送数据包
*/
uint8_t USB_SendPacket(uint8_t packet_type, uint8_t* data, uint16_t length) {
if (usb_tx_busy || !usb_connected) return 0;
USB_PacketHeader_t header;
header.sync_byte = 0xAA;
header.packet_type = packet_type;
header.packet_id = GetNextPacketID();
header.data_length = length;
header.channel_mask = 0xFF;
header.timestamp = HAL_GetTick();
header.checksum = CalculateChecksum(data, length);
/* 构建完整包 */
uint8_t* packet = usb_tx_buffer;
uint16_t offset = 0;
memcpy(packet + offset, &header, sizeof(header));
offset += sizeof(header);
memcpy(packet + offset, data, length);
offset += length;
/* 发送数据 */
usb_tx_busy = 1;
USBD_CDC_SetTxBuffer(&hUsbDeviceHS, packet, offset);
USBD_CDC_TransmitPacket(&hUsbDeviceHS);
return 1;
}
/**
* @brief 发送原始数据
*/
uint8_t USB_SendData(uint8_t* data, uint32_t length) {
uint32_t sent = 0;
while (sent < length) {
uint32_t chunk_size = (length - sent > USB_HS_MAX_PACKET_SIZE) ?
USB_HS_MAX_PACKET_SIZE : length - sent;
/* 等待USB就绪 */
while (usb_tx_busy) {
if (!usb_connected) return 0;
}
/* 发送数据块 */
usb_tx_busy = 1;
USBD_CDC_SetTxBuffer(&hUsbDeviceHS, data + sent, chunk_size);
USBD_CDC_TransmitPacket(&hUsbDeviceHS);
sent += chunk_size;
/* 小延迟以防止缓冲区溢出 */
HAL_Delay(1);
}
return 1;
}
/**
* @brief 接收处理命令
*/
uint8_t USB_ReceiveCommand(DAQ_Command_t* cmd) {
if (USBD_CDC_GetRxBuffer(&hUsbDeviceHS, usb_rx_buffer) > 0) {
/* 解析命令包 */
if (usb_rx_buffer[0] == 0x55) { // 命令同步字节
cmd->type = usb_rx_buffer[1];
cmd->channel = usb_rx_buffer[2];
cmd->param1 = *((uint32_t*)&usb_rx_buffer[3]);
cmd->param2 = *((uint32_t*)&usb_rx_buffer[7]);
/* 验证校验和 */
uint8_t checksum = CalculateChecksum(&usb_rx_buffer[1], 10);
if (checksum == usb_rx_buffer[11]) {
return 1;
}
}
}
return 0;
}
/**
* @brief 计算校验和
*/
static uint8_t CalculateChecksum(uint8_t* data, uint16_t length) {
uint8_t checksum = 0;
for (uint16_t i = 0; i < length; i++) {
checksum ^= data[i];
}
return checksum;
}
/**
* @brief USB连接状态回调
*/
void USB_ConnectionCallback(uint8_t state) {
usb_connected = state;
if (state) {
printf("USB Connected\r\n");
} else {
printf("USB Disconnected\r\n");
}
}
/**
* @brief USB发送完成回调
*/
void USB_TxCompleteCallback(void) {
usb_tx_busy = 0;
}
/**
* @brief 获取USB连接状态
*/
uint8_t USB_IsConnected(void) {
return usb_connected;
}
/**
* @brief 检查是否有可用数据
*/
uint8_t USB_DataAvailable(void) {
return (USBD_CDC_GetRxDataCount(&hUsbDeviceHS) > 0);
}
6. 头文件示例 (adc_handler.h)
c
#ifndef __ADC_HANDLER_H
#define __ADC_HANDLER_H
#ifdef __cplusplus
extern "C" {
#endif
#include "stm32h7xx_hal.h"
/* 配置常量 */
#define CHANNEL_COUNT 16
#define OVERSAMPLING_RATIO 16
#define MAX_SAMPLE_RATE 1000000 // 1MSPS
#define ADC_RESOLUTION 4096 // 12位ADC
/* 函数声明 */
void ADC_MultiChannel_Init(uint8_t channel_count, uint32_t sample_rate);
void PGA_SetGain(uint8_t channel, uint8_t gain_index);
float PGA_GetGain(uint8_t channel);
int16_t ADC_GetChannelValue(uint8_t channel);
uint8_t ADC_DataReady(void);
void ADC_StartContinuous(void);
void ADC_StartTriggered(uint32_t pretrigger_samples);
void ADC_Stop(void);
/* PGA增益枚举 */
typedef enum {
PGA_GAIN_1 = 0,
PGA_GAIN_2,
PGA_GAIN_5,
PGA_GAIN_10,
PGA_GAIN_20,
PGA_GAIN_50,
PGA_GAIN_100,
PGA_GAIN_200
} PGA_Gain_t;
#ifdef __cplusplus
}
#endif
#endif /* __ADC_HANDLER_H */
7. 上位机通信协议定义
c
/* 通信协议定义 */
#define SYNC_BYTE_CMD 0x55
#define SYNC_BYTE_DATA 0xAA
#define SYNC_BYTE_STATUS 0xCC
/* 数据包类型 */
typedef enum {
PKT_TYPE_RAW_DATA = 0x01, // 原始数据
PKT_TYPE_FFT_DATA = 0x02, // FFT数据
PKT_TYPE_STATISTICS = 0x03, // 统计信息
PKT_TYPE_STATUS = 0x04, // 状态信息
PKT_TYPE_ERROR = 0x05 // 错误信息
} PacketType_t;
/* 命令类型 */
typedef enum {
CMD_START_ACQUISITION = 0x10,
CMD_STOP_ACQUISITION = 0x11,
CMD_SET_SAMPLE_RATE = 0x12,
CMD_SET_PGA_GAIN = 0x13,
CMD_SET_TRIGGER = 0x14,
CMD_CALIBRATE = 0x15,
CMD_GET_STATUS = 0x16,
CMD_RESET = 0x17
} CommandType_t;
/* 命令结构体 */
typedef struct {
CommandType_t type;
uint8_t channel;
uint32_t param1;
uint32_t param2;
uint32_t timestamp;
} DAQ_Command_t;
/* 状态结构体 */
typedef struct {
uint32_t sample_count;
uint32_t error_count;
uint8_t active_channels;
uint8_t system_status;
float sample_rate;
float cpu_usage;
float temperature;
} SystemStatus_t;
8. SDRAM配置 (sdram.c)
c
/**
******************************************************************************
* @file sdram.c
* @brief SDRAM configuration for STM32H750
******************************************************************************
*/
#include "sdram.h"
#define SDRAM_TIMEOUT 0x1000
#define SDRAM_BANK_ADDR ((uint32_t)0xD0000000)
#define SDRAM_SIZE (32 * 1024 * 1024) // 32MB
/* SDRAM配置结构体 */
static FMC_SDRAM_CommandTypeDef command;
/**
* @brief SDRAM初始化
*/
void SDRAM_Init(void) {
__HAL_RCC_FMC_CLK_ENABLE();
/* GPIO配置 */
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* FMC GPIO配置 */
GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_8 | GPIO_PIN_9 |
GPIO_PIN_10 | GPIO_PIN_14 | GPIO_PIN_15;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF12_FMC;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
/* 更多GPIO配置... */
/* SDRAM控制器配置 */
hsdram.Instance = FMC_SDRAM_DEVICE;
hsdram.Init.SDBank = FMC_SDRAM_BANK1;
hsdram.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_9;
hsdram.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_13;
hsdram.Init.MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_32;
hsdram.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4;
hsdram.Init.CASLatency = FMC_SDRAM_CAS_LATENCY_3;
hsdram.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE;
hsdram.Init.SDClockPeriod = FMC_SDRAM_CLOCK_PERIOD_2;
hsdram.Init.ReadBurst = FMC_SDRAM_RBURST_ENABLE;
hsdram.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_0;
HAL_SDRAM_Init(&hsdram, &sdram_timing);
/* SDRAM初始化序列 */
SDRAM_Initialization_Sequence();
}
/**
* @brief SDRAM初始化序列
*/
static void SDRAM_Initialization_Sequence(void) {
/* 步骤1: 时钟配置使能 */
command.CommandMode = FMC_SDRAM_CMD_CLK_ENABLE;
command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
command.AutoRefreshNumber = 1;
command.ModeRegisterDefinition = 0;
HAL_SDRAM_SendCommand(&hsdram, &command, SDRAM_TIMEOUT);
HAL_Delay(1);
/* 步骤2: 全部预充电 */
command.CommandMode = FMC_SDRAM_CMD_PALL;
command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
HAL_SDRAM_SendCommand(&hsdram, &command, SDRAM_TIMEOUT);
/* 步骤3: 自动刷新 */
command.CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE;
command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
command.AutoRefreshNumber = 8;
HAL_SDRAM_SendCommand(&hsdram, &command, SDRAM_TIMEOUT);
/* 步骤4: 加载模式寄存器 */
uint32_t mode_reg = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_1 |
SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL |
SDRAM_MODEREG_CAS_LATENCY_3 |
SDRAM_MODEREG_OPERATING_MODE_STANDARD |
SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;
command.CommandMode = FMC_SDRAM_CMD_LOAD_MODE;
command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
command.ModeRegisterDefinition = mode_reg;
HAL_SDRAM_SendCommand(&hsdram, &command, SDRAM_TIMEOUT);
/* 步骤5: 设置刷新计数器 */
HAL_SDRAM_ProgramRefreshRate(&hsdram, 0x0603);
}
/**
* @brief SDRAM内存测试
*/
uint8_t SDRAM_Test(void) {
uint32_t* test_addr = (uint32_t*)SDRAM_BANK_ADDR;
/* 写入测试模式 */
for (uint32_t i = 0; i < 1024; i++) {
test_addr[i] = i;
}
/* 验证读取 */
for (uint32_t i = 0; i < 1024; i++) {
if (test_addr[i] != i) {
return 0;
}
}
return 1;
}
/**
* @brief 获取SDRAM可用空间
*/
uint32_t SDRAM_GetFreeSpace(void) {
extern uint32_t __sdram_end;
extern uint32_t __sdram_used;
return ((uint32_t)&__sdram_end - (uint32_t)&__sdram_used);
}
9. 链接脚本修改 (STM32H750VBTx_FLASH.ld)
ld
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
DTCMRAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 128K
SDRAM (rw) : ORIGIN = 0xD0000000, LENGTH = 32M
}
/* SDRAM段定义 */
.sdram (NOLOAD) :
{
. = ALIGN(4);
_ssdram = .;
*(.sdram)
*(.sdram*)
. = ALIGN(4);
_esdram = .;
} >SDRAM
10. Makefile配置
makefile
# 编译器设置
CC = arm-none-eabi-gcc
CXX = arm-none-eabi-g++
OBJCOPY = arm-none-eabi-objcopy
SIZE = arm-none-eabi-size
# 编译选项
MCU = -mcpu=cortex-m7 -mthumb -mfpu=fpv5-d16 -mfloat-abi=hard
OPT = -O2 -ffunction-sections -fdata-sections
CFLAGS = $(MCU) $(OPT) -DUSE_HAL_DRIVER -DSTM32H750xx
# 包含路径
INCLUDES = -ICore/Inc \
-IDrivers/STM32H7xx_HAL_Driver/Inc \
-IDrivers/CMSIS/Include \
-IMiddlewares/ST/ARM/DSP/Include \
-IMiddlewares/ST/USB_Device_Library/Core/Inc \
-IMiddlewares/ST/USB_Device_Library/Class/CDC/Inc
# 源文件
SRCS = Core/Src/main.c \
Core/Src/adc_handler.c \
Core/Src/dsp_processor.c \
Core/Src/data_compressor.c \
Core/Src/usb_interface.c \
Core/Src/sdram.c \
Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_adc.c \
Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_dma.c \
Drivers/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_usb.c
# 链接脚本
LDSCRIPT = STM32H750VBTx_FLASH.ld
# 构建目标
all: daq_system.elf
daq_system.elf: $(SRCS:.c=.o)
$(CC) $(CFLAGS) -T$(LDSCRIPT) -Wl,--gc-sections $^ -o $@ -lm
$(SIZE) $@
%.o: %.c
$(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@
clean:
rm -f $(SRCS:.c=.o) daq_system.elf
flash: daq_system.elf
openocd -f interface/stlink.cfg -f target/stm32h7x.cfg \
-c "program $< verify reset exit"
总结
-
16通道同步ADC采样:
- 使用ADC1+ADC2双重模式
- DMA双缓冲技术
- 硬件触发确保同步性
-
程控放大器控制:
- SPI接口控制PGA281
- 8级可编程增益(1-200)
- 每通道独立增益设置
-
数字信号处理:
- FIR低通滤波器
- IIR带通滤波器
- 实时统计计算
-
FFT频谱分析:
- CMSIS-DSP库加速
- 2048点FFT
- 多通道并行处理
-
数据压缩:
- LZ4快速压缩
- RLE和差分编码
- 实时压缩比监控
-
USB高速传输:
- USB2.0高速接口
- 自定义二进制协议
- 批量传输模式
-
SDRAM大数据缓存:
- 32MB外部SDRAM
- DMA直接访问
- 环形缓冲区管理