STM32 + 淘晶驰T1串口屏波形显示

STM32 + 淘晶驰T1串口屏波形显示完整方案

一、STM32硬件连接

1. 接线方式

复制代码
T1显示屏        STM32F103C8T6
TX    ----------> PA3 (USART2_RX)
RX    ----------> PA2 (USART2_TX)
GND   ----------> GND
VCC   ----------> 3.3V/5V

二、STM32固件开发

1. CubeMX配置

c 复制代码
// 使用USART2与T1屏幕通信
// 波特率:115200
// 数据位:8
// 停止位:1
// 无校验位

2. 核心代码实现

c 复制代码
/* t1_display.h */
#ifndef __T1_DISPLAY_H
#define __T1_DISPLAY_H

#include "stm32f1xx_hal.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

// T1指令结束符
#define T1_END_CMD     "\xFF\xFF\xFF"

// 波形控件ID
#define WAVE_ID        1
#define VALUE_TEXT_ID  10
#define STATUS_TEXT_ID 11

// 函数声明
void T1_Init(UART_HandleTypeDef *huart);
void T1_SendString(char *str);
void T1_SendCmd(char *cmd);
void T1_ClearWaveform(void);
void T1_AddWavePoint(uint16_t value);
void T1_AddWavePoints(uint16_t *values, uint8_t count);
void T1_UpdateValueText(float value);
void T1_UpdateStatus(char *status);
void T1_SetWaveRange(uint16_t y_min, uint16_t y_max);

#endif
c 复制代码
/* t1_display.c */
#include "t1_display.h"

static UART_HandleTypeDef *t1_huart;
static char tx_buffer[128];

// 初始化
void T1_Init(UART_HandleTypeDef *huart) {
    t1_huart = huart;
    HAL_Delay(1000);  // 等待屏幕启动
    
    // 清空屏幕
    T1_SendCmd("cls");
    HAL_Delay(100);
    
    // 设置波形范围 (ADC 12位: 0-4095)
    T1_SetWaveRange(0, 4096);
    
    // 更新状态
    T1_UpdateStatus("Ready");
}

// 发送字符串到T1屏幕
void T1_SendString(char *str) {
    uint16_t len = strlen(str);
    HAL_UART_Transmit(t1_huart, (uint8_t*)str, len, HAL_MAX_DELAY);
}

// 发送完整指令
void T1_SendCmd(char *cmd) {
    sprintf(tx_buffer, "%s%s", cmd, T1_END_CMD);
    T1_SendString(tx_buffer);
}

// 清空波形
void T1_ClearWaveform(void) {
    sprintf(tx_buffer, "cle %d,0", WAVE_ID);
    T1_SendCmd(tx_buffer);
}

// 添加单个波形点
void T1_AddWavePoint(uint16_t value) {
    sprintf(tx_buffer, "add %d,0,%d", WAVE_ID, value);
    T1_SendCmd(tx_buffer);
}

// 批量添加波形点 (更高效)
void T1_AddWavePoints(uint16_t *values, uint8_t count) {
    if (count == 0) return;
    
    sprintf(tx_buffer, "addt %d,0,%d", WAVE_ID, values[0]);
    
    for (uint8_t i = 1; i < count; i++) {
        char temp[10];
        sprintf(temp, ",%d", values[i]);
        strcat(tx_buffer, temp);
    }
    
    T1_SendCmd(tx_buffer);
}

// 更新数值显示
void T1_UpdateValueText(float value) {
    sprintf(tx_buffer, "t%d.txt=\"%.2f\"", VALUE_TEXT_ID, value);
    T1_SendCmd(tx_buffer);
}

// 更新状态显示
void T1_UpdateStatus(char *status) {
    sprintf(tx_buffer, "t%d.txt=\"%s\"", STATUS_TEXT_ID, status);
    T1_SendCmd(tx_buffer);
}

// 设置波形显示范围
void T1_SetWaveRange(uint16_t y_min, uint16_t y_max) {
    sprintf(tx_buffer, "yadd %d,0,%d,%d", WAVE_ID, y_min, y_max);
    T1_SendCmd(tx_buffer);
}

3. ADC采集 + 波形显示主程序

