【淘晶驰串口屏开发】复刻2021年电赛失真度测量装置:记录串口屏绘制重构波形、显示数据及按键控制方案

引言

博主在复刻 2021年电赛A题:信号失真度测量装置 时,在开发串口屏用来显示数据并绘制波形的时候,在绘制波形这一方面出了一点问题:绘制波形并不能在串口屏的曲线控件上很好的显示出一个周期波形。另一个写这篇文章的原因就是:每次使用串口屏都要重新看一遍淘晶驰的使用手册,会比较浪费时间,故也是在这里做一个记录。

串口屏绘制波形

2021年A题的要求是显示出一个周期的波形。再通过前面的采样分析后,可以得到用于还原波形的数据有:基波幅值、二次到五次谐波的幅值。这里不难看出,要还原波形只需要用上《信号与系统》中学过的“傅里叶级数”来恢复即可。

波形恢复

\(傅里叶级数公式:(三角形式)\)
\(f(t)=\frac{a_{0}}{2}+\sum_{n=1}^{\infty }[a_{n}\cdot cos(n\omega t)+b_{n}\cdot sin(n\omega t)]\)

\((其中\frac{a}{2}代表直流分量,n代表各次谐波,a_{n}和b_{n}分别是余弦分量和正弦分量的系数)\)

\(傅里叶级数公式:(余弦形式)\)
$ f(t)=c_{0}+\sum_{n=1}^{\infty }[c_{n}\cdot cos(n\omega t + \phi_{n})]$

\((其中c_{0}=\frac{a}{2}代表直流分量,c_{n}=\sqrt{a_{n}^{2}+b_{n}^{2}},\phi_{n}=-arctan(\frac{a_{n}}{b_{n}}))\)
这里我们已知谐波的幅值,就可直接用下面的余弦形式进行还原,因为是工程上的使用,对于公式并不需要完全遵循,要懂得变通。

波形显示

这里有两个方案,可以先看看代码,猜猜哪一个更好?
方案一:

点击查看代码
/* 傅里叶级数(1...N求和):A1*cos(2*pi*f*1)+A2*cos(2*pi*f*2)+A2*cos(2*pi*f*2)+...An*cos(2*pi*f*n) */
                /* 还原波形 */
                point = (uint8_t)((adc_sample_rate) / freq);
                for (uint8_t i = 0; i < point + 5; i++) {
                    float t = i * (1.0f / adc_sample_rate);
                    // 累加各次谐波(含正确时间参数)
                    wave_data = A[0] * arm_cos_f32(2 * pi * freq * 1 * t * 2 + 4 / pi) +  // 基波
                                A[1] * arm_cos_f32(2 * pi * freq * 2 * t * 2 + 4 / pi) +  // 2次谐波
                                A[2] * arm_cos_f32(2 * pi * freq * 3 * t * 2 + 4 / pi) +  // 3次谐波
                                A[3] * arm_cos_f32(2 * pi * freq * 4 * t * 2 + 4 / pi) +  // 4次谐波
                                A[4] * arm_cos_f32(2 * pi * freq * 5 * t * 2 + 4 / pi);   // 5次谐波
					/* 使用串口一 */
                    Set_CurrentUART(UART1_IDX);
					/* 串口屏波形控件显示波形 */
                    printf("add s0.id,0,%d\xff\xff\xff",(int)((int)ori_signal % 256));
                    printf("add s0.id,0,%d\xff\xff\xff",(int)((int)ori_signal % 256));
                    printf("add s0.id,0,%d\xff\xff\xff",(int)((int)ori_signal % 256));
                    printf("add s0.id,0,%d\xff\xff\xff",(int)((int)ori_signal % 256));
                }

方案二:

