项目介绍:
使用STM32G031的信号产生以及数据采集功能,通过USB链接电脑,通过电脑发送控制命令,测量板上麦克风发生器部分的幅频特性和相频特性,并将测试数据传递到电脑,在电脑屏幕上通过自己设计的界面将波特图绘制出来。
测试系统构成
被测电路部分
(1)使用电子森林的在线电路仿真工具对被测的模拟电路进行仿真,将仿真的电路以及仿真结果生成短连接,并附在项目报告中。
(2)对比实测的结果以及电路仿真的结果,分析二者之间的差异及原因。
设计思路:
首先需要找到STM32G031示波器板卡的电路图,观察被测电路部分所在位置,以及芯片所在位置,观察电路构成以及接口,方便后面使用STM32CubeMX。
电路部分如上图所示,待测电路在左上角,我们需要将PWM信号通过电脑端生成,然后传给端口PB0,PB0会将其按照箭头的方向传播,在经过一个起到滤波作用的电路后,因为来到端口1,这时候我们需要将板卡的12相连,使电路接通,信号流向待测电路,经过两级运放之后,回到PA0,PA0也就是ADC的接口,ADC会帮助我们得到量化的信号,然后通过串口传递给PA3、PA2,再传给USB接口,然后通过数据线传给电脑,电脑计算得出结果,画出波特图。
项目所用硬件介绍:
- 内核: Arm® 32-bit Cortex®-M0+ CPU, 最高频率为64 MHz
- 存储器:
- 8KBytes SRAM
- 64Kbytes的Flash存储器,并有保护和安全区
- 12位, 0.4µs ADC (最多达16个外部通道)
- 通过硬件过取样能够达到最多16位
- 转换范围: 0 to 3.6V
- 11个定时器 (有一个可以支持到128 MHz): 1个用于先进马达控制的16-bit定时器, 一个32位和4个16位的通用定时器, 2个低功耗16位, 2个看门狗, SysTick定时器
- 通信接口
- 2个I2C总线接口支持快速模式Plus (1Mbit/s),需要额外的电流供应, 一个支持SMBus/PMBus并能够从Stop模式中唤醒
- 2个USARTs并有着master/slave同步SPI; 一个支持ISO7816接口, LIN, IrDA, 自动波特率监测和唤醒功能
- 1个低功耗UART
- 2个SPIs (32Mbit/s)有4到16位可编程位帧,一个可以与I2S接口复用
- 开发支持: 串行线调试(SWD)
- 96位独特的ID
仿真结果如下:
https://www.eetree.cn/short/24oc5vxg
10Hz:
100Hz:
1kHz:
10kHz:
下方的四个示波器分别对应待测电路的3、1、5、7四个接口。
问题:在调试的过程中,我并未发现示波器的不同,可能是示波器的范围没有调整正确。
实测步骤:
一、安装STM32CubeMX并选择对应STM32型号(STM32G0x1G8U6)
二、配置
2.1 配置RCC
LSE选择Crystal/Ceremic Resonator。
图2.1 RCC配置
2.2 配置GPIO
PB0:选择TIM3_CH3。
PA0:选择ADC1_IN0。
图2.2 GPIO配置
2.3 配置TIM3
选择TIM3,将Channel3 配置为PWM Generation CH3。
设置PSC和ARR以生成所需的PWM频率。PSC=71,ARR=999,PWM频率为1kHz。设置CRR=499,即50%占空比。
图2.3 TIM3配置
2.4 配置ADC
选择ADC1,将Channel0(PA0)添加。
设置19.5cycles。
Continuous Conversion Mode选为Enabled。
图2.4 ADC配置
2.5 配置USART
选择USART2,波特率为115200,数据位为8,停止位为1。
图2.5 USART配置
2.6 Generate Code
生成main.c等文件。
2.7 编写代码
在main.c中添加代码如下:
/* USER CODE BEGIN Includes */
#include "my_functions.h"
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "stm32g0xx_hal_adc_ex.h"
/* USER CODE END Includes */
/* USER CODE BEGIN PV */
uint16_t adc_value;
float freq = 1000.0; //
float ref_value = 2048.0;
#define BODE_MSG_LEN 64
char msg[BODE_MSG_LEN];
/* USER CODE END PV */
/* USER CODE BEGIN 2 */
HAL_ADCEx_Calibration_Start(&hadc1);
float vrefint_value = 3.0 * (*VREFINT_CAL_ADDR) / 4095.0;
ref_value = 4095.0 * 1.2 / vrefint_value;
/* USER CODE END 2 */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_ADC_Start(&hadc1);
if (HAL_ADC_PollForConversion(&hadc1, 10) == HAL_OK) {
adc_value = HAL_ADC_GetValue(&hadc1);
//char msg;
int required = snprintf(msg, sizeof(msg), "Freq:%.1f, Gain:%.2fdB\r\n",
freq, 20*log10f(adc_value/ref_value));
if (required > 0 && required < sizeof(msg)) {
HAL_UART_Transmit(&huart2, (uint8_t*)msg, (uint16_t)required, 100);
}
//HAL_UART_Transmit(&huart2, (uint8_t*)msg, strlen(msg), 100);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, (adc_value > 2048) ? GPIO_PIN_SET : GPIO_PIN_RESET);
}
HAL_Delay(500);
}
/* USER CODE END 3 */
幅频特性测量:
Vin:PWM经过滤波后的等效正弦波峰峰值
Vout:通过PA0的ADC值换算,
相频特性测量:
已在上述代码中体现。
在\Core\Inc中添加my_functions.h,代码如下:
/* my_functions.h */
#ifndef __MY_FUNCTIONS_H
#define __MY_FUNCTIONS_H
#include "main.h" //
//
void ProcessADCData(uint16_t raw_value);
void UART_SendFloat(float value);
#endif /* __MY_FUNCTIONS_H */
在\Core\Src中添加my_functions.c,代码如下:
/* my_functions.c */
#include "my_functions.h"
#include <stdio.h>
void ProcessADCData(uint16_t raw_value) {
static float filtered_value = 0;
filtered_value = 0.9 * filtered_value + 0.1 * raw_value;
}
void UART_SendFloat(float value) {
char buffer;
snprintf(buffer, sizeof(buffer), "Voltage: %.2fV\r\n", value * 3.3f / 4095.0f);
HAL_UART_Transmit(&huart1, (uint8_t*)buffer, strlen(buffer), 100);
}
void SaveToSD(float freq, float gain, float phase) {
FIL file;
UINT bw;
char buf;
sprintf(buf, "%.1f,%.2f,%.1f\n", freq, gain, phase);
f_open(&file, "bode.csv", FA_WRITE | FA_OPEN_APPEND);
f_write(&file, buf, strlen(buf), &bw);
f_close(&file);
}
2.8 传输数据
然后进行程序烧录、数据采集和传输、数据处理和绘制波特图。
烧录使用ST-LINK/V2调试器,使用Python处理数据,生成波特图。
python代码如下:
import matplotlib.pyplot as plt
import numpy as np
# 加载带相位的数据
data = np.loadtxt('bode.csv', delimiter=',', dtype=[
('freq', 'f4'), ('gain', 'f4'), ('phase', 'f4')])
plt.figure(figsize=(10, 6))
plt.subplot(211)
plt.semilogx(data['freq'], data['gain'], 'b-', label='Measured')
plt.title('Realistic Bode Plot')
plt.ylabel('Gain (dB)')
plt.grid(True, which='both', ls='--')
plt.ylim(-40, 10)
plt.subplot(212)
plt.semilogx(data['freq'], data['phase'], 'r-')
plt.xlabel('Frequency (Hz)')
plt.ylabel('Phase (deg)')
plt.yticks(np.arange(-360, 91, 45))
plt.grid(True)
plt.tight_layout()
plt.savefig('bode_actual.png', dpi=300)
三、结果与分析
图3.1 波特图
分析:
1. 元件非理想特性:电容、电阻存在误差,运放可能存在限制。
2. 测量误差
3. 电路寄生参数:走线电感、电容可能存在,导致改变反馈网络阻抗,增益下降。
4. 高频时差异明显:在1MHz时,增益仿真值是-25dB,实测值是-35dB,可能是运放带宽模型过于理想。相位仿真值是-180°,实测值是-210°,可能是寄生电感导致相位滞后。增益也存在差异,可能是电源噪声导致的。
感想:
这是我第一次接触STM32,没有任何的基础。其中把自己做的每一步都写进了报告里,是因为这些都是我一点点问同学查博客才了解的,从最开始的我连电路图在哪里看都不知道,到后面输出测量的波特图,过程真的学习到了很多,也让我认识到了FPGA这块的神奇之处。