c 复制代码
/* main.c */
#include "main.h"
#include "adc.h"
#include "usart.h"
#include "t1_display.h"
#include <math.h>

#define ADC_BUFFER_SIZE   200
#define SAMPLE_RATE       100   // Hz
#define DISPLAY_RATE      20    // Hz - 屏幕刷新率

uint16_t adc_buffer[ADC_BUFFER_SIZE];
uint16_t adc_index = 0;
uint32_t last_sample_time = 0;
uint32_t last_display_time = 0;
uint8_t display_enabled = 1;

// ADC完成回调
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) {
    if (hadc->Instance == ADC1) {
        adc_buffer[adc_index] = HAL_ADC_GetValue(hadc);
        adc_index = (adc_index + 1) % ADC_BUFFER_SIZE;
    }
}

// 触摸回调处理 (需要在串口接收中断中解析)
void T1_TouchCallback(uint8_t page_id, uint8_t control_id) {
    switch(control_id) {
        case 20:  // 开始按钮
            display_enabled = 1;
            T1_UpdateStatus("Running");
            break;
            
        case 21:  // 暂停按钮
            display_enabled = 0;
            T1_UpdateStatus("Paused");
            break;
            
        case 22:  // 清空按钮
            T1_ClearWaveform();
            T1_UpdateStatus("Cleared");
            break;
    }
}

// 解析串口接收数据 (T1触摸返回)
void USART2_RxCpltCallback(void) {
    // T1触摸数据格式: touch j,page_id,control_id
    // 需要解析串口接收缓冲区
    // 这里省略具体解析代码
}

int main(void) {
    HAL_Init();
    SystemClock_Config();
    
    // 外设初始化
    MX_GPIO_Init();
    MX_ADC1_Init();
    MX_USART2_UART_Init();
    
    // T1显示屏初始化
    T1_Init(&huart2);
    
    // 启动ADC DMA连续采集
    HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_buffer, ADC_BUFFER_SIZE);
    
    // 主循环
    while (1) {
        uint32_t current_time = HAL_GetTick();
        
        // 定期更新波形显示
        if (display_enabled && (current_time - last_display_time >= 1000/DISPLAY_RATE)) {
            last_display_time = current_time;
            
            // 获取最新ADC值
            uint16_t latest_value = adc_buffer[(adc_index - 1 + ADC_BUFFER_SIZE) % ADC_BUFFER_SIZE];
            
            // 更新波形
            T1_AddWavePoint(latest_value);
            
            // 更新数值显示 (可选滤波)
            T1_UpdateValueText(latest_value * 3.3 / 4096.0);  // 转换为电压值
            
            // 状态显示采样率
            static uint16_t sample_count = 0;
            sample_count++;
            if (sample_count % 50 == 0) {
                char status[20];
                sprintf(status, "%d Hz", DISPLAY_RATE);
                T1_UpdateStatus(status);
            }
        }
        
        // 其他处理
        // ...
        
        HAL_Delay(1);
    }
}

三、高级功能扩展

1. 双通道ADC波形显示

c 复制代码
/* dual_channel_adc.c */
#define CH1_WAVE_ID     1
#define CH2_WAVE_ID     2

// 双通道ADC采集
void DisplayDualChannelWave(void) {
    uint16_t ch1_value = Read_ADC_CH1();
    uint16_t ch2_value = Read_ADC_CH2();
    
    // 通道1 - 红色
    sprintf(tx_buffer, "add %d,0,%d", CH1_WAVE_ID, ch1_value);
    T1_SendCmd(tx_buffer);
    
    // 通道2 - 绿色
    sprintf(tx_buffer, "add %d,0,%d", CH2_WAVE_ID, ch2_value);
    T1_SendCmd(tx_buffer);
    
    // 更新数值显示
    sprintf(tx_buffer, "t1.txt=\"CH1:%.2fV\"", ch1_value * 3.3 / 4096.0);
    T1_SendCmd(tx_buffer);
    
    sprintf(tx_buffer, "t2.txt=\"CH2:%.2fV\"", ch2_value * 3.3 / 4096.0);
    T1_SendCmd(tx_buffer);
}

