完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
3个回答
|
|
一、任务要求
设计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 |
|
|
|
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 |
|
|
|
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乘上对应区间的该斜率,则可求出对应的温度。 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1683 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1582 浏览 1 评论
1013 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
703 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1627 浏览 2 评论
1892浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
675浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
538浏览 3评论
558浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
526浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-4 03:32 , Processed in 0.758215 second(s), Total 50, Slave 44 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号