2025寒假练 - 基于STM32G031板卡实现虚拟仪器
该项目使用了STM32G031板卡、C语言,实现了虚拟仪器的设计,它的主要功能为:产生常见的四种波形,传输模拟信号并在上位机上显现波形。
标签
测试
显示
额...
更新2025-03-17
14

项目总结报告

一、项目介绍

2025年寒假在家一起练活动中,我选择的项目是基于STM32的虚拟仪器实现。该项目是将STM32G031示波器板卡同PC连接起来,利用PC的数据处理能力和大屏幕显示,实现更好的测试测量效果具体任务要求是:

1、使用STM32G031平台进行数据采集及信号产生

2、通过USBPC进行数据传输

3、在上位机上编写简单的仪器控制界面,实现双通道示波器和单通道信号发生器的功能 ,显示波形以及基本的参数


二、硬件介绍

1.基于STM32G031微控制器,Arm Cortex M0+内核,主频为64MHz

2.个按键+ 一个光电旋转编码器用于控制输入

3.SPI接口的OLED显示屏(128*128分辨率)

4.路音频放大电路用于产生ADC的测试信号,并可作为测试电路使用

5.一个蜂鸣器用于音效输出

6.一路基于PWMDDS信号输出,用于产生测试信号(任意波形)

7.路增益可调的模拟信号输入,通过12bits ADC采集2mVpp - 30Vpp,带宽为100KHz的模拟信号

 

三、方案框图及项目设计思路

 

image.png 

 

分析任务要求,项目主要由两部分构成:信号发生器和示波器。由于STM32G031板卡上并未提供DC模块,不能利用其产生任意波形,因此利用板卡上PWMLPF电路来产生任意波形。示波器利用2路增益可调的模拟信号输入,通过12bits ADC采集2mVpp - 30Vpp,带宽为100KHz的模拟信号,数据由DMA传输,减少MCU的运行压力,通过USB和电脑进行数据传输,并在电脑上编写简单的上位机,利用电脑强大的算力进行数据处理,并在上位机上完成信号的波形绘制额相关参数的测量并显现。

 

四、软件流程图及关键代码


 void HAL_GPIO_EXTI_Rising_Callback(uint16_t GPIO_Pin)
{
switch(GPIO_Pin)
{
case KEY3_EXIT_Pin:
if(HAL_GPIO_ReadPin(KEY5_GPIO_Port,KEY5_Pin)==1&&num==0)//反转
{
if(page_flag==0&&mode==0)
{
scan--;
if(scan==0) scan=4;
}
}
else if(HAL_GPIO_ReadPin(KEY5_GPIO_Port,KEY5_Pin)==0&&num==1)//正转
{
if(page_flag==0&&mode==0)
{
scan++;
if(scan==5) scan=1;
}
}
break;
}
}

  光电旋转编码器输入控制信号发生器界面参数的滚动浏览,光电旋转编码器顺时针旋转参数向下浏览,浏览时参数反色显示,当浏览最后一个参数时,继续顺时针旋转跳转至第一个参数。逆时针同理。


void HAL_GPIO_EXTI_Falling_Callback(uint16_t GPIO_Pin)
{
switch(GPIO_Pin)
{
case KEY1_EXIT_Pin:
if(HAL_GPIO_ReadPin(KEY1_EXIT_GPIO_Port,KEY1_EXIT_Pin)==GPIO_PIN_RESET)
{
HAL_GPIO_TogglePin(LED_G_GPIO_Port,LED_G_Pin);
if(page_flag==0)
{OLED_Clear();
mode^=1;

OLED_Clear();
}
if(page_flag==1)
{
switch(scan)
{
case 1:
frequency+=1000;
if(frequency>=6000) frequency=5000;
setparameters();
break;
case 2:
if(amplitude<160)
{
amplitude+=15;
setparameters();
}
break;
case 3:
WAVESTATE=(WAVESTATE+1)%4;
setparameters();
break;
case 4:
out_flag^=1;
break;
}
}
}
break;
case KEY2_EXIT_Pin:
if(HAL_GPIO_ReadPin(KEY2_EXIT_GPIO_Port,KEY2_EXIT_Pin)==GPIO_PIN_RESET)
{
if(page_flag==1)
{
switch(scan)
{
case 1:
frequency-=1000;
if(frequency==0) frequency=1000;
setparameters();
break;
case 2:
if(amplitude>75)
{
amplitude-=15;
setparameters();
}
break;
case 3:
WAVESTATE=(WAVESTATE+1)%4;
setparameters();
break;
case 4:break;
}
}
}
break;
case KEY4_EXIT_Pin:
if(HAL_GPIO_ReadPin(KEY4_EXIT_GPIO_Port,KEY4_EXIT_Pin)==GPIO_PIN_RESET)
{
if(mode==0)
{
page_flag^=1;
}
}
break;
case KEY3_EXIT_Pin:
if(HAL_GPIO_ReadPin(KEY5_GPIO_Port,KEY5_Pin)==1){num=1;}
else num=0;
break;
}
}