2. FFT频谱显示

c 复制代码
/* fft_display.c */
#include "arm_math.h"

#define FFT_SIZE         256
#define SAMPLE_FREQ      1000  // Hz

float32_t fft_input[FFT_SIZE * 2];
float32_t fft_output[FFT_SIZE];
uint16_t spectrum_bars[64];  // 频谱柱状图数据

void ProcessFFTAndDisplay(void) {
    static uint16_t sample_count = 0;
    
    // 采集时域数据
    fft_input[sample_count * 2] = adc_buffer[sample_count] * 3.3 / 4096.0;  // 实部
    fft_input[sample_count * 2 + 1] = 0;  // 虚部
    
    sample_count++;
    
    if (sample_count >= FFT_SIZE) {
        sample_count = 0;
        
        // 执行FFT
        arm_cfft_instance_f32 fft_instance;
        arm_cfft_init_f32(&fft_instance, FFT_SIZE);
        arm_cfft_f32(&fft_instance, fft_input, 0, 1);
        
        // 计算幅度
        arm_cmplx_mag_f32(fft_input, fft_output, FFT_SIZE);
        
        // 转换为频谱柱状图 (64个柱子)
        for (int i = 0; i < 64; i++) {
            uint16_t start = i * 2;
            uint16_t end = (i + 1) * 2;
            float32_t sum = 0;
            
            for (int j = start; j < end && j < FFT_SIZE/2; j++) {
                sum += fft_output[j];
            }
            
            spectrum_bars[i] = (uint16_t)(sum * 100);  // 缩放
            if (spectrum_bars[i] > 4096) spectrum_bars[i] = 4096;
        }
        
        // 发送频谱数据到T1屏幕
        T1_DisplaySpectrum(spectrum_bars, 64);
    }
}

void T1_DisplaySpectrum(uint16_t *bars, uint8_t count) {
    // 使用柱状图显示
    sprintf(tx_buffer, "addt %d,0,%d", 3, bars[0]);  // 控件ID=3为频谱图
    
    for (uint8_t i = 1; i < count; i++) {
        char temp[10];
        sprintf(temp, ",%d", bars[i]);
        strcat(tx_buffer, temp);
    }
    
    T1_SendCmd(tx_buffer);
}

3. 数据记录与回放

c 复制代码
/* data_logger.c */
#define LOG_BUFFER_SIZE  1000

typedef struct {
    uint16_t data[LOG_BUFFER_SIZE];
    uint32_t timestamp[LOG_BUFFER_SIZE];
    uint16_t index;
    uint8_t recording;
} DataLogger_t;

DataLogger_t logger = {0};

// 开始记录
void StartLogging(void) {
    logger.recording = 1;
    logger.index = 0;
    T1_UpdateStatus("Recording...");
}

// 记录数据
void LogData(uint16_t value) {
    if (!logger.recording || logger.index >= LOG_BUFFER_SIZE) 
        return;
    
    logger.data[logger.index] = value;
    logger.timestamp[logger.index] = HAL_GetTick();
    logger.index++;
}

// 回放数据
void PlaybackData(void) {
    T1_ClearWaveform();
    T1_UpdateStatus("Playing back...");
    
    for (uint16_t i = 0; i < logger.index; i++) {
        T1_AddWavePoint(logger.data[i]);
        T1_UpdateValueText(logger.data[i] * 3.3 / 4096.0);
        
        // 控制回放速度
        HAL_Delay(10);  // 100Hz回放
        
        // 可以在这里添加暂停/停止检查
    }
    
    T1_UpdateStatus("Playback done");
}

四、性能优化技巧

1. DMA双缓冲优化

c 复制代码
// 使用DMA双缓冲减少CPU干预
#define BUFFER_SIZE  256

uint16_t adc_buffer1[BUFFER_SIZE];
uint16_t adc_buffer2[BUFFER_SIZE];
volatile uint8_t buffer_ready = 0;

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) {
    static uint8_t buffer_select = 0;
    
    if (buffer_select == 0) {
        // buffer1已满,处理数据
        buffer_ready = 1;
        buffer_select = 1;
        HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_buffer2, BUFFER_SIZE);
    } else {
        // buffer2已满,处理数据
        buffer_ready = 2;
        buffer_select = 0;
        HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_buffer1, BUFFER_SIZE);
    }
}

