当前位置:首页 > 工业控制 > 电路设计项目集锦
[导读]在本次实验中,使用了STM32F407ZGT6的模数转换器(ADC)外设来测量两个电压源:CR2032锂聚合物电池和USB 5V总线电源。由于STM32F407ZGT6的ADC只能安全接收最高达VDDA + 0.3V(绝对最大值为3.6V)的输入电压,因此设计了一个电阻分压电路,在输入信号到达MCU引脚之前将其降压。随后读取分压后的电压值,进行数字化处理,并通过固件重新缩放,以恢复原始的电源电压。

在本次实验中,使用了STM32F407ZGT6的模数转换器(ADC)外设来测量两个电压源:CR2032锂聚合物电池和USB 5V总线电源。由于STM32F407ZGT6的ADC只能安全接收最高达VDDA + 0.3V(绝对最大值为3.6V)的输入电压,因此设计了一个电阻分压电路,在输入信号到达MCU引脚之前将其降压。随后读取分压后的电压值,进行数字化处理,并通过固件重新缩放,以恢复原始的电源电压。

实验室还研究了元件公差对测量精度的影响,并将单个样本的ADC读数与软件平均读数进行比较,以评估降噪效果。

设计与测试

第一部分 — 硬件描述

1 — 开发板

RT-Thread RT-Spark开发板基于STM32F407ZGT6微控制器构建,该芯片为168 MHz的ARM Cortex-M4F处理器,并配备三个独立的12位ADC。本实验中使用了ADC1的通道1(PA1)作为模拟输入。

2 — 为什么需要分压器

CR2032纽扣电池的工作电压范围为2.0V至3.3V,这在ADC的安全输入范围内,理论上可直接连接。然而,USB总线工作电压为5V,若直接连接到PA1,则会超过ADC输入的绝对最大值3.6V,导致ADC输入永久损坏。因此,设计了一个单级分压电路,通过将输入信号按0.5倍的比例缩放,来同时处理两种电压源。

分隔符公式:

VADCIn = VSource × R2 / (R1 + R2)

当 R1 = R2 = 1 MΩ 时:

VADCIn = VSource × 0.5

5V USB 输入在 ADC 引脚处变为 2.5V,安全低于 3.3V 参考电压;3.0V 电池输入在 ADC 引脚处变为 1.5V。

特意选择了1 MΩ的高电阻值,以使分压器的电流消耗保持在约1.5 µA,从而在监测电池电压时限制不必要的电池放电。

3 — 电路板搭建

电路搭建在一块标准的面包板上。R1和R2串联连接,它们之间的中间点接到了面包板扩展接口上的PA1引脚。面包板的GND排线则连接到面包板的GND引脚。

4 — 信号源阻抗与采样时间

该电路的一个重要考虑因素是其较高的源阻抗。当 R1 = R2 = 1 MΩ 时,ADC 输入端所见的等效特维宁阻抗为:

Zsource = R1 ∥ R2 = 500 kΩ

ADC的内部采样保持电容(约10 pF)必须通过该阻抗完全充电,然后才能开始转换。所需的稳定时间约为5τ = 25 µs。在21 MHz的ADC时钟频率下,这相当于大约525个周期。STM32CubeMX中可提供的最大采样时间为480个周期(约22.9 µs),这一数值已足够接近,并被选用于本实验。

第二部分 — 软件设置

1 — 创建项目

•打开 STM32CubeMX → 文件 → 新建项目

•对于MCU,搜索到了STM32F407ZGT6并选中了它

•项目名称:该项目/实验室命名为 Lab7_ADC_VoltageMonitor

•工具链 / IDE:STM32CubeIDE

•点击生成代码

2 — 系统核心配置

•在系统核心 → SYS 中:

•调试:串行线(自动为SWD分配PA13/PA14)

•在系统核心 → RCC 下:

•HSE:晶体/陶瓷谐振器(RT-Spark板上使用的是8 MHz晶体)

3 — 时钟树配置

系统时钟通过板载8 MHz的HSE晶振配置为168 MHz运行。在此过程中出现了一个问题:在配置PLL设置后,系统时钟复用器意外地指向了HSE而非PLLCLK,导致SYSCLK显示为8 MHz而不是168 MHz。该问题在代码生成前被发现,并通过在系统时钟复用器中点击PLLCLK进行了修正。

4 — ADC1配置

在模拟 → ADC1 中:

5 — USART1配置

