一、系统概述
以STM32F407ZGT6(Cortex-M4,168MHz,带FPU)为主控,结合TFTLCD触摸屏与高速ADC,实现一款低成本、便携式的数字示波器。核心功能包括:
-
信号采集:通过ADC采集模拟信号(0~3.3V,最高采样率1MHz),支持单通道输入;
-
波形显示:在TFTLCD上实时显示波形(时域),支持网格、刻度、参数叠加;
-
参数测量:自动计算电压峰峰值(Vpp)、频率(f)、占空比(Duty);
-
用户交互:触摸控制(采样率、垂直灵敏度、触发方式),按键控制(启动/停止)。
应用场景:电子电路调试、传感器信号监测、教学实验等。
二、硬件设计
2.1 核心组件选型
| 模块 | 型号/参数 | 功能说明 |
|---|---|---|
| 主控 | STM32F407ZGT6(1MB Flash,192KB RAM) | ADC采集、数据处理、TFTLCD驱动、触摸控制 |
| TFTLCD | 3.5寸ILI9488(320×480,16位色) | 显示波形、参数、菜单(8080并行接口,FSMC驱动) |
| ADC | STM32内置12位ADC(3个ADC,16通道) | 采集模拟信号(单通道,DMA传输) |
| 信号调理 | 程控增益放大器(PGA205,增益1/10/100) | 适配不同幅度信号(0.1V~10V),低通滤波(截止频率100kHz) |
| 触发电路 | 电压比较器(LM311)+ 施密特触发器 | 边沿触发(上升沿/下降沿)、电平触发(阈值可调) |
| 电源 | 5V/2A DC电源(AMS1117-3.3V稳压) | 为STM32、TFTLCD、信号调理供电 |
2.2 硬件连接
| 模块 | STM32引脚(F407ZGT6) | 说明 |
|---|---|---|
| TFTLCD | FSMC_D0D15(PD0PD1, PD8~PD15, PE0~PE15) | 16位数据总线(8080并行) |
| FSMC_NE1(PD7) | 片选信号 | |
| FSMC_NWE(PD5) | 写使能 | |
| FSMC_NRD(PD4) | 读使能 | |
| ADC | PA0(ADC1_IN0) | 模拟信号输入(经PGA调理) |
| 触发电路 | PB0(EXTI0) | 触发信号输入(外部中断) |
| 触摸控制 | SPI1(PA5-SCK, PA6-MISO, PA7-MOSI) | 触摸芯片(XPT2046)通信 |
三、软件设计(STM32 HAL库 + FSMC驱动)
3.1 系统架构
主程序
初始化
ADC采集(DMA+双缓冲)
触发检测(边沿/电平)
数据处理(电压转换、参数计算)
TFTLCD显示(波形+参数)
触摸/按键交互(参数设置)
3.2 核心模块实现
3.2.1 TFTLCD驱动(FSMC并行接口)
使用STM32的FSMC(灵活的静态存储控制器) 驱动TFTLCD,模拟8080并行时序,提高传输速度(最高60MB/s)。
关键代码(ILI9488初始化):
c
#include "ili9488.h"
#include "fsmc.h"
// FSMC配置(NE1片选,16位数据)
void FSMC_LCD_Init(void) {
FSMC_NORSRAM_TimingTypeDef timing;
FSMC_NORSRAM_InitTypeDef init;
// 时序配置(写周期)
timing.AddressSetupTime = 1; // 地址建立时间
timing.AddressHoldTime = 0;
timing.DataSetupTime = 9; // 数据建立时间(关键,需根据LCD调整)
timing.BusTurnAroundDuration = 0;
timing.CLKDivision = 0;
timing.DataLatency = 0;
timing.AccessMode = FSMC_ACCESS_MODE_A;
// FSMC参数配置
init.NSBank = FSMC_NORSRAM_BANK1_NORSRAM1;
init.DataAddressMux = FSMC_DATA_ADDRESS_MUX_DISABLE;
init.MemoryType = FSMC_MEMORY_TYPE_SRAM;
init.MemoryDataWidth = FSMC_NORSRAM_MEM_BUS_WIDTH_16;
init.BurstAccessMode = FSMC_BURST_ACCESS_MODE_DISABLE;
init.WaitSignalPolarity = FSMC_WAIT_SIGNAL_POLARITY_LOW;
init.WrapMode = FSMC_WRAP_MODE_DISABLE;
init.WaitSignalActive = FSMC_WAIT_TIMING_BEFORE_WS;
init.WriteOperation = FSMC_WRITE_OPERATION_ENABLE;
init.WaitSignal = FSMC_WAIT_SIGNAL_DISABLE;
init.ExtendedMode = FSMC_EXTENDED_MODE_DISABLE;
init.AsynchronousWait = FSMC_ASYNCHRONOUS_WAIT_DISABLE;
init.WriteBurst = FSMC_WRITE_BURST_DISABLE;
HAL_SRAM_Init(&hsram1, &init, &timing);
}
// ILI9488写命令/数据
void ILI9488_WriteCmd(uint16_t cmd) {
LCD->CMD = cmd; // FSMC映射到LCD_CMD地址
}
void ILI9488_WriteData(uint16_t data) {
LCD->DATA = data; // FSMC映射到LCD_DATA地址
}
3.2.2 ADC采集与触发检测
ADC配置:12位分辨率,单通道(PA0),DMA传输(双缓冲),采样率1MHz(通过TIM3触发)。
触发检测:边沿触发(上升沿/下降沿)或电平触发(阈值可调),检测到触发信号后开始采集一帧数据(如1024点)。
核心代码(ADC+DMA双缓冲):
c
#define BUFFER_SIZE 1024 // 一帧数据点数
uint16_t adc_buffer[2][BUFFER_SIZE]; // 双缓冲
uint8_t active_buffer = 0; // 当前采集缓冲(0/1)
// ADC初始化(TIM3触发,1MHz采样率)
void ADC_Init(void) {
ADC_ChannelConfTypeDef sConfig = {0};
hdma_adc1.Instance = DMA2_Stream0;
hdma_adc1.Init.Channel = DMA_CHANNEL_0;
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_HALFWORD;
hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
hdma_adc1.Init.Mode = DMA_CIRCULAR; // 循环模式(双缓冲)
hdma_adc1.Init.Priority = DMA_PRIORITY_HIGH;
HAL_DMA_Init(&hdma_adc1);
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; // 84MHz/4=21MHz
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
hadc1.Init.ScanConvMode = DISABLE;
hadc1.Init.ContinuousConvMode = DISABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;
hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T3_TRGO; // TIM3触发
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 1;
HAL_ADC_Init(&hadc1);
sConfig.Channel = ADC_CHANNEL_0;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES; // 3周期采样(21MHz下≈0.14μs)
HAL_ADC_ConfigChannel(&hadc1, &sConfig);
// 启动DMA双缓冲
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_buffer[0], BUFFER_SIZE*2);
}
// 触发检测(边沿触发示例)
void Trigger_Detect(uint16_t *data, uint16_t len) {
static uint16_t last_val = 0;
for (int i=0; i<len; i++) {
if ((last_val < trigger_level) && (data[i] >= trigger_level)) { // 上升沿触发
start_capture = 1; // 开始采集一帧
break;
}
last_val = data[i];
}
}
3.2.3 波形显示与参数计算
波形绘制 :将ADC采集的二进制值(04095)转换为电压(03.3V),再映射到TFTLCD屏幕坐标(纵轴:电压/格,横轴:时间/格)。
参数计算:
-
Vpp:最大值-最小值;
-
频率:通过过零检测或FFT计算(基础版用周期法:T=相邻上升沿时间差,f=1/T);
-
占空比:高电平时间/周期。
核心代码(波形绘制):
c
// 坐标转换:ADC值→屏幕Y坐标(纵轴:0~3.3V,对应屏幕顶到底)
uint16_t adc_to_y(uint16_t adc_val, uint16_t height) {
float voltage = (adc_val * 3.3f) / 4096.0f; // ADC值转电压
float y_ratio = voltage / 3.3f; // 电压占比(0~1)
return (height - 1) - (uint16_t)(y_ratio * (height - 1)); // 屏幕Y坐标(上正下负)
}
// 绘制波形(一帧数据,1024点)
void Draw_Waveform(uint16_t *data, uint16_t len) {
uint16_t x, y, prev_x = 0, prev_y = 0;
uint16_t screen_width = 320, screen_height = 240; // 屏幕分辨率
uint16_t grid_size = 20; // 网格大小(像素)
// 清屏(黑色背景)
LCD_Fill(0, 0, screen_width, screen_height, BLACK);
// 绘制网格
Draw_Grid(grid_size, screen_width, screen_height, GRAY);
// 绘制波形(折线连接)
for (int i=0; i<len; i++) {
x = (i * screen_width) / len; // X坐标(时间轴)
y = adc_to_y(data[i], screen_height);
if (i > 0) {
LCD_DrawLine(prev_x, prev_y, x, y, GREEN); // 绿色波形
}
prev_x = x; prev_y = y;
}
// 显示参数(Vpp、频率)
char str[20];
sprintf(str, "Vpp: %.2fV", vpp);
LCD_ShowString(10, 10, str, WHITE, BLACK, 16);
sprintf(str, "Freq: %.1fHz", frequency);
LCD_ShowString(10, 30, str, WHITE, BLACK, 16);
}
参考代码 基于STM32与TFTLCD的示波器设计 www.youwenfan.com/contentcst/182932.html
四、关键问题与解决方案
4.1 实时性不足
-
问题:高采样率下(1MHz),CPU处理数据+显示耗时过长,导致波形卡顿。
-
解决:
-
用DMA双缓冲采集ADC数据,采集与处理并行;
-
显示采用局部刷新(只更新变化区域),而非全屏重绘;
-
降低显示分辨率(如每2个点取1个显示)。
-
4.2 触发不稳定
-
问题:噪声导致误触发,波形偏移。
-
解决:
-
增加触发迟滞(如上升沿触发时,设置"触发阈值+迟滞电压");
-
软件消抖(连续3次检测到触发条件才确认)。
-
4.3 测量精度低
-
问题:ADC量化误差、噪声导致Vpp/频率计算不准。
-
解决:
-
用多次采样平均降低噪声(如1024点取平均);
-
校准ADC参考电压(用高精度万用表测量3.3V,软件修正)。
-
五、测试与验证
-
功能测试:输入正弦波(1kHz,1Vpp),示波器显示波形稳定,Vpp=1.0V±0.05V,频率=1.0kHz±0.1kHz。
-
性能测试:最大采样率1MHz,显示刷新率20fps(1024点/帧),无明显卡顿。
-
交互测试:触摸设置采样率(100kHz/500kHz/1MHz)、垂直灵敏度(0.1V/格~1V/格),响应时间<0.5s。
六、总结
基于STM32F407与TFTLCD实现了低成本示波器,核心是高速ADC采集、双缓冲DMA传输与实时波形显示。通过模块化设计,可扩展多通道输入、FFT频谱分析、触摸菜单优化等功能,满足基础电子测量需求。