2. 数据压缩传输

c 复制代码
// 差值压缩算法
typedef struct {
    uint16_t base_value;
    int8_t diff[8];  // -128 ~ 127的差值
} CompressedData_t;

void SendCompressedWaveData(uint16_t *data, uint8_t count) {
    CompressedData_t compressed;
    compressed.base_value = data[0];
    
    for (uint8_t i = 1; i < count && i < 9; i++) {
        compressed.diff[i-1] = (int8_t)(data[i] - data[i-1]);
    }
    
    // 发送压缩数据
    sprintf(tx_buffer, "cmp %d,%d", WAVE_ID, compressed.base_value);
    for (uint8_t i = 0; i < count-1; i++) {
        char temp[8];
        sprintf(temp, ",%d", (int)compressed.diff[i]);
        strcat(tx_buffer, temp);
    }
    T1_SendCmd(tx_buffer);
}

五、调试与测试

1. 串口调试函数

c 复制代码
void Debug_SendToPC(char *format, ...) {
    va_list args;
    va_start(args, format);
    
    char debug_buffer[128];
    vsprintf(debug_buffer, format, args);
    
    // 通过USART1发送到PC
    HAL_UART_Transmit(&huart1, (uint8_t*)debug_buffer, strlen(debug_buffer), 100);
    HAL_UART_Transmit(&huart1, (uint8_t*)"\r\n", 2, 100);
    
    va_end(args);
}

2. 系统状态监控

c 复制代码
void Monitor_SystemStatus(void) {
    static uint32_t last_monitor_time = 0;
    uint32_t current_time = HAL_GetTick();
    
    if (current_time - last_monitor_time > 1000) {
        last_monitor_time = current_time;
        
        // 发送状态信息到PC
        Debug_SendToPC("ADC Index: %d", adc_index);
        Debug_SendToPC("Free Heap: %lu", xPortGetFreeHeapSize());
        Debug_SendToPC("CPU Usage: %d%%", getCPUUsage());
    }
}

六、项目文件结构

复制代码
Project/
├── Core/
│   ├── Src/
│   │   ├── main.c
│   │   ├── t1_display.c
│   │   ├── adc_handler.c
│   │   └── fft_processor.c
│   └── Inc/
│       ├── t1_display.h
│       ├── adc_handler.h
│       └── fft_processor.h
├── Drivers/
└── USART_HMI/
    └── screen_project.HMI  # T1屏幕工程文件

这个方案提供了完整的STM32与淘晶驰T1串口屏的波形显示实现。可以根据具体需求调整采样率、显示点数、通信协议等参数。

相关推荐
A9better2 小时前
嵌入式开发学习日志53——互斥量
stm32·嵌入式硬件·学习
Q_21932764554 小时前
基于单片机的个性化服装尺寸红外 测量仪的设计
单片机·嵌入式硬件
Polanda。4 小时前
定时器-PWM参数测量实验
stm32·单片机·嵌入式硬件
恶魔泡泡糖5 小时前
51单片机串口通信
c语言·单片机·嵌入式硬件·51单片机
wotaifuzao5 小时前
【Keil 5安装】keil 5最新版本安装+环境配置+下载百度资源分享(安装包,注册机等)
stm32·单片机·嵌入式硬件·mcu·学习·keil5·最新keil
染予6 小时前
8.AD软件操作:绘制一个完整的原理图需要进行哪些操作?
嵌入式硬件
方芯半导体7 小时前
EtherCAT “通信 + 控制“ 的全国产化控制方案,ESC芯片(FCE1323)与国产MCU芯片功能板解析
xml·网络·单片机·嵌入式硬件·网络协议·机器人·自动化
三佛科技-134163842127 小时前
LP3716NCK 隔离型12V1A 12W茶炉板电源方案典型应用电路与设计关键
单片机·嵌入式硬件·物联网·智能家居·pcb工艺
羽获飞9 小时前
从零开始学嵌入式之STM32——5.GPIO外设
stm32·单片机·嵌入式硬件