当前位置: 首页 > news >正文

STM32入门笔记(03): ADC 电阻分压的方式测量电池电压方案(避免浮点运算,改为整数运算)(SPL库函数版)(3)

设计一个用一个3.3V供电的单片机STM32F103C8T6的ADC来测量12V电池的电压的方案。

为了使用一个3.3V供电的STM32F103C8T6单片机的ADC来测量12V电池的电压,您需要设计一个电压分压电路以确保电池电压降到适合ADC输入的范围。STM32F103C8T6的ADC输入范围是0到3.3V,因此您需要将12V电池电压降低到这个范围内。

1. 电压分压电路

为了将12V电池的电压转换到STM32的ADC输入电压范围(0–3.3V),我们可以使用电阻分压器。电压分压器的工作原理是利用两个电阻串联,输出电压为输入电压的一个比例。

2. 分压公式

在这里插入图片描述

电压分压器的输出电压 V o u t V_{out} Vout 由以下公式给出:

V o u t = V i n × R 2 R 1 + R 2 V_{out} = V_{in} \times \frac{R_2}{R_1 + R_2} Vout=Vin×R1+R2R2

其中:

  • V i n = 12 V V_{in} = 12V Vin=12V 是电池电压
  • V o u t V_{out} Vout 是分压后的电压,应该不超过3.3V(STM32的ADC输入范围)
  • R 1 R_1 R1 R 2 R_2 R2 是电阻分压器的两个电阻

3. 计算电阻值

要求 V o u t ≤ 3.3 V V_{out} \leq 3.3V Vout3.3V,那么我们需要设置 V o u t = 3.3 V V_{out} = 3.3V Vout=3.3V 来计算所需的电阻值。

3.3 = 12 × R 2 R 1 + R 2 3.3 = 12 \times \frac{R_2}{R_1 + R_2} 3.3=12×R1+R2R2

解这个方程:

3.3 12 = R 2 R 1 + R 2 \frac{3.3}{12} = \frac{R_2}{R_1 + R_2} 123.3=R1+R2R2

0.275 = R 2 R 1 + R 2 0.275 = \frac{R_2}{R_1 + R_2} 0.275=R1+R2R2

从上面的方程可以得到:

R 2 = 0.275 × ( R 1 + R 2 ) R_2 = 0.275 \times (R_1 + R_2) R2=0.275×(R1+R2)

R 2 = 0.275 × R 1 + 0.275 × R 2 R_2 = 0.275 \times R_1 + 0.275 \times R_2 R2=0.275×R1+0.275×R2

R 2 − 0.275 × R 2 = 0.275 × R 1 R_2 - 0.275 \times R_2 = 0.275 \times R_1 R20.275×R2=0.275×R1

0.725 × R 2 = 0.275 × R 1 0.725 \times R_2 = 0.275 \times R_1 0.725×R2=0.275×R1

R 2 = 0.275 0.725 × R 1 ≈ 0.379 × R 1 R_2 = \frac{0.275}{0.725} \times R_1 \approx 0.379 \times R_1 R2=0.7250.275×R10.379×R1

因此, R 2 R_2 R2 R 1 R_1 R1 的关系是:

R 2 ≈ 0.379 × R 1 R_2 \approx 0.379 \times R_1 R20.379×R1

4. 选择电阻值

假设选择 R 1 = 100 K Ω R_1 = 100K\Omega R1=100KΩ,那么:

R 2 = 0.379 × 100 K Ω = 37.9 K Ω R_2 = 0.379 \times 100K\Omega = 37.9K\Omega R2=0.379×100KΩ=37.9KΩ

您可以选择标准电阻值,例如 R 2 = 38 K Ω R_2 = 38K\Omega R2=38KΩ

5. 计算电压和ADC输入值

通过分压电路,输入电压 12V 被转换为:

V o u t = 12 V × 38 K Ω 100 K Ω + 38 K Ω ≈ 3.3 V V_{out} = 12V \times \frac{38K\Omega}{100K\Omega + 38K\Omega} \approx 3.3V Vout=12V×100KΩ+38KΩ38KΩ3.3V