根据RT-Spark原理图,PA9(USART1_TX)和PA10(USART1_RX)被连接到STLink芯片,从而提供一个虚拟串行端口,实现无需额外硬件的免费串行调试。

在连接性 → USART1:

•模式:异步

•波特率:115200

•字长:8位,无奇偶校验,1个停止位

6 — 代码生成

代码已生成。将生成的 main.c 替换为固件后,出现了一个编译警告:

浮点格式支持未启用……请在链接器标志中手动添加 -u _printf_float。

这导致 snprintf() 通过 UART 输出空白内容而非电压值。修复方法是在链接器标志中添加 -u _printf_float:

第三部分 — 软件实现

第3.1节 — 全局变量

三个关键变量被声明为全局变量,以便 CubeIDE 调试器的变量窗口可以在断点处检查它们:

第3.2部分 — ADC_Read() — 单次转换

用于步骤4、8和9。启动一次由软件触发的单次转换,读取结果后,ADC将被干净地停止,再进行电压计算。

电压转换使用 4096.0 作为除数(12 位 ADC 的 2¹² 步),而不是 4095.0。两者之间的差异约为 0.024%,但数学上正确的值是 4096。

第3.3部分 — ADC_Read_Averaged() — 软件平均

用于步骤10、11和12。以每个样本之间间隔10毫秒进行十次独立转换,返回平均值。

取N个样本的平均值可将均方根噪声降低√N倍。对于10个样本,这大约使噪声底噪降低了3.16倍——结果已得到证实。

第3.4部分 — 主循环

while 循环每秒执行一次 ADC_Read(),通过 UART 发送读取结果,并在调试器的断点处暂停。从步骤 10 到 12 转换为 ADC_Read_Averaged() 只需注释掉一个函数调用并取消注释另一个即可。

结果

第4.1部分 — 预闪存万用表测量

在刷写固件之前,使用万用表测量了相关电压,以建立接地参考值。这些基准值对于评估ADC计算值与实际电压的匹配程度至关重要。

第4.2部分 — 调试器断点 — 第4步(标称比例因子)

闪存后,固件以调试模式(F11)运行。在while循环内的HAL_Delay(1000)行上设置了一个断点。当程序遇到断点时,使用CubeIDE中的变量窗口检查计算出的值。

ADC结果在标称增益下与万用表读数非常接近,误差仅为1.08%。对于使用±5%容差电阻且未进行校准的12位ADC而言,这一结果是合理的。

第4.3部分 — 电阻测量与校准(步骤5–7)

R1 和 R2 被从电路中移除,并使用万用表在电阻模式下分别进行测量。

两个电阻的阻值均低于其标称的1 MΩ值,且在±5%的公差范围内。由于R1和R2不相等,实际倍数因子并非精确为2.0:

尺度因子 = (R1 + R2) / R2

= (986,312 + 977,291) / 977,291

= 2.009230618

代码已更新,R1 = 986312.0f,R2 = 977291.0f,启动时缩放因子自动重新计算为2.0092。

使用校准值重新刷写后:

第4.4部分 — 无需平均的重复性(步骤8–9)

断点连续五次触发,且每次暂停时均记录了电压值。

第4.5部分 — 平均读数(步骤10–12)

固件已切换为ADC_Read_Averaged(),该函数以10毫秒间隔采集10个样本并返回平均值。重建并重新烧录后,记录了五次测量数据。

第4.6部分 — USB总线测量(步骤13–14)

CR2032电池已断开连接。电路板的5V USB电源线连接到R1的顶部。使用了相同的电压分压器、接线方式和固件,未作任何修改。

第4.7部分 — 第15步:为什么仅使用电池无法工作

问题在于,当仅使用CR2032纽扣电池供电时,测量系统为何无法正常工作。

核心问题是,ADC的参考电压(VDDA = 3.3V)由电路板上的LDO稳压器提供,而该稳压器需要输入电压高于3.3V才能正常工作。一个3.0V的CR2032电池无法驱动LDO进入稳压状态——VDDA会逐渐接近电池电压。由于固件中源电压sourceVolt被硬编码为3.3f,实际较低的VDDA会导致每次读数都系统性地被低估。系统仍可运行,但测量结果不准确。

额外加分——使用内部VREFINT进行修复:

STM32F407 内部有一个 1.21V 的带隙参考电压(VREFINT),连接到 ADC 的通道 17。通过读取 VREFINT 并将其与已知的 1.21V 值进行比较,即可动态计算出实际的 VDDA:

float vdda_actual = (1.21f * 4096.0f) / (float)vrefint_raw;

