STM32H750多通道数据采集系统

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"

总结

  1. 16通道同步ADC采样

    • 使用ADC1+ADC2双重模式
    • DMA双缓冲技术
    • 硬件触发确保同步性
  2. 程控放大器控制

    • SPI接口控制PGA281
    • 8级可编程增益(1-200)
    • 每通道独立增益设置
  3. 数字信号处理

    • FIR低通滤波器
    • IIR带通滤波器
    • 实时统计计算
  4. FFT频谱分析

    • CMSIS-DSP库加速
    • 2048点FFT
    • 多通道并行处理
  5. 数据压缩

    • LZ4快速压缩
    • RLE和差分编码
    • 实时压缩比监控
  6. USB高速传输

    • USB2.0高速接口
    • 自定义二进制协议
    • 批量传输模式
  7. SDRAM大数据缓存

    • 32MB外部SDRAM
    • DMA直接访问
    • 环形缓冲区管理
相关推荐
S火星人S2 小时前
LVGL[display]
单片机·学习
龙大大L3 小时前
第七章、7.1 ESP32 触摸传感器超详细教程(Arduino 环境)实战指南
单片机·嵌入式硬件·esp32
小渔村的拉线工4 小时前
18.SPI通信的原理及相关知识
单片机·嵌入式硬件·spi通信·全双工通信·主从机通信
youcans_4 小时前
【动手学STM32G4】(13)STM32G431之 TIM+ADC
stm32·单片机·嵌入式硬件·定时器
兔子,你孩子掉了5 小时前
【gd32vf103 折腾】基于gcc+make的开发环境配置
单片机·硬件工程
小灰灰搞电子6 小时前
STM32、GD32 ppm协议解析源码分享
stm32·ppm协议
项目題供诗7 小时前
51单片机入门(二)
单片机·嵌入式硬件·51单片机
恶魔泡泡糖7 小时前
51单片机步进电机
单片机·嵌入式硬件·51单片机
tobias.b8 小时前
408真题解析-2010-12-计组-程序执行时间
单片机·嵌入式硬件·fpga开发·计算机考研·408真题解析