这样,输出电压就会接近3.3V,适合STM32的ADC输入。

6. 接入STM32F103C8T6的ADC

STM32F103C8T6的ADC输入最大为3.3V,因此分压后的电压 3.3V 可以直接作为ADC的输入。STM32F103C8T6的ADC有10位分辨率,输入范围是0到3.3V,对应的数字值范围是0到1023。

  • 如果输入电压是0V,ADC值为0。
  • 如果输入电压是3.3V,ADC值为1023。

使用ADC读取电压的公式为:

V A D C = A D C v a l u e 1023 × 3.3 V V_{ADC} = \frac{ADC_{value}}{1023} \times 3.3V VADC=1023ADCvalue×3.3V

根据ADC读取的数字值 A D C v a l u e ADC_{value} ADCvalue,可以计算出实际的电压 V A D C V_{ADC} VADC

7. 计算实际电池电压

根据电压分压公式,实际电池电压 V i n V_{in} Vin 可以通过以下公式计算:

V i n = V o u t × R 1 + R 2 R 2 V_{in} = V_{out} \times \frac{R_1 + R_2}{R_2} Vin=Vout×R2R1+R2

如果您读取到的ADC值是 A D C v a l u e ADC_{value} ADCvalue,则输出电压 V o u t V_{out} Vout 是:

V o u t = A D C v a l u e 1023 × 3.3 V V_{out} = \frac{ADC_{value}}{1023} \times 3.3V Vout=1023ADCvalue×3.3V

然后可以计算电池电压:

V i n = V o u t × 100 K Ω + 38 K Ω 38 K Ω V_{in} = V_{out} \times \frac{100K\Omega + 38K\Omega}{38K\Omega} Vin=Vout×38KΩ100KΩ+38KΩ

8. 总结

  • 使用电压分压电路,选择 R 1 = 100 K Ω R_1 = 100K\Omega R1=100KΩ R 2 = 38 K Ω R_2 = 38K\Omega R2=38KΩ
  • 通过STM32F103C8T6的ADC读取分压后的电压,计算实际电池电压。
  • 使用公式 V i n = V o u t × R 1 + R 2 R 2 V_{in} = V_{out} \times \frac{R_1 + R_2}{R_2} Vin=Vout×R2R1+R2 来计算电池电压。

这样,你就可以使用STM32F103C8T6的ADC成功地测量12V电池的电压。

这种方法太多乘法和除法,会增加单片机的负担。

理解您的需求,确实在实际应用中,过多的乘法和除法运算会增加单片机的负担,特别是当运算频繁时,可能会影响系统的性能。为了减轻负担并提高效率,可以采用以下方法来简化计算过程:

优化方案:使用比例系数减少运算

我们可以预先计算一个比例系数,减少运行时的复杂计算。具体来说,我们可以通过以下步骤进行优化:

1. 分压电路设置

在电压分压电路中,已经知道分压后的电压和输入电压之间的关系是线性的。因此,关键是找到一个常数比例系数,计算 ADC 值到电池电压的关系。

从前面的分压公式:

V o u t = V i n × R 2 R 1 + R 2 V_{out} = V_{in} \times \frac{R_2}{R_1 + R_2} Vout=Vin×R1+R2R2

我们知道:

  • V i n = 12 V V_{in} = 12V Vin=12V
  • V o u t = A D C v a l u e 1023 × 3.3 V V_{out} = \frac{ADC_{value}}{1023} \times 3.3V Vout=1023ADCvalue×3.3V
  • R 1 = 100 K Ω R_1 = 100K\Omega R1=100KΩ
  • R 2 = 38 K Ω R_2 = 38K\Omega R2=38KΩ

因此,电池电压 V i n V_{in} Vin 和 ADC 输出值 A D C v a l u e ADC_{value} ADCvalue 之间的关系为:

V i n = V o u t × R 1 + R 2 R 2 = A D C v a l u e 1023 × 3.3 × 100 K + 38 K 38 K V_{in} = V_{out} \times \frac{R_1 + R_2}{R_2} = \frac{ADC_{value}}{1023} \times 3.3 \times \frac{100K + 38K}{38K} Vin=Vout×R2R1+R2=1023ADCvalue×3.3×38K100K+38K

