STM32
直播中

贾大林

7年用户 1336经验值
私信 关注
[问答]

怎样去设计一种PT100温度传感器的信号采集电路呢

怎样去设计一种PT100温度传感器的信号采集电路呢?
如何使用嵌入式系统实验板采集外部的温度并显示出来呢?

回帖(3)

曹雪

2021-11-17 11:09:32
一、任务要求
设计PT100温度传感器的信号采集电路,使用嵌入式系统实验板采集外部的温度并显示。
要求:
范围: 20 ~ 80 ℃ ;
精度:与标准仪器比较小于 0.3℃;
30、 50、 70℃三级高温报警。
注:本次设计采用的主板芯片为STM32F103RCT6 
二、硬件设计
1、分析所要使用的PT100温度传感器。
结合有关PT100的资料,可得几个重要知识:
PT100的阻值会随温度的变化而成正比变化(温度越高阻值越大),但阻值变化很小,约等于 0.385Ω/度;
PT100的测温范围是 ﹣200℃ ~ 150℃,且在0℃时,阻值刚好等于100Ω;
PT100的工作电流要小于 5mA;
PT100的阻值虽然随温度的变化而成正比变化,但在不同温度区间内其变化的速率(也就是 K值)不一样。


2、设计PT100驱动电路。
结合所学经验,开始有想法:
如果把PT100当电阻串联在电路中,并用主板上STM32F103RCT6芯片的PA1引脚的ADC功能去读取电压值并进行温度转换,可得出温度,如图1所示:

图1 PT100串联电路测AD法  
但结合资料,这种想法秒速推翻。
常温(25℃)水中的PT100的阻值大概在 109.89 Ω 左右。
假设主板给PT100的供电是标准的 3.3V直流电,并且通过PT100的电流也是其最大 5mA直流电流,那么在此刻,PT100所要分掉的电压约为 109.89 ∗ 0.005 = 0.54945 V
将其根据AD转换的换算公式换算成AD值大概为 0.54945 / 3.3 ∗ 4096 = 681.98 ≈ 682
当温度上升一度,假设PT100的阻值刚好上升了 0.385 Ω,那么其分掉的电压的变动值约等于
0.385 ∗ 0.005 = 0.001925 V
将其根据AD转换的换算公式换算成AD值大概为 0.001925 / 3.3 ∗ 4096 = 2.39 ≈ 2
0.5℃/AD ?好像还不错,但任务要求所设计的PT100电路测温得出的结果,精度要小于 0.3 ℃ 。
0.3 ℃是什么概念?换算为PT100的阻值变化,也就约为 0.1155 Ω ,那么其精度下,PT100变化 0.1155 Ω 阻值,要变化的电压约为,将其根据AD转换的换算公式换算成AD值大概为,连 1个AD值都不到,无法达到这个精度。
所以,这种方法被推翻。


直流电桥(微小电阻变化转微小电压变化)
找到了关键问题所在,就是PT100的随温度的变化而成正比变化太小了,只要把这种变化变大,大到很明显,就解决了问题。
电阻的阻值是没法调大的,只能通过电阻变化导致的电压变化调大,就可以解决变化小的问题。
结合所学知识,只要将微小的电阻变化转化为微小的电压变化,再将微小的电压变化转化为大的电压变化,也就是用直流电桥配上一个放大电路,就很完美地解决这个问题。
如图2为一个直流电桥,R1、R2、R3、R4为该直流电桥的桥臂,且R1、R2、R3、R4皆为固定电阻,U1为该直流电桥的供电电源,U2为该直流电桥的输出电压。

图2 直流电桥  
结合所学的直流电桥知识,可得公式:
U 2 = U 1 ∗ ( R 1 R 1 + R 4 − R 2 R 2 + R 3 )
当 R 1 ∗ R 3 = R 2 ∗ R 4 ,该直流电桥会达到平衡,带入公式可得输出U2的值为 U 2 = U 1 ∗ 0 = 0 V 也就是该直流电桥在平衡状态下,输出电压为 0 V ;
当 R 1 ∗ R 3 ≠ R 2 ∗ R 4时,该直流电桥的平衡会被打破,带入公式可得输出U2的值。
利用直流电桥不平衡状态下会输出电压的特性,应用不平衡电桥之一——单臂电桥,来把微小的电阻变化转化为微小的电压变化。
如图3为一个直流电桥,R1、R2、R3、R4为该直流电桥的桥臂,且R1为可变电阻,R2、R3、R4为固定电阻,且 R 3 = R 4 ,U1为该直流电桥的供电电源,U2为该直流电桥的输出电压。

图3 直流单臂电桥  
该单臂电桥应用于本次设计,R1为PT100,R2为与PT100接近的阻值,这样可以使得在一定(温度)情况下(PT100的阻值等于R2的阻值)电桥可以达到平衡,使得单臂电桥的输出趋近于 0 0 0。
又因为通过PT100的电流不能大于 5 m A ,不然可能会烧坏PT100,所以R3与R4的阻值虽然要取相等,但又要把电桥电流稳定到 5 m A 以下,所以R2和R3要给PT100分流。
本次设计,实验板可接出供电为 3.3 V 3.3V 3.3V和 5 V 5V 5V两种,为了提高精度,也就是提高单臂电桥的输出电压的范围,故选择5V供电。
在先前的计算中,常温( 25 ℃)水中的PT100的阻值大概在 109.89 Ω 左右。假设主板给PT100的供电是标准的 5 V 直流电,并且通过PT100的电流也是其最大 5 m A直流电流,那么在此刻,PT100所占电压最大为 109.89 ∗ 0.005 = 0.54945 V 也就是说R3和R4至少要分掉的电压为 5 - 0.54945 = 4.45055 V
设 R 1 = R 2 = 109.89 Ω,在此刻, 5 V通电的电桥为一个并联电路,可变形为图4所示的电路:

图4 PT100单臂电桥变形图  
又R3和R4至少要分掉 4.45055 V的电压,所以R3和R4的阻值至少为 4.45055 / 0.005 = 0.5 V
又由于本次设计PT100用来测量 20 ℃ ~ 80 ℃ 的水温,水常压下的极端液态也就是 0 ℃ 。
重新计算PT100将分掉的电压,PT100的阻值放入 0 ℃ 的水中,其阻值为 100 Ω 左右。假设主板给PT100的供电是标准的 5 V 直流电,并且通过PT100的电流也是其最大 5 m A 直流电流,那么在此刻,PT100所占电压最大为,在此刻,R3和R4又至少要分掉的电压为 5 - 0.5 = 405 V 所以R3和R4的阻值至少为 4.5 / 0.005 = 900 Ω
所以R3和R4的电阻取值,在理想状态下至少是 900 Ω,但现实中没有刚刚好的阻值可以挑,那就可以选择比该值大的电阻,例如 1 K Ω ,或者是比 1 K Ω 再大的,但是如果选用的电阻太大,则分压过多,依旧导致电桥的输出范围越来越少,最后使得微弱的电压变化变得更加微弱,甚至是不变化了,而且电阻的型号选用金属膜电阻,因为其体积小、噪声低、稳定性好,选它很不错,误差1%可接受。
又因为R2要与PT100趋近,所以对水的温度测量中,温度变化最大为 0 ℃ ~ 100 ℃ ,所以PT100的电阻变化约为 100 Ω~ 139 Ω ,因而要使得电路达到最佳的变化R2为 150 Ω 的可变电阻最佳,又可调精度要非常高,所以要选用精密电阻。
但现实中没有刚刚好阻值的精密电阻可以挑,那就可以选择比该值大一点点的精密电阻,所以3296w不错,多圈式精密可调,例如3296w电位器201( 200 Ω )。
所以本次设计选用的R3和R4为 1 K Ω ,单臂电桥部分的设计完成,如图5所示。

图5 PT100单臂电桥部分  
差分放大电路(放大微小的电压变化)
接下来就是放大电路部分,通过放大电路来实现把电压的微小变化扩大,使用模电所学过的差分放大电路(减法电路),可以把电桥的输出进行减法运算,并增益放大输出。
当电桥平衡,电桥输出电压电势相等,差分放大电路的减法运算的结果为 0 V ;
当电桥的平衡被破坏,电桥输出电压电势拉开,此时差分放大电路的减法运算即可有一定的差值,放大器对其进行放大到合适的差值变动并输出,即当电桥输出最大时,经过差分放大电路,放大到我们所需的最大差值电压 0 V ~ 3.3 V 。如图6为一个差分放大电路:

