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 Vout≤3.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 R2−0.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×R1≈0.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 R2≈0.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 Vin≈ADCvalue×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×138≈0.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×138≈0.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)