简化这个公式,得到一个比例常数:

V i n = A D C v a l u e × 3.3 × ( 100 K + 38 K ) 1023 × 38 K V_{in} = ADC_{value} \times \frac{3.3 \times (100K + 38K)}{1023 \times 38K} Vin=ADCvalue×1023×38K3.3×(100K+38K)

我们可以计算出这个常数:

3.3 × ( 100 K + 38 K ) 1023 × 38 K ≈ 0.098 \frac{3.3 \times (100K + 38K)}{1023 \times 38K} \approx 0.098 1023×38K3.3×(100K+38K)0.098

所以,电池电压 V i n V_{in} Vin 与 ADC 值之间的关系为:

V i n ≈ A D C v a l u e × 0.098 V_{in} \approx ADC_{value} \times 0.098 VinADCvalue×0.098

2. 减少运算

在这种情况下,您只需要将 ADC 读取的值乘以常数 0.098,计算电池电压。这样避免了频繁的除法和复杂的运算,仅仅依赖一次乘法运算,减少了 CPU 的负担。

3. 优化代码

在 STM32F103C8T6 上的实现会非常简单。例如,假设 ADC 值为 ADC_value,您可以通过以下代码计算电池电压:

float V_in = ADC_value * 0.098;

这只需要一个乘法运算,显著减少了运算负担,并且避免了复杂的乘法和除法链。

4. 进一步的优化:整数计算(可选)

如果您希望进一步优化,避免使用浮点数运算(虽然现代 MCU 的浮点运算通常较为高效),可以将常数转换为整数计算。通过将常数放大 1000 来避免浮点数计算:

例如,常数变为 98(因为 0.098 * 1000 = 98):

V i n = A D C v a l u e × 98 1000 V_{in} = \frac{ADC_{value} \times 98}{1000} Vin=1000ADCvalue×98

然后在代码中实现:

int V_in = (ADC_value * 98) / 1000;

通过这种方式,你可以避免浮点运算,改为整数运算,进一步优化性能。

总结

通过将 ADC 值与预先计算好的常数相乘,您可以简化计算过程,减少乘法和除法运算,减轻单片机的负担。我们还可以选择使用整数运算,进一步提高效率。这种方法对于高效且稳定的电池电压测量非常有效。


????

在这里插入图片描述

您说得对,非常抱歉给您带来困扰。确实,之前的计算结果和我的回答是错误的。现在我们来进行详细的分析和重新计算。

1. 重新解释比例常数的计算

在之前的计算中,我错误地将比例常数当作不受分辨率影响的常量。实际上,比例常数是与 ADC的分辨率(10位或12位)相关的,因为分辨率决定了 ADC 输出的数字范围(最大值)。因此,在计算中,比例常数应考虑到 ADC 的最大数字值(例如,1023 对应 10 位,4095 对应 12 位)。

计算过程

电压分压公式为:

V o u t = V i n × R 2 R 1 + R 2 V_{out} = V_{in} \times \frac{R_2}{R_1 + R_2} Vout=Vin×R1+R2R2

我们已经知道:

  • 输入电压 V i n = 12 V V_{in} = 12V Vin=12V
  • 输出电压 V o u t V_{out} Vout 最大值为 3.3V
  • R 1 = 100 K Ω R_1 = 100K\Omega R1=100KΩ, R 2 = 38 K Ω R_2 = 38K\Omega R2=38KΩ

首先,计算输出电压 V o u t V_{out} Vout 对应的比例系数:

V o u t = 12 V × 38 138 = 3.3 V V_{out} = 12V \times \frac{38}{138} = 3.3V Vout=12V×13838=3.3V

接下来,我们要把 ADC 数值(10位或12位)映射到电压上。比例常数的定义就是通过将 ADC 数值(如 1023 或 4095)映射到电压范围(0-3.3V)来计算电池电压。公式为:

V o u t = A D C v a l u e A D C m a x × V r e f V_{out} = \frac{ADC_{value}}{ADC_{max}} \times V_{ref} Vout=ADCmaxADCvalue×Vref