图6 差分放大电路  
△假设U1 = U2:
①因输入端U1、U2的电流趋近相等,为“虚断”特性,同相输入端为高阻态,其输入电压值仅仅取决于R2、R4分压值。同相输入端的电压可以看作成为输入端比较基准电压;
②因输入端U1、U2的电压趋近相等,为“虚短”特性,进而又推知其为反相输入端,即R1、R3串联分压电路,这是反馈电压。放大器的控制目的是使反馈电压等于基准电压;
③由R1=R2,R3=R4条件可知,放大器输出端OUT只有处于“虚地”状态,即输出端OUT为0V,才能满足反馈电压等于基准电压,这可以由此导出差分放大器的一个工作特征。
△假设U1 ≠ U2,例如U1 》 U2:
①此时因同相输入端电压高于反相输入端,输出端电压往正方向变化,其R1、R3偏置电路中的电流方向为R3→R1;
②由R1、R3的阻值比例可知,R1两端电压降为 ( 同 向 输 入 端 电 压 ) - U 1 (同向输入端电压)-U1 (同向输入端电压)-U1  则R3两端电压降为 [ ( 同 向 输 入 端 电 压 ) - U 1 ] ∗ ( R 3 / R 1 ) [(同向输入端电压)-U1]*(R3/R1) [(同向输入端电压)-U1]∗(R3/R1)  输出端电压为 ( 同 向 输 入 端 电 压 ) + [ ( 同 向 输 入 端 电 压 - U 1 ) ∗ ( R 3 / R 1 ) (同向输入端电压)+[(同向输入端电压-U1)*(R3/R1) (同向输入端电压)+[(同向输入端电压-U1)∗(R3/R1)
③若此时的输入电压差为 U 1 - U 2 U1-U2 U1-U2,输出电压为 X ∗ ( U 1 - U 2 ) X*(U1-U2) X∗(U1-U2)。则该差分放大器的差分电压放大倍数为 R 4 / R 3 = X R4/R3=X R4/R3=X  可得该差分放大电路的放大倍数是 X X X倍。
△假设U1 ≠ U2,例如U1 《 U2:
①此时因同相输入端电压低于反相输入端,输出端电压往反方向变化,其R1、R3偏置电路中的电流方向为R3←R1;
②由R1、R3的阻值比例可知,R1两端电压变为 - U 1 - ( 同 向 输 入 端 电 压 ) -U1-(同向输入端电压) -U1-(同向输入端电压)  则R3两端电压变为 - [ U 1 - ( 同 向 输 入 端 电 压 ) ] ∗ ( R 3 / R 1 ) -[U1-(同向输入端电压)]*(R3/R1) -[U1-(同向输入端电压)]∗(R3/R1)  输出端电压为 - ( 同 向 输 入 端 电 压 ) - ( 同 向 输 入 端 电 压 - U 1 ) ∗ ( R 3 / R 1 ) -(同向输入端电压)-(同向输入端电压-U1)*(R3/R1) -(同向输入端电压)-(同向输入端电压-U1)∗(R3/R1)  结果是一个负电压。
所以故障维修的经验就冒出来了:
如果直接测量R1、R3串联电路的分压状态,只要R1、R3串联分压是成立的,则该差分电路就大致上就是好的,电路的电压放大倍数也由此得出;
只要测量输入电压差(R1、R2左端电压差),再测量输出端电压进行比较,则外围偏置电路的好坏,也会得出明确的结论。
所以公式就推出来了:
其输出公式为: O U T = ( R 2 + R 4 ) ∗ R 3 ∗ U 1 ( R 1 + R 4 ) ∗ R 2 − R 4 ∗ R 2 R 2 OUT=frac{(R2+R4)*R3*U1}{(R1+R4)*R2} -frac{R4*R2}{R2} OUT=(R1+R4)∗R2(R2+R4)∗R3∗U1−R2R4∗R2
在实际应用中,一般使 R 1 = R 2 R1=R2 R1=R2、 R 3 = R 4 R3=R4 R3=R4化简电路,则
其输出公式为: O U T = ( U 1 - U 2 ) ∗ R 4 R 1 OUT=frac{(U1-U2)*R4}{R1} OUT=R1(U1-U2)∗R4
当所前边所设计的电桥与差分放大电路结合起来, U 1 - U 2 U1-U2 U1-U2就为电桥输出的电势差,OUT输入到STM32F103RCT6实验板ADC1口,其最大可读取电压为 3.3 V 3.3V 3.3V,则电势差放大的倍数也就是 R 4 / R 1 R4/R1 R4/R1即可进行计算了。
假设所设计的单臂电桥达到理想状态,最小电桥输出 U 2 = 0 V U2=0V U2=0V,最大电桥输出为 U 2 = M a x B r i d g e U2=Max Bridge U2=MaxBridge O u t Out Out。水温最高为 100 ℃ 100℃ 100℃,最大电桥输出为PT100置于 100 ℃ 100℃ 100℃时电桥的输出。
实测100℃时PT100的阻值约为 138.8 Ω 138.8Ω 138.8Ω,电桥所接输入电压为 5 V 5V 5V, R 3 = R 4 = 1 K R3=R4=1K R3=R4=1K,若要使得测温范围是从 0 ℃ 0℃ 0℃ ~ 100 ℃ 100℃ 100℃,则精密电阻R2的阻值应该调为 0 ℃ 0℃ 0℃时PT100的阻值,也就是 100 Ω 100Ω 100Ω,带入公式可得电桥的输出 U 2 = U 1 ∗ ( R 1 R 1 + R 4 - R 2 R 2 + R 3 ) = 5 ∗ ( 138.8 138.8 + 1000 - 100 100 + 1000 ) = 0.154867963087 V ≈ 0.155 V U2=U1*(frac{R1}{R1+R4}-frac{R2}{R2+R3}) =5*(frac{138.8}{138.8+1000}-frac{100}{100+1000})=0.154867963087V≈0.155V U2=U1∗(R1+R4R1-R2+R3R2)=5∗(138.8+1000138.8-100+1000100)=0.154867963087V≈0.155V
将其放大到ADC1最大可检测电压 3.3 V 3.3V 3.3V,所需的放大倍数为 3.3 / 0.155 ≈ 21.29 ≈ 21 3.3/0.155≈21.29≈21 3.3/0.155≈21.29≈21倍。
但是在现实中, 100 ℃ 100℃ 100℃的开水降温速度很快,所以理想的倍数有点浪费,所以我们只测到 80 ℃ 80℃ 80℃,常温下的冰水升温速度也很快,所以我们最小也只测到 20 ℃ 20℃ 20℃,这就是设计条件的由来吧。
实测 80 ℃ 80℃ 80℃时PT100的阻值约为 131.1 Ω 131.1Ω 131.1Ω,电桥所接输入电压为 5 V 5V 5V, R 3 = R 4 = 1 K R3=R4=1K R3=R4=1K若要使得测温范围是从 20 ℃ 20℃ 20℃ ~ 80 ℃ 80℃ 80℃,则精密电阻R2的阻值应该调为 20 ℃ 20℃ 20℃时PT100的阻值,实测约为 108 Ω 108Ω 108Ω,带入公式可得电桥的输出 U 2 = U 1 ∗ ( R 1 R 1 + R 4 - R 2 R 2 + R 3 ) = 5 ∗ ( 131.1 131.1 + 1000 - 108 108 + 1000 ) = 0.0.2159735882 V ≈ 0.092 V U2=U1*(frac{R1}{R1+R4}-frac{R2}{R2+R3})=5*(frac{131.1}{131.1+1000}-frac{108}{108+1000})=0.0.2159735882V≈0.092V U2=U1∗(R1+R4R1-R2+R3R2)=5∗(131.1+1000131.1-108+1000108)=0.0.2159735882V≈0.092V
将其放大到ADC1最大可检测电压 3.3 V 3.3V 3.3V,所需的放大倍数为 3.3 / 0.092 ≈ 35.87 ≈ 35 3.3/0.092≈35.87≈35 3.3/0.092≈35.87≈35倍。
接下来就要计算电阻取值了,因为 35 ∗ R 1 = 35 ∗ R 2 = R 3 = R 4 35*R1=35*R2=R3=R4 35∗R1=35∗R2=R3=R4,所以可以设R1、R2的阻值为 1 ∗ X Ω 1*XΩ 1∗XΩ,R3、R4的阻值为 35 ∗ X Ω 35*XΩ 35∗XΩ,只要算出 X X X即可算出全部的电阻, X X X为该差分放大电路的输入电阻值,如图7:

图7 35倍差分放大电路  
现在生产的运放,一般其输入阻抗都很高,所以运放输入端电阻选择余地比较大,但又为了减少偏置电流带来的影响,降低噪声和温漂的影响,输入电阻的取值一般选择在 10 k Ω 10kΩ 10kΩ ~ 100 K Ω 100KΩ 100KΩ的区间。
本次设计所使用的运算放大器为LM358,其内部集成结构如图7所示:

图7 LM358集成结构  
LM358增益高(高达 100 d B 100dB 100dB),自带内部频率补偿,低功耗,差模输入电压范围宽(单电源 3 V 3V 3V ~ 30 V 30V 30V),输出电压摆幅大( 0 V 0V 0V ~ V C C VCC VCC)。
使用R1和R2选用 10 K Ω 10KΩ 10KΩ,保证输入稳定的同时也尽可能地保证精度,所以R3和R4选用 350 K Ω 350KΩ 350KΩ。在现实中,有 10 K Ω 10KΩ 10KΩ的金属膜电阻和 300 K 300K 300K的金属膜电阻考虑到实际放大倍数可能不够,因为不是理想电路,所以用电位器503( 50 K Ω 50KΩ 50KΩ)串联 300 K 300K 300K来达到想要的放大倍数。

图8 PT100驱动电路  
电路构思完成,将单臂电桥和差分放大电路合二为一,加上 0.1 u F 0.1uF 0.1uF的电容给输入 5 V 5V 5V电压滤波,搭建成完整的PT100驱动电路,如图8所示。届时调节电路,根据测温范围调节R2至合适,根据电压放大效果调节R9、R10至合适即可。


3、电路焊接
关于电路的焊接,我焊接了三次。
第一次焊接的板子为:“PT100驱动电路V1.0(万用阻值可调实验板)”,其精度特别满足设计要求,与标准温度的差值不超过0.1℃,但其毕竟是实验板,不是成品板,不能作为设计成品;
第二次焊接为:“PT100驱动电路V2.0(测试板)”,其精度基本满足设计要求,与标准温度的差值不超过0.2℃,但毕竟是校验板,还不是成品板,不能作为设计成品;
第三次焊接为:“PT100驱动电路V3.0”,属于成品板,其精度基本满足设计要求,与标准温度的差值不超过0.2℃,可作为设计成品。
具体如下:
①PT100驱动电路V1.0(万用阻值可调实验板)
功能:多固定电阻和可调电位器的焊接,使得每个电阻的电阻值可精确调节,其中R3、R4精确到1K,R5、R6可精确的阻值范围为 10 K 10K 10K ~ 15 K 15K 15K,R7、R8可精确的阻值范围为 250 K 250K 250K ~ 350 K 350K 350K;多排针焊接,可用万用表探查线路中电阻、电压、电流的变化;双色排针,用于标注电路的整体布线。
焊接布局图:

图9 PT100驱动电路V1.0布局图  
焊接效果图:
使用杜邦线连接各个电阻,对电阻阻值进行精确调整;再用杜邦线连接整个电路,完成驱动板的硬件制作,如图11。
②PT100驱动电路V2.0(测试板)
功能:在V1.0所测的数据后,选用更加合适阻值电阻的焊接,其中R3、R4精确到 1 K 1K 1K,R5、R6的阻值为 10 K 10K 10K,R7、R8的阻值为 300 K 300K 300K;多排针焊接,跳线帽完成各元件的连接,可用万用表探查线路中电阻、电压、电流的变化。
焊接布局图:
图12 PT100驱动电路V2.0布局图  
焊接效果图:
图13 PT100驱动电路V2.0(测试板)  
较上一版本,新增电源控制模块,控制PT100驱动板的开关;并且体积明显减小,方便携带。
图14 PT100驱动电路V2.0(测试板)  
③PT100驱动电路V3.0
功能:在V2.0的基础下,双面焊接,提高电路阻值精度和电路布线简洁度;新增可调整放大倍数(30倍~35倍)的5K电位器于底部;去除测试数据用的端口(排针、跳线帽);新增独立电源接口,可单独给该驱动板供电。
焊接布局图:略。
焊接效果图:
图15 PT100驱动电路V3.0  

举报

张海燕

2021-11-17 11:09:58
4、设计PT100驱动电路与STM32F103RC实验板的电气连接思路框图。

图16 PT100驱动板与STM32F103RC实验板的电气连接框图  
5、了解已有蜂鸣器电路与STM32F103RCT6实验板的电路图。

图17 已有蜂鸣器电路与STM32F103RCT6实验板的电路图  
6、了解已有OLED电路与STM32F103RCT6实验板的电路图。

图18 已有蜂鸣器电路与STM32F103RCT6实验板的电路图  
7、实现STM32F103RCT6实验板外设改装。
图19 STM32F103RCT6实验板外设  
表:STM32F103RCT6实验板外设平面接口
[tr]电源IOADC 0~3其余IO4*4矩阵键盘[/tr](3.3V)红Pin1~Pin6OLEDOLED4*4矩阵键盘
(GND)黑Pin7~Pin12OLEDOLED4*4矩阵键盘
(5V)红Pin13~Pin18串口 1~2其余IO4*4矩阵键盘


8、实现PT100驱动电路V3.0与STM32F103RCT6实验板的电气连接(实际电路连接)。
图20 PT100驱动电路V3.0与STM32F103RCT6实验板的电气连接图  
三、软件设计


总代码工程链接下载:PT100测温系统


1、设计PT100测温系统,完成各驱动模块总调配。
为了完成本次的设计目标,需要开始代码的构思,根据任务要求,在本次PT100测温系统的软件设计中,所需要使用的代码模块有:STM32F103RCT6自带的Time内部时钟模块、STM32F103RCT6自带的ADC模数转换模块、主板上的蜂鸣器模块、外设的OLED显示模块。
系统运行前,要先初始化将要使用的这些模块。
初始化后,让所有模块达到“备战”状态。
当PT100驱动电路的输出被实验板上的STM32F103RCT6芯片的ADC1端口(PA1)读取到的时候,芯片自带的ADC模数转换模块会启动,将在ADC1端口(PA1)所读到的电压值用12位的AD值表示出来,并将这表示出来的AD值用液晶屏显示在屏幕上,此时AD值通过计算公式算出该AD时对应的温度,并将温度也一起显示出来,当转化出来的温度达到报警的要求(30℃,50℃,70℃),蜂鸣器鸣叫,即可完成本次设计的要求。
总程序流程图如图21所示:

图21 各驱动模块总调配流程图   主程序“main.c”
//*************************************************************************************** //*** __----~~~~~~~~~~~------___ //*** 。 。 ~~//====。。。。。。 __--~ ~~ //*** -。 _|// |||\ ~~~~~~::::。。。 /~ //*** ___-==_ _-~o~ / ||| \ _/~~- //*** __---~~~。==~||=_ -_--~/_-~|- |\ \ _/~ //*** _-~~ 。=~ | \-_ ‘-~7 /- / ||  / //*** 。~ 。~ | \ -_ / /- / ||  / //*** / ____ / | \ ~-_/ /|- _/ 。||  / //*** |~~ ~~|--~~~~--_  ~==-/ | ~--===~~ 。 //*** ’ ~-| /| |-~~~ __--~~ //*** |-~~-_/ | | ~_ _-~ / //*** /  __ /~ __ //*** _--~ _/ | 。-~~____--~-/ ~~==。 //*** ((-》/~ ‘。|||’ -_| ~~-/ , 。 _|| //*** -_ ~ ~~---l__i__i__i--~~_/ //*** _-~-__ ~) --______________--~~ //*** //。-~~~-~_--~- |-------~~~~~~~~ //*** //。-~~~-- //*** //*** PT100驱动程序V4.0 (2021.05.28) //*** By XingDala.2905469493.All Rights Reserved. //*************************************************************************************** #include “stm32f10x.h” #include “adc.h” #include “OLED.h” #include “PT100INT.h” #include “sound.h” #include “time.h” int main(void) { ADC_init();//ADC初始化 time_init();//时钟初始化 OLED_Init();//OLED初始化 PT100_OLED();//PT100驱动程序显示初始化 sound_init();//蜂鸣器初始化 while(1) { PT100INT();//PT100驱动程序 } } 2、TIME系统内部时钟模块
为流畅运行本次设计,因而选用STM32F103RCT6自带的系统时钟TIM2、TIM3、TIM4、TIM5、TIM6、TIM7。以往会使用高精度的中断函数加以控制,以达到STM32F103RCT6最极限的延时精度,但这里不要求精度,所以不需要使用内部中断来写延时。
其中,TIM2、TIM3、TIM4用来控制蜂鸣器报警系统,TIM5用来控制足以驱动并流畅运行系统各模块的延时(三种时间单位:us、ms、s),TIM6和TIM7用来控制AD采集的速度和滤波频次及速率。

图22 STM32F103RCT6系统内部时钟树 (1)初始化时钟TIM6、TIM7:
在所调用的6个系统时钟中,用来处理AD采集的两个系统时钟TIM6、TIM7是固定的速率,所以要对固定速率的系统时钟进行初始化。
(2)时钟程序:
时钟程序“time.c”
void time_init(void)//初始化 { time6(); time7(); } void time2(unsigned int n)//蜂鸣器响的持续时长 { RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); TIM_TimeBaseInitTypeDef time2; time2.TIM_CounterMode = TIM_CounterMode_Up; time2.TIM_Period = n*10 - 1; time2.TIM_Prescaler = 7200 - 1; TIM_TimeBaseInit(TIM2, & time2); TIM_SetCounter(TIM2,0); TIM_ClearFlag(TIM2,TIM_FLAG_Update); } void time3(unsigned int n)//蜂鸣器关的持续时长 { RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); TIM_TimeBaseInitTypeDef time3; time3.TIM_CounterMode = TIM_CounterMode_Up; time3.TIM_Period = n*10 - 1; time3.TIM_Prescaler = 7200 - 1; TIM_TimeBaseInit(TIM3, & time3); TIM_SetCounter(TIM3,0); TIM_ClearFlag(TIM3,TIM_FLAG_Update); } void time4(unsigned int n)//蜂鸣器音调 { RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); TIM_TimeBaseInitTypeDef time4; time4.TIM_CounterMode = TIM_CounterMode_Up; time4.TIM_Period = n - 1; time4.TIM_Prescaler = 72 - 1; TIM_TimeBaseInit(TIM4, & time4); TIM_SetCounter(TIM4,0); TIM_ClearFlag(TIM4,TIM_FLAG_Update); } void T(unsigned int n,unsigned int x)//延时函数(us、ms、s)eg:T(152,1)表示延时125微秒,T(254,2)表示延时254毫秒 { unsigned int j = 0,k = 0; if(x == 1){j=72;k = 1;}//us if(x == 2){j=7200;k = 10;}//ms if(x == 3){j=7200;k = 10000;}//s RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE); TIM_TimeBaseInitTypeDef time5; time5.TIM_CounterMode = TIM_CounterMode_Up; time5.TIM_Period = n*k - 1; time5.TIM_Prescaler = j - 1; TIM_TimeBaseInit(TIM5, & time5); TIM_SetCounter(TIM5,0); TIM_ClearFlag(TIM5,TIM_FLAG_Update); TIM_Cmd(TIM5, ENABLE); while(TIM_GetFlagStatus(TIM5,TIM_FLAG_Update)==RESET); TIM_Cmd(TIM5, DISABLE); } void time6(void)//1S { RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE); TIM_TimeBaseInitTypeDef time6; time6.TIM_CounterMode = TIM_CounterMode_Up; time6.TIM_Period = 10000 - 1; time6.TIM_Prescaler = 7200 - 1; TIM_TimeBaseInit(TIM6, & time6); TIM_SetCounter(TIM6,0); TIM_ClearFlag(TIM6,TIM_FLAG_Update); } void time7(void)//1ms { RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7, ENABLE); TIM_TimeBaseInitTypeDef time7; time7.TIM_CounterMode = TIM_CounterMode_Up; time7.TIM_Period = 10 - 1; time7.TIM_Prescaler = 7200 - 1; TIM_TimeBaseInit(TIM7, & time7); TIM_SetCounter(TIM7,0); TIM_ClearFlag(TIM7,TIM_FLAG_Update); }  
时钟程序“time.h”
#ifndef _TIME_H__ #define _TIME_H__ void time_init(void); void time2(unsigned int n); void time3(unsigned int n); void time4(unsigned int n); void T(unsigned int n,unsigned int x); void time6(void); void time7(void); #endif
3、AD采集模块
(1)初始化:
配置STM32F103RCT6的ADC1接口的读取模式,打开ADC1的时钟,设置为模拟输入模式,配置单通道扫描模式,配置连续转化模式,定义规则通道的外部触发方式为内部触发,设置数据对齐方式为右对齐,设置ADC模拟通道个数为1,设置被采集的通道为ADC1,使能ADC1,使能ADC1的复位校准,开始ADC1的复位,ADC1的复位和校准结束后,ADC1初始化结束,把LM358的输出接到ADC1上即可准备AD值的读取。

图23 ADC1初始化流程图 (2)AD采集程序:
由于5V电压不稳定,导致输出的AD值也会微微波动,此刻就需要用到程序滤波。
使用时钟,每隔1ms采集一次AD值,并将所采集的AD值加起来,用IN存起来;使用时钟,每隔1s输出一次IN值,并将所输出的IN值除以1000,因为在这1s内采集了1000个AD值,除以1000后,就可以得到1S内平均AD值,也就是滤波。
接着,再利用sprintf把要转换的AD数值格式化为字符串,并用OLED显示屏显示出来,由于IN值1s输出一次,使用滤波后的平均AD值1秒刷新一次。

图24 STM32F103RCT6AD采集程序流程图  
AD采集程序“adc.c”
#include “stm32f10x.h” void ADC_init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1, ENABLE); GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(GPIOA, &GPIO_InitStructure); RCC_ADCCLKConfig(RCC_PCLK2_Div6); ADC_InitTypeDef ADC_InitStructure; ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; ADC_InitStructure.ADC_ScanConvMode = ENABLE; ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfChannel = 1; ADC_Init(ADC1, &ADC_InitStructure); ADC_RegularChannelConfig(ADC1 ,ADC_Channel_1 ,1 ,ADC_SampleTime_1Cycles5); ADC_Cmd(ADC1,ENABLE); ADC_ResetCalibration(ADC1); while(ADC_GetResetCalibrationStatus(ADC1) == SET); ADC_StartCalibration(ADC1); while(ADC_GetCalibrationStatus(ADC1) == SET); }
AD采集程序“adc.h”
#ifndef _ADC_H__ #define _ADC_H__ void ADC_init(void); #endif

1 举报

关睿

2021-11-17 11:10:02
4、蜂鸣器响应模块
(1)初始化:
打开蜂鸣器引脚所在的时钟,设置其为推挽输出模式。

图25 蜂鸣器响应模块初始化流程图 (2)蜂鸣器响应:
TIM2控制蜂鸣器通电的时长,TIM3控制蜂鸣器断电的时长,TIM4控制蜂鸣器发声的音调(频率),以此来调出万能的警报声音。当温度达到报警温度,触发蜂鸣器响应程序,程序流程图如图22所示:

图26 蜂鸣器响应模块报警主程序流程图  
蜂鸣器鸣响程序“sound.c”
#include “stm32f10x.h” #include “sound.h” #include “time.h” void sound_init(void)//初始化蜂鸣器 { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); GPIO_InitTypeDef FMQ; FMQ.GPIO_Pin = GPIO_Pin_8; FMQ.GPIO_Speed = GPIO_Speed_50MHz; FMQ.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOB, &FMQ); GPIO_ResetBits(GPIOB, GPIO_Pin_8); } void FMQ_T(void)//蜂鸣器响 { TIM_Cmd(TIM2, ENABLE); while(TIM_GetFlagStatus(TIM2,TIM_FLAG_Update) == RESET) { TIM_Cmd(TIM4, ENABLE); while(TIM_GetFlagStatus(TIM4,TIM_FLAG_Update) == RESET) { GPIO_ResetBits(GPIOB, GPIO_Pin_8); } TIM_ClearFlag(TIM4,TIM_FLAG_Update); while(TIM_GetFlagStatus(TIM4,TIM_FLAG_Update) == RESET) { GPIO_SetBits(GPIOB, GPIO_Pin_8); } TIM_ClearFlag(TIM4,TIM_FLAG_Update); TIM_Cmd(TIM4, DISABLE); } TIM_ClearFlag(TIM2,TIM_FLAG_Update); TIM_Cmd(TIM2, DISABLE); } void FMQ_F(void)//蜂鸣器关 { TIM_Cmd(TIM3, ENABLE); while(TIM_GetFlagStatus(TIM3,TIM_FLAG_Update) == RESET) { GPIO_ResetBits(GPIOB, GPIO_Pin_8); } TIM_ClearFlag(TIM3,TIM_FLAG_Update); TIM_Cmd(TIM3, DISABLE); } void sound1(void)//蜂鸣器鸣叫,节奏调节 { time2(100);//响的持续时长 time4(100);//音调 FMQ_T();//蜂鸣器开始响一段时间 time3(100);//关的持续时长 FMQ_F();//蜂鸣器关闭一段时间 time2(100);//响的持续时长 time4(100);//音调 FMQ_T();//蜂鸣器开始响一段时间 GPIO_ResetBits(GPIOC, GPIO_Pin_13);//蜂鸣器关 }   
蜂鸣器鸣响程序“sound.h”
#ifndef _SOUND_H__ #define _SOUND_H__ void sound_init(void); void FMQ_T(void); void FMQ_F(void); void sound1(void); #endif
5、OLED显示模块
(1)初始化:
打开OLED接口的时钟,推挽输出OLED两条信号线(SCL、SDA),并且一块拉高,延时200ms;关闭显示,设置时钟分频因子和震荡频率([3:0]分频因子、[7:4]震荡频率),设置驱动路数为默认0X3F(1/64),设置显示偏移默认为0,设置显示开始行 [5:0],电荷泵设置为bit2,设置内存地址模式页地址模式,段重定义设置为bit0:0,0-》0;1,0-》127,设置COM扫描方向为普通模式,设置COM硬件引脚配置为[5:4]配置,对比度设置为默认0X7F最亮,设置预充电周期为[3:0]、PHASE 1、[7:4]、PHASE 2,设置VCOMH 电压倍率为[6:4] 0.83*3.3,开启全局显示,设置显示方式为正常,开启显示,清屏,OLED初始化完成。

图27 OLED初始化流程图 (2)显示:
ZFC(0,0,“abc254!”);//在坐标(0,0)显示字符串abc254! ZF(0,0,‘0’);//在坐标(0,0)显示字符0 WZ(0,0,2,3);//在坐标(0,0)显示第3页的第2个汉字 TP(0,0,128,64,2);///在坐标(0,0)显示第二张图片,显示的图片范围为x:0~128,y:0~64 4、PT100系统总驱动模块
PT100的阻值是随着温度的变化而变化,在对各标准温度下温度AD采集的结果可以得出,AD值随着温度的升高而升高,其线性关系近乎是一条直线,但这条直线有略微的弯曲,所以需要进行大量的AD采集进行数据拟合。
本次设计计划使用100个AD采集数据,也就是100个温度区间,但一百个区间很多,不可能用计算器一个一个计算,所以这一百个区间(温度-AD)将被分别放入两个数组(一个数组放温度值,一个数组放AD值,两两对应),再在程序中用AD比对,找出此刻LM358传来的AD在哪个区间,再用固定的公式算出每个AD的温度是多少 该 区 间 温 度 变 化 / 该 区 间 A D 变 化 = 每 个 A D 是 多 少 温 度 该区间温度变化/该区间AD变化=每个AD是多少温度 该区间温度变化/该区间AD变化=每个AD是多少温度  再乘以此刻测出的实时AD值,算出准确的温度。
又由于供电不稳定,每次供电接口的微微位移,都会使得V供电偏大或者偏小,间接导致同温度下,LM358输出的AD与AD采集时的电压不一致,所以在AD值进入计算前,先借助标准仪表对比同温度下与AD采集时的AD偏移了多少AD,对程序中的AD进行误差加减,把微微偏移的AD曲线平移到AD采集时的曲线。
PT100测温系统程序“PT100INT.c”
#include “stm32f10x.h” #include “adc.h” #include “SSA.h” #include “time.h” #include “OLED.h” unsigned int wucha = 0;//误差偏移修正 void PT100INT(void) { unsigned int Dout = 0;//清除AD数据缓存 unsigned int IN = 0;//采集AD前清零 TIM_Cmd(TIM6, ENABLE);//1s计时准备 while(TIM_GetFlagStatus(TIM6,TIM_FLAG_Update) == RESET)//开始1s计时,1s内采集1000次AD并软件滤波 { TIM_Cmd(TIM7, ENABLE);//1ms计时准备 while(TIM_GetFlagStatus(TIM7,TIM_FLAG_Update) == RESET)//开始10ms计时,采集100次 { ADC_SoftwareStartConvCmd(ADC1, ENABLE);//AD采集准备 while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);//AD采集 Dout = ADC_GetConversionValue(ADC1);//AD数据缓存 } TIM_ClearFlag(TIM7,TIM_FLAG_Update);//10ms结束,定时器清零,为下一次计时10ms做准备 TIM_Cmd(TIM7, DISABLE);//关闭10ms定时器 IN = IN + Dout;//AD累加,为滤波做准备 } TIM_ClearFlag(TIM6,TIM_FLAG_Update);//1s结束,定时器清零,为下一次计时1s做准备 TIM_Cmd(TIM6, DISABLE);//关闭1s定时器 IN = (IN / 1000)+wucha;//滤波 PT100show_AD(IN);//AD值显示 //AD采集值,请从低温到高温排 unsigned int TEMP[]= //温度值 { 26,27,28,29,30,31,32,33,34,35, 36,37,38,39,40,41,42,43,44,45, 46,47,48,49,50,51,52,53,54,55, 56,57,58,59,60,61,62,63,64,65, 66,67,68,69,70,71,72,73,74,75 }; unsigned int AD[]= //AD值 { 937, 977,1017,1057,1098,1144,1101,1240,1289,1332, 1378,1423,1474,1525,1560,1610,1661,1706,1753,1786, 1847,1902,1949,1984,2048,2100,2188,2231,2275,2322, 2372,2420,2465,2511,2554,2602,2652,2701,2747,2802, 2841,2886,2937,2994,3037,3065,3139,3164,3194,3347 }; unsigned int Temp = 0;//温度值清零 if(IN 《 937)//温度超过测量范围,使用最后测量范围的K值进行计算 { Temp = IN*10*TEMP[1]/AD[1];//动态拟合比对,动态显示温度 } else if(IN 》= 937 && IN 《= 3347)//温度在测量范围内,开始测温 { unsigned int a=0; while(Temp == 0)//算出温度后跳出 { if(IN 》 AD[a])//按区间比对 { Temp = IN*10*TEMP[a]/AD[a];//动态拟合比对,动态显示温度 } a++;//AD采集区间切换 } } else if(IN 》 3347)//温度超过测量范围,使用最后测量范围的K值进行计算 { Temp = IN*10*TEMP[49]/AD[49];//动态拟合比对,动态显示温度 } PT100show_Temp(Temp);温度显示 }
PT100测温系统程序“PT100INT.h”
#ifndef _PT100INT_H__ #define _PT100INT_H__ void PT100INT(void); #endif
最终结果,所测试的温度与标准仪表相差 0.1 ℃ 0.1℃ 0.1℃ ~ 0.2 ℃ 0.2℃ 0.2℃。
图28为PT100测温系统的测温显示效果:
当前面板所显示的AD值每1s刷新一次;

所显示的温度值每1s刷新一次;
警报未响起时蜂鸣器状态显示“静音”,警报响起时蜂鸣器报警鸣叫,且状态显示“鸣响”,当报警声响三遍后,报警声停止,蜂鸣器报警系统进入睡眠状态,当温度继续上升超过报警温度1℃时,蜂鸣器报警系统又会进入预备触发状态,等待报警温度的再次达到报警温度值;
最底下的图案为系统运行指示灯,当系统正在(流畅)运行时,该图标是动态显示的动画状态,最右边的方形图标闪烁。
四、调试

1、电路调试
在设计电桥中,一开始是把 5 V 5V 5V接在PT100与精密电阻间,把GND接在两个 1 K 1K 1K中间,模拟软件测试没有问题,但实际电路中会出现问题,LM358的2号引脚和3号引脚不能承受过大的电压,最终导致LM358的输出为爆输出状态(标准温度下超过 3.3 V 3.3V 3.3V),但在LM358的芯片手册上提到这两个引脚所能接受的电压远远不止这么少,百思不得其解。
所以在设计中将GND接在PT100与精密电阻间,把 5 V 5V 5V接在两个 1 K 1K 1K中间,让 1 K 1K 1K去分掉电压,模拟软件测试也是没有问题,最终LM358的2号引脚和3号引脚所承受的电压降到了 0.5 V 0.5V 0.5V以下,输出也和模拟差不多,电路调试成功。
2、放大倍数调试

根据实测,实物与理论出现预料范围内的偏差(电桥输出比理论偏大,放大倍数比理论偏小),通过串联电位器(由于元件不足,没有过大的电位器),勉强把放大倍数调整到了32倍。
3、AD采集:

此时刚好测出一百个温度区间内的AD值(当温度降的慢AD变化率小的时候,选最大温度区间为 1 ℃ 1℃ 1℃,;但当温度降得快,AD变化很大的时候,选用最小温度区间为 0.5 ℃ 0.5℃ 0.5℃,多次高温采样),其折线图25所示。

图29 AD采集  
一百个区间已出,每个区间的斜率 K = 温 度 变 化 / A D 变 化 = 每 个 A D 是 多 少 温 度 K= 温度变化/AD变化=每个AD是多少温度 K=温度变化/AD变化=每个AD是多少温度  很容易可以求出来,只要把AD乘上对应区间的该斜率,则可求出对应的温度。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分