点击查看代码
                    for (uint16_t i = POINT ; i > 0; i --) {/* 利用基波和各个谐波幅值合成波形 */
                        wave_buf = harm_amp[0] * arm_sin_f32(0.030 * i) + 
                                   harm_amp[1] * arm_sin_f32(0.030 * i * 2) + 
                                   harm_amp[2] * arm_sin_f32(0.030 * i * 3) + 
                                   harm_amp[3] * arm_sin_f32(0.030 * i * 4) + 
                                   harm_amp[4] * arm_sin_f32(0.030 * i * 5);
                        wave_buf_printf = 20 * wave_buf + 150;
                        Set_CurrentUART(UART1_IDX);
                        printf("add s0.id,0,%d\xff\xff\xff", wave_buf_printf);
                        printf("add s0.id,0,%d\xff\xff\xff", wave_buf_printf);
                        printf("add s0.id,0,%d\xff\xff\xff", wave_buf_printf);

                        wave_data[i] = 400 * (harm_amp[0] * arm_sin_f32(0.065 * i) + 
                                              harm_amp[1] * arm_sin_f32(0.065 * i * 2) + 
                                              harm_amp[2] * arm_sin_f32(0.065 * i * 3) + 
                                              harm_amp[3] * arm_sin_f32(0.065 * i * 4) + 
                                              harm_amp[4] * arm_sin_f32(0.065 * i * 5));
                    }

这里就不放图片了(其实是我没拍),答案是第二种方案更好。为什么呢?
第一种方案: 直接很单纯的就用实际测到的波形的频率作为还原波形的基波频率和谐波频率,并且显示很多个点,打印很多次,当时我试了很多次,屏幕上的波形宽度都还是细如牛毛。原因就是,你用那么高的波形频率显示,周期都那么小了,怎么可能在那么大一个屏幕上显示一个完整的周期波形!
第二种方案: 这里将\(\omega\)直接赋值为0.030,可以直接也可以间接的知道,这个波形的频率非常非常非常的小,周期非常非常非常的大,如此宽的一个波形,是不是就能很好的在屏幕上显示了呢?只需要微微调整一下打印的总点数和一次循环索要打印的次数即可获得自己想要的波形。

数据显示

由于博主也是经常容易忘记串口屏上到底哪一个控件用来显示,这里就直说了,就用文本控件,即可显示中文,又可显示英文;不仅可显示整数,还可以显示浮点数,可谓非常的好用。串口格式如下:

点击查看代码
                    /* HMI串口屏各谐波参数显示 */
                    Set_CurrentUART(UART1_IDX);
                    printf("t12.txt=\"%.3f\"\xff\xff\xff", thd * 100.0f);
                    printf("t7.txt=\"%.3f\"\xff\xff\xff", harm_amp[0] / harm_amp[0]);
                    printf("t8.txt=\"%.3f\"\xff\xff\xff", harm_amp[1] / harm_amp[0]);
                    printf("t9.txt=\"%.3f\"\xff\xff\xff", harm_amp[2] / harm_amp[0]);
                    printf("t10.txt=\"%.3f\"\xff\xff\xff", harm_amp[3] / harm_amp[0]);
                    printf("t11.txt=\"%.3f\"\xff\xff\xff", harm_amp[4] / harm_amp[0]);

按键控制

这里也很简单,快速过一遍了:
HMI按键代码:

点击查看代码
/* 发送一个字符串 */
prints "action \r",0

单片机rx程序:
要记得开启串口接收中断,直接在中断函数内直接判断字符串某个字符或者字符串长度即可接收到指令

点击查看代码
void UART_1_INST_IRQHandler(void)
{
    volatile uint8_t rx_size;
    switch (DL_UART_Main_getPendingInterrupt(UART_1_INST)) {
        case DL_UART_MAIN_IIDX_RX:
            uart_1_rx_data[0] = DL_UART_Main_receiveData(UART_1_INST);
            if (uart_1_rx_data[0] == 'a') {
                HMI_Botton_flag = true;
                Set_CurrentUART(UART1_IDX);
                printf("cle s0.id,0\xff\xff\xff");
            }
            break;
        default:
            break;
    }
}
posted @ 2025-07-17 17:01  膝盖中箭卫兵  阅读(306)  评论(1)    收藏  举报
ORCID iD icon https://orcid.org/0000-0001-5102-772X