这段代码主要是按键控制界面的切换,参数的变化,其中包括波形的产生,频率、幅度以及波形的控制。

void setparameters(void) {
const uint32_t SYSCLK = 64000000;
const float max_amp = 165.0f;
float amp_norm = amplitude / max_amp;
uint32_t arr_val = SYSCLK / (LEN * frequency) - 1;

__HAL_TIM_SET_AUTORELOAD(&htim3, arr_val);
TIM3->CNT = 0;

for(uint16_t i=0; i<LEN; i++) {
float value;

switch(WAVESTATE) {
case 0: // DC
value = amp_norm; // 0.0~1.0
break;

case 1: // Sine
value = 0.5f + 0.5f * amp_norm * sinf(2*3.1415926*i/LEN);
break;

case 2: // Square
value = (i < LEN/2) ? amp_norm : 0.0f;
break;

case 3: // Triangle
value = 2.0f * fabs((float)i/LEN - 0.5f) * amp_norm;
break;

default:
value = 0.0f;
break;
}

send_Buf[i] = (uint16_t)(value * arr_val);
send_Buf[i] = (send_Buf[i] > arr_val) ? arr_val : send_Buf[i]; // 限幅
}
}

这段代码是信号发生器的核心算法,用于产生四种基础波形(直流/正弦波/方波/三角波)的PWM控制信号,并通过send_Buf缓冲区输出到定时器外设,通过外部LPF电路产生相应波形。其中频率和幅度可调,每次波形参数发生变化时调用该函数,产生新的波形。


void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
if(hadc->Instance == ADC1)
{
send_data_packet(); //发送数据包
HAL_ADC_Start_DMA(&hadc1, (uint32_t *)adc_value, 2); //重启DMA,搬运adc数据
}
}

这段代码在ADC1完成DMA数据转换时触发,自动发送采集到的数据包,并立即重启DMA进行下一轮双通道数据采集,实

现实时、连续的数据采集与传输循环。


五、功能展示及说明

图1 图2 图3 图4

界面UI设计借鉴了往届学长的布局。图1为上电时信号发生器初始化界面,此界面按下左边按键切换到示波器界面(图2),将数据通过USB不断发送到电脑上位机上,并绘制相应波形。在信号发生器界面旋转光电旋转编码器,依次浏览四个参数(频率/幅度/波形/信号产生开关)。浏览时,被浏览的参数反色显示(图3)。此时,按下光电旋转编码器即可选中参数,参数正常显示,说明进入选中状态(图4)。在参数选中界面,左右两个按键可以修改选中参数数值或状态。例如参数频率被选中,左按键增加频率,右按键减小频率。信号产生开关被选中,左按键可控制波形的产生与否。参数修改完成后,再次按下光电旋转编码器即可退出选中状态,进入浏览状态。

图5 图6 图7 图8

图5为信号发生器产生波形,图6为增大幅度,图6为减小频率,图8为上位机显示波形。


六、遇到的难题和解决方法

在此次活动中遇到的第一个难题是光电旋转编码器,由于之前并没有接触过这个元件,并不知道怎么使用。在CSDN上搜索相关资料,找到如下时序图。结合活动视频资料,将一个引脚配成外部中断,另一个为正常输出,判断上升沿时,两个引脚输出相位。但经过实践后,发现效果并不好,旋转过快时,其稳定性不好,容易发生误判。再次研究时序,通过对上升沿,下降沿都进行判断,稳定性相比之前强不少。

image.png

其次,在进行信号发生器产生波形时,产生信号在示波器上每一段波形之间会有一段直线,应该是没有信号产生。经过一段时间逐次排查发现,产生PWM波的定时器DMA传输没有配置成循环模式。修改过后,产生完整的波形。但是波形会发生饱和失真,找了很久的原因没有解决,直到减小波形幅度时,波形正常。可能的原因是,外部LPF电路对高频滤波效果不好。

最后,在编写UI界面时,因为要在OLED屏上显示四个波形图片,需要四个大数组储存相关点位。发现板卡range小了,空间不够,在CSDN上查找,将数组前加上const,即将四个大数组储存在flash中,并修改OLED相关函数,成功解决。

上位机由于某些功能实现不尽人意,未能解决,在录制视频时,对相关布局进行了调整。

七、心得体会

在此次活动中,我进行了相关练习,对嵌入式的学习有了初步了解和学习。在活动过程中遇到不少难题,通过在网上查找相关资料,锻炼了解决问题的能力。同时,编写代码的过程中,不同的写法会导致结果的不同,这对整体的把控有一定要求,锻炼了我的思维能力。将板卡和PC结合,编写上位机,让我见识到电脑强大的处理数据能力。尽管在项目实现在某些方面并不完美,有很多可以改进的地方。但这次活动确确实实的让我收获颇多。希望活动能越办越好,在下次活动上,能有更多收获。

附件下载
2025年寒假在家练.zip
团队介绍
额...
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号