volt = ((float)value / 4096.0f) * vdda_actual * scaleFactor;

这使得电压读数能够自动校正,无论实际供电电压如何,从而使系统即使在电池供电下也能报告准确的数值。

结论

所学内容

这个实验让ADC的感觉比仅仅阅读数据手册时更加具体。源阻抗问题——即1 MΩ电阻迫使使用480周期的采样时间——只有在实际操作硬件时才会变得明显。如果采用更短的采样时间,就会持续产生错误读数,而不会有任何错误提示。

校准实验产生了意想不到的结果。人们原本认为,通过使用测量得到的电阻值更新代码可以提高精度,但实际测得的校准误差(1.67%)实际上略高于未校准时的误差(1.08%)。这是因为硬编码的3.3V VDDA在静默地补偿了电阻不匹配的问题,而仅修正比例因子就破坏了这种平衡。这提醒我们,测量误差并不总是相互独立的。

平均化的结果是最令人满意的部分。在固件中使用一个简单的for循环,将峰值到峰值的波动从160毫伏降低到5毫伏——稳定程度提高了32倍——且未增加任何额外硬件。非平均化数据集中2.870V的异常值也清楚地表明,高阻抗节点会拾取瞬态噪声,而平均化能有效抑制这些噪声。

进一步改进

当前基于采样法的实现会在每次转换时阻塞CPU。如果使用DMA将ADC采样数据连续流式写入循环缓冲区,则可在零CPU开销下实现平均计算。此外,启用VREFINT通道并动态计算VDDA,可消除因假设VDDA精确为3.3V而产生的0.7%系统误差——这一修正在电池寿命接近末期时变得越来越重要。

本文编译自hackster.io

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除( 邮箱:macysun@21ic.com )。
换一批
延伸阅读

该项目是一个简单的人体反应计时器,使用RT-Spark开发板和STM32F407ZGT6微控制器构建而成。它用于测量当RGB LED亮起时,人能多快做出反应。

关键字: 微控制器 开发板 LED STM32F407ZGT6

该项目是一个基于微控制器的C语言编写的音频生成器,配备三个按钮,用户可通过按钮播放声音或调节音高。它作为基本GPIO控制和按钮逻辑的实际演示。

关键字: 微控制器 C语言 音频生成器 STM32F407ZGT6

本项目使用RT-Spark开发板和STM32F407ZGT6微控制器构建,主要通过代码延时来产生频率,实现引脚的开关控制、读取按钮输入、保存状态,并通过被动蜂鸣器发出提示音。

关键字: 蜂鸣器 开发板 STM32F407ZGT6

在这次实验活动中,我学习了如何在STM32F407ZGT6微控制器上使用定时器、中断和任务调度。主要目标是理解中断的工作原理、多个任务如何在系统中运行,以及不同的调度方法对任务性能的影响。

关键字: 定时器 中断 微控制器 STM32F407ZGT6

显示屏每100毫秒刷新一次,使时钟更新平稳且准确。一个每毫秒运行一次的定时器中断在后台负责时间记录,确保时钟保持精确。同时,一个外部LED灯每秒闪烁一次,然后逐渐变暗直至关闭,通过PWM实现平滑的淡出效果。

关键字: 数字时钟 开发板 STM32F407ZGT6

该项目使用RT-Spark开发板(STM32F407ZGT6)进行开发。在绿色LED亮起前,会随机生成1到3秒之间的间隔时间。一旦灯亮起,用户应尽快按下按钮。微控制器会计算从按钮中断发生前执行的循环次数,这可作为用户反应...

关键字: 开发板 LED 硬件中断 STM32F407ZGT6

本实验的目的是制作一个电压表,使用RT-Thread RT-Spark开发板(STM32F407ZGT6)来测量CR2032纽扣电池的放电情况。

关键字: ADC 电压表 STM32F407ZGT6

本实验/项目的目标是在基于STM32F407ZGT6的RT-Spark开发板上实现硬件定时器中断以及前台/后台任务调度系统。通过配置两个硬件定时器TIM2和TIM3,以不同速率切换两个内置LED灯;同时在KEY_UP按钮...

关键字: 定时器 开发板 STM32F407ZGT6

本项目的目标是制作一个非常简单的电压表,至少具备良好的精度,并理解模数转换器(ADC)的工作原理。该项目使用了RT-Thread公司生产的RT-Spark(Spark-1)开发板。

关键字: 模数转换器 电压表 RT-Spark 开发板
关闭