1. STM32与淘晶驰T1串口屏波形显示方案解析
在嵌入式系统开发中,实时数据可视化一直是个重要课题。传统方案往往需要复杂的图形库和昂贵的显示屏,而淘晶驰T1串口屏提供了一种简单高效的解决方案。这个方案特别适合需要快速实现数据可视化的工业控制、传感器监测和教学实验场景。
我最近在一个环境监测项目中采用了STM32F103C8T6搭配淘晶驰T1屏的方案,实测下来波形刷新率可以达到50Hz以上,完全满足大多数应用场景的需求。下面我就详细分享这个方案的实现细节和优化技巧。
2. 硬件连接与配置
2.1 硬件选型与接线
淘晶驰T1系列串口屏有多个尺寸可选,推荐使用4.3寸或5寸版本,它们都支持115200波特率通信。与STM32的连接非常简单:
code复制T1显示屏 STM32F103C8T6
TX ----------> PA3 (USART2_RX)
RX ----------> PA2 (USART2_TX)
GND ----------> GND
VCC ----------> 3.3V/5V
注意:虽然T1屏支持5V供电,但建议使用3.3V以匹配STM32的电平,避免电平转换问题。如果必须使用5V,需要在RX线上添加电平转换电路。
2.2 CubeMX配置要点
在STM32CubeMX中配置USART2时,有几个关键参数需要注意:
- 波特率:115200(与T1屏默认设置一致)
- 数据位:8位
- 停止位:1位
- 无校验位
- 开启USART2全局中断
ADC配置建议:
- 使用ADC1的通道0(PA0)
- 12位分辨率
- 连续转换模式
- 启用DMA传输
- 采样周期设置为239.5个时钟周期
3. 核心代码实现
3.1 通信协议封装
淘晶驰T1屏使用简单的ASCII指令协议,每条指令以0xFF 0xFF 0xFF结尾。我们先封装基础通信函数:
c复制/* t1_display.h */
#define T1_END_CMD "\xFF\xFF\xFF"
#define WAVE_ID 1 // 波形控件ID
void T1_SendCmd(char *cmd) {
char tx_buffer[128];
sprintf(tx_buffer, "%s%s", cmd, T1_END_CMD);
HAL_UART_Transmit(&huart2, (uint8_t*)tx_buffer, strlen(tx_buffer), HAL_MAX_DELAY);
}
3.2 波形显示功能实现
波形显示是核心功能,T1屏支持两种数据添加方式:
- 单点添加(add指令):
c复制void T1_AddWavePoint(uint16_t value) {
char cmd[32];
sprintf(cmd, "add %d,0,%d", WAVE_ID, value);
T1_SendCmd(cmd);
}
- 批量添加(addt指令,更高效):
c复制void T1_AddWavePoints(uint16_t *values, uint8_t count) {
if(count == 0) return;
char cmd[128];
sprintf(cmd, "addt %d,0,%d", WAVE_ID, values[0]);
for(uint8_t i=1; i<count; i++) {
char temp[8];
sprintf(temp, ",%d", values[i]);
strcat(cmd, temp);
}
T1_SendCmd(cmd);
}
3.3 主程序逻辑
主程序需要协调ADC采集和屏幕刷新:
c复制#define SAMPLE_RATE 100 // Hz
#define DISPLAY_RATE 20 // Hz
uint16_t adc_buffer[200];
uint16_t adc_index = 0;
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) {
adc_buffer[adc_index] = HAL_ADC_GetValue(hadc);
adc_index = (adc_index + 1) % 200;
}
while(1) {
uint32_t now = HAL_GetTick();
// 定时刷新显示
if(now - last_display_time >= 1000/DISPLAY_RATE) {
last_display_time = now;
uint16_t latest = adc_buffer[(adc_index-1+200)%200];
T1_AddWavePoint(latest);
T1_UpdateValueText(latest * 3.3 / 4096.0);
}
HAL_Delay(1);
}
4. 高级功能扩展
4.1 双通道波形显示
对于需要同时显示两个信号的应用,可以扩展为双通道:
c复制#define CH1_WAVE_ID 1
#define CH2_WAVE_ID 2
void DisplayDualChannel(uint16_t ch1, uint16_t ch2) {
char cmd[64];
// 通道1(红色)
sprintf(cmd, "add %d,0,%d", CH1_WAVE_ID, ch1);
T1_SendCmd(cmd);
// 通道2(绿色)
sprintf(cmd, "add %d,0,%d", CH2_WAVE_ID, ch2);
T1_SendCmd(cmd);
}
在T1屏的UI编辑器中,需要预先设置两个波形控件,并分别指定不同的颜色。
4.2 FFT频谱显示
对于频域分析,可以添加FFT功能:
c复制#include "arm_math.h"
#define FFT_SIZE 256
void ProcessFFT(float32_t *input, float32_t *output) {
arm_cfft_instance_f32 fft;
arm_cfft_init_f32(&fft, FFT_SIZE);
// 执行FFT
arm_cfft_f32(&fft, input, 0, 1);
// 计算幅度
arm_cmplx_mag_f32(input, output, FFT_SIZE);
}
void DisplaySpectrum(float32_t *fft_output) {
char cmd[256] = "addt 3,0";
for(int i=0; i<64; i++) {
char temp[16];
uint16_t val = (uint16_t)(fft_output[i] * 100);
sprintf(temp, ",%d", val > 4096 ? 4096 : val);
strcat(cmd, temp);
}
T1_SendCmd(cmd);
}
4.3 数据记录与回放
添加数据记录功能便于后续分析:
c复制#define LOG_SIZE 1000
typedef struct {
uint16_t data[LOG_SIZE];
uint32_t timestamps[LOG_SIZE];
uint16_t index;
} DataLogger;
void LogData(DataLogger *logger, uint16_t value) {
if(logger->index >= LOG_SIZE) return;
logger->data[logger->index] = value;
logger->timestamps[logger->index] = HAL_GetTick();
logger->index++;
}
void Playback(DataLogger *logger) {
for(uint16_t i=0; i<logger->index; i++) {
T1_AddWavePoint(logger->data[i]);
HAL_Delay(10); // 控制回放速度
}
}
5. 性能优化技巧
5.1 DMA双缓冲技术
使用DMA双缓冲可以大幅降低CPU负载:
c复制uint16_t adc_buf1[256];
uint16_t adc_buf2[256];
volatile uint8_t buf_flag = 0;
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) {
if(buf_flag == 0) {
// 处理adc_buf1数据
buf_flag = 1;
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_buf2, 256);
} else {
// 处理adc_buf2数据
buf_flag = 0;
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_buf1, 256);
}
}
5.2 数据压缩传输
对于高采样率应用,可以采用差值压缩:
c复制void SendCompressed(uint16_t *data, uint8_t count) {
char cmd[128];
sprintf(cmd, "cmp %d,%d", WAVE_ID, data[0]);
for(uint8_t i=1; i<count; i++) {
int8_t diff = data[i] - data[i-1];
char temp[8];
sprintf(temp, ",%d", diff);
strcat(cmd, temp);
}
T1_SendCmd(cmd);
}
6. 调试与问题排查
6.1 常见问题及解决方案
-
屏幕无显示
- 检查电源电压(3.3V/5V)
- 确认TX/RX交叉连接
- 测量串口信号是否正常
-
波形显示卡顿
- 降低显示刷新率
- 使用批量传输(addt)代替单点传输(add)
- 检查STM32时钟配置
-
数据不同步
- 确保屏幕和STM32波特率一致
- 添加软件流控或硬件流控
- 在关键位置添加时间戳调试
6.2 调试工具推荐
- 逻辑分析仪:观察串口时序
- 串口调试助手:监控原始通信数据
- STM32 ST-Link Utility:监测CPU负载和内存使用
7. 项目优化建议
-
界面设计优化
- 在T1屏的UI编辑器中合理布局控件
- 添加按钮控制开始/暂停/清除
- 设计状态指示区域
-
功能扩展方向
- 添加网络传输功能(通过ESP8266)
- 实现SD卡数据存储
- 开发自动量程调整功能
-
性能提升技巧
- 使用硬件定时器触发ADC采样
- 优化DMA缓冲区大小
- 适当降低显示分辨率换取更高刷新率
在实际项目中,我发现最影响性能的往往是串口传输效率。通过实测,批量传输(addt)比单点传输(add)效率提升3-5倍。另外,T1屏的波形控件有最大点数限制(通常500-1000点),超出后会自动丢弃旧数据,这点需要注意。