其中:

  • A D C m a x ADC_{max} ADCmax 是 ADC 的最大数字值(对于 10 位是 1023,12 位是 4095)
  • V r e f = 3.3 V V_{ref} = 3.3V Vref=3.3V 是参考电压

然后,电池电压 V i n V_{in} Vin V o u t V_{out} Vout 之间的关系是通过分压电路来计算的:

V i n = V o u t × R 1 + R 2 R 2 V_{in} = V_{out} \times \frac{R_1 + R_2}{R_2} Vin=Vout×R2R1+R2

2. 重新计算比例常数

对于 12 位 ADC(最大值为 4095):

V i n = ( A D C v a l u e 4095 × 3.3 ) × 100 K + 38 K 38 K V_{in} = \left( \frac{ADC_{value}}{4095} \times 3.3 \right) \times \frac{100K + 38K}{38K} Vin=(4095ADCvalue×3.3)×38K100K+38K

计算比例常数:

3.3 × 138 4095 × 38 ≈ 0.00293 \frac{3.3 \times 138}{4095 \times 38} \approx 0.00293 4095×383.3×1380.00293

对于 10 位 ADC(最大值为 1023):

V i n = ( A D C v a l u e 1023 × 3.3 ) × 100 K + 38 K 38 K V_{in} = \left( \frac{ADC_{value}}{1023} \times 3.3 \right) \times \frac{100K + 38K}{38K} Vin=(1023ADCvalue×3.3)×38K100K+38K

计算比例常数:

3.3 × 138 1023 × 38 ≈ 0.01171 \frac{3.3 \times 138}{1023 \times 38} \approx 0.01171 1023×383.3×1380.01171

3. 总结

根据正确的计算:

  • 对于 12 位 ADC(最大值为 4095),比例常数为 0.00293
  • 对于 10 位 ADC(最大值为 1023),比例常数为 0.01171

因此,比例常数是 与分辨率相关的,并且在不同分辨率下是不同的。之前我给出的 0.098 是错误的,因为它忽略了分辨率的影响。

再次感谢您的耐心!


参考资料

  • [1] STM32入门笔记(02): ADC(SPL库函数版)(1)
  • [2] STM32入门笔记(03): ADC低通滤波(IIR)(SPL库函数版)(2)

相关文章:

  • vue3 获取当前路由信息失败问题
  • OpenCV DNN 模块使用指南
  • ToDesk云电脑各类鼠标有什么区别?虚拟/3D/游戏鼠标等各有利
  • 100道C#高频经典面试题及答案解析:C#程序员面试题库分类总结
  • pfsense部署三(snort各版块使用)
  • 探秘海螺 AI 视频与计算机视觉算法的奇妙融合
  • 95 计费 5% 时间窗口的利用
  • Java 双端队列实战 实现滑动窗口 用LinkedList的基类双端队列Deque实现 洛谷[P1886]
  • 在线运行vscode
  • 图解AUTOSAR_CP_EEPROM_Driver
  • Vue学习笔记集--Vuex
  • Androidstudio实现引导页文字动画
  • 大理石机械构件在设计的时候需要注意些什么?
  • 如何利用<picture>标签实现更灵活的图片展示,应对不同设备和格式需求?
  • 【Scrapy】Scrapy教程8——处理子链接
  • Kafka集成Debezium监听postgresql变更
  • 快速入手-Django项目模版和静态文件(二)
  • 2025年03月10日人慧前端面试(外包滴滴)
  • 随笔(1)
  • 操作系统复习(第五章 输入与输出管理)
  • 强政神鸟——故宫里的乌鸦
  • 常熟银行一季度净赚超10亿增逾13%,净息差较上年末下降0.1个百分点
  • 云南省委常委、组织部部长刘非任浙江省委常委、杭州市委书记
  • 贝壳:网传“深圳贝壳内部通知”不实
  • 拖车10公里收1900元?货车司机质疑收费过高,潮州饶平县市监局已介入
  • 凯撒旅业:2024年营业收入约6.53亿元,同比增长12.25%