- 壹零零单片机©版权所有 2008-2023 粤ICP备17151077号
1、RC 充放电的原理和硬体
我们知道,电阻R 与电容C 充电时间的关系如下图:
注:Rs 为标准电阻 Rt 为热敏电阻
由上图可以看出在RC 充电开始阶段,我们可以认为是近似线性的。
那么:
Tt=K*Rt*C (1)
Ts=K*Rs*C (2)
其中: K 为常数
由(1)、(2)可知充电时间的比例与R 有关,而C 无关。
Rt=(Rs*Tt)/Ts
当然,随环境温度的变化电容C 变化比较大,我们完成标准电阻和热敏电阻对同一电容的充放电在很短的时间
内,因而电容C 变化引起的误差可以消除。为了提高精度,对电容C 的选取也有关系,电容容量不能太小,也不能太大,
与传感器的标称值有关。
下面是我自己写的程序,仅着参考:
///////////////////////////////////////
RC充放电---得到NTC的阻值
电路: p2.3(IOntc)接NTC,P2.4(IOrs)接一个1k的电阻,二电阻一端连接一个10uf的电容到地
思路:
; 放电:
; 二个端口是都输出0,
; 充电:(NTC)
; IOntc 输出 1 ,进行充电,并开始计时,
; 时刻检测IOrs的电平,当 IOrs 端口为高电平的时候,说明充电已经完成,并停止计时,把时间保持给t_ntc_middle和t_ntc_low
; 放电:同上
; 充电:(RS)
; 让 IOntc 输入检测 0 当 IOntc 为高,继续检测直到为0为止
; IOrs 输出 1 ,进行充电,并开始计时,
; 时刻检测 IOntc 的电平,当 IOntc 端口为高电平的时候,说明充电已经完成,并停止计时,把时间保持给t_rs_middle和t_rs_low
; 注:这里所说的计时是根据指令的长短计时的,比如我这里一条指令为0.25US,一周为7跳指令
///////////////////////////////////////
///////////////////////////////////////
.DATA
t_ntc_middle ds 1 ;
t_ntc_low ds 1 ;
t_rs_middle ds 1 ;
t_rs_low ds 1 ;
///////////////////////////////////////
.CODE
///////////////////////////////////////
rc:
///////////////////////////////////////
;放电
///////////////////////////////////////
rc_sub:
bset IOntcm
bset IOrsm
bclr IOntc ;输出 0
bclr IOrs
///////////////////////////////////////
bclr IOrsm ;输入检测 0,为0 说明放电完全
bts0 IOrs
jmp $-1
///////////////////////////////////////
bts0 f_turn ;为谁充电
jmp rc_rs_add
///////////////////////////////////////
;充电:(NTC)
///////////////////////////////////////
rc_ntc_add:
clr t_ntc_low
clr t_ntc_middle
bset IOntcm ;输出 1,充电
bset IOntc
incms t_ntc_low
jmp $+2
incms t_ntc_middle
bclr IOrsm
bts1 IOrs ;检测1,为1 说明充电完成
jmp $-5
bset f_turn
jmp rc_pro90
///////////////////////////////////////
;充电:(RS)
///////////////////////////////////////
rc_rs_add:
bset IOrsm ;输出 1,充电
bset IOrs
incms t_rs_low
jmp $+2
incms t_rs_middle
bclr IOntcm
bts1 IOntc ;检测1,为1 说明充电完成
jmp $-5
bclr f_turn
jmp rc_pro90
///////////////////////////////////////
rc_pro90:
Ret
RC 测温的实现方法是利用电阻R 给电容C 充放电时间来测量温度的(此处的温度感测器为热敏电阻)。
用不同的电阻给电容充放电时间不一样,对RC 测量温度的精度与电阻R 和电容C 的选取有关。我们通常是选用一个标准电阻(随温度变化其阻值变化很小,可忽略不计,通常为高精度的金属膜电阻),它的阻值Rs 与温度传感器在标准大气压下、25℃时的阻值相同。当温度发生变化时,热敏电阻的阻值Rt 发生变化,那么热敏电阻Rt 给电容C 的充放电时间也发生变化。而标准电阻Rs 给电容C 的充放电时间则不发生变化。
以下介绍的这个方法是用没有ADC 功能的芯片来检测模拟量,如采集温度。
1. 温度检测电路图
2. 温度检测步骤
第一步:放电 P85 和 P86设置为高阻态,P87 输出“1” ,电容放电
第二步:测标准电阻 P85 和 P87设置为高阻态,P86 输出“0” ,电容充电,并对充电时间计时 计时功能说明:计时最小时基为 30US,用定时器中断来实现。每 30US中断一次,计时器+1。 计时器长度=16BIT, 高字节的 BIT4 代表溢出位。 所以实际有效长度为 12 位超出则判为溢
出,可能是被测电阻开路和电容短路等故障引起的。
第三步:放电 P85 和 P86设置为高阻态,P87 输出“1” ,电容放电
第四步:测温度电阻 P86 和 P87设置为高阻态,P85 输出“0” ,电容充电,并对充电时间计时 计时功能说明: (同第二步)
第五步:计算电阻比率 计算公式: 电阻比率=温度电阻
说明:在做温度检测并由数码管显示的时候由于一个温度对应一个 AD值,而我们的 AD 值是在一段时间的平均值,很大一部分 AD 在表中是不能够一对一对应的,所以我们只能取隔他最近的 AD,此为 AD 转换后用于查表的顺序程序,这样查表很容易理解,但是也存在很多不足,比如 CPU 在此程序运行周期长等等,当然我会在以后会添加
输入:高位 AD_Data_high,低位 AD_Data_low,
输出:数码管显示的数值 b_room_temp
.data//把 AD 值转换成数值,
ad_new_tab ds 1 ;查表的地址给A(如 0 1 2 74 99 105之类的,比如99就对应的是99度)
ad_old_tab ds 1 ;旧
ad_old_h ds 1 ;旧值的高位
ad_old_l ds 1 ;旧值的低位
ad_new_h ds 1 ;新值的高位
ad_new_l ds 1 ;新值的低位
ad_mean_h ds 1 ;平均值的高位
ad_mean_l ds 1 ;平均值的低位
b_room_temp ds 1 ;显示的数值,是十进制的
////////////////////////////////////////////////////////
.code
ad_change:
////////////////////////////////////////////////////////;;这里可以单独检查其他程序的错误性
/* MOV a, #0x0f ;;
B0MOV AD_Data_High, a ;;ad数据存放
MOV a, #0x00b ;;
B0MOV AD_Data_low, a ;;ad数据存放 */
MOV_ ad_old_tab, #0
check_tab:
b0mov y,#temp_tab$m ;
b0mov z,#temp_tab$l ;
mov a,ad_old_tab ;查表的地址给A(如 0 1 2 74 99 105之类的,比如99就对应的是99度)
b0add z,a ;
b0bts0 fc ;
incms y ;
nop ;
movc ;
mov ad_old_l,a ;低8位存放在temp_l中
mov a,r ;高4位存放在temp_h中
mov ad_old_h,a ;
////////////////////////////////////////////////////////;把旧值赋给新值,这里是为平均那里作准备
mov a,ad_old_l
mov ad_new_l,a
mov a,ad_old_h
mov ad_new_h,a
mov a,ad_old_tab
mov ad_new_tab,a
////////////////////////////////////////////////////////
cjne_ AD_Data_high, ad_new_h, ad_change10;判断高位是否相等,不等跳转到 ad_change10 继续查找
cjne_ AD_Data_low, ad_new_l, ad_change10;如果高位相等,那比较低位,如果不等,跳转到ad_change10
mov_ b_room_temp, ad_new_tab
jmp ad_change_exit ;如果刚好 等于 则把 b_ad_tab 给 b_room_temp, 然后跳出程序
///////////////////////////////////////////////////////// ;如果不等
ad_change10:
cjae2 AD_Data_High,AD_Data_Low,ad_new_h,ad_new_l,ad_change30
///////////////////////////////////////////////////////// 当小
ad_change20:
incms ad_old_tab
jmp check_tab
///////////////////////////////////////////////////////// 当大
ad_change30: ;先判断是否超出范围(00-99),如果在的话查出上一次的值
cjae2 AD_Data_High,AD_Data_Low,#0x0f,#0x17,ad_change70 ;0度的 AD 值为0xf16,防止下于 0度
cjbe2 AD_Data_High,AD_Data_Low,#0x3,#0xd2,ad_change80 ;100 度的AD 值为0x3d3,防止超过 99度
decms ad_old_tab
b0mov y,#temp_tab$m ;
b0mov z,#temp_tab$l ;
mov a,ad_old_tab ;查表的地址给A(如 0 1 2 74 99 105之类的,比如99就对应的是99度)
b0add z,a ;
b0bts0 fc ;
incms y ;
nop ;
movc ;
mov ad_old_l,a ;低8位存放在temp_l中
mov a,r ;高4位存放在temp_h中
mov ad_old_h,a
/////////////////////////////////////////////////////////上次(大)的减去这次(小)的值,得的值再平均一下,再加上现在 Ad 的低位
mov a,ad_old_h ;平均值的高位
sub a,ad_new_h
mov x,a
b0bclr fc
rrcm x
add_ x,ad_new_h
mov_ ad_mean_h, x
mov a,ad_old_l ;平均值的低位
sub a,ad_new_l
mov x,a
b0bclr fc
rrcm x
add_ x,ad_new_l
mov_ ad_mean_l,x
/////////////////////////////////////////////////////////看采样的 AD 值更靠那一边,那个距离短 就取那个值
cjae2 AD_Data_High,AD_Data_Low,ad_mean_h,ad_mean_l,ad_change60
/////////////////////////////////////////////////////////取新值,,比如一个AD为86,80和90的平均值为85,86>85,则选择90
ad_change50: ;(AD大的,温度小的)
mov_ b_room_temp, ad_new_tab
jmp ad_change_exit
/////////////////////////////////////////////////////////取旧值
ad_change60: ;(AD大的,温度小的)
mov_ b_room_temp, ad_old_tab
jmp ad_change_exit
/////////////////////////////////////////////////////////// 小于 00
ad_change70:
mov_ b_room_temp, #0
jmp ad_change_exit
/////////////////////////////////////////////////////////// 大于 99
ad_change80:
mov_ b_room_temp, #99
jmp ad_change_exit
/////////////////////////////////////////////////////////
ad_change_exit:
ret
MCU芯片中时常碰到口线不够用的时候,我们会采用口线复用的方法,将io口同时既作为输入口驱动led灯,同时又作驱动数码管,又将按键也复用下面看下这个图
当我们需要同时点亮led灯,数码管,同时需要判断按键的时候我们就必需合理处理它们之间的关系,在扫描led灯的时候我们可以设定扫描周期为1ms扫描一次,每次扫描led灯的时候,需要初始化led灯的口线状态,扫描完led灯再扫描数码管,设定数码管的扫描周期为3ms,同时需要初始化数码管的口线,为输出模式同时为输出为1。最后是扫描按键,在扫描按键的时候我们设定按键为输入上拉电阻模式。扫描的周期为5ms,由于程序运行时间即短,所以它们之间不会相互影响。
上面的按键公共端接地,连接单片机的这端必需接个10k的上拉电阻,这样按键按下或按键长按的时候不会影响数码管的亮度,或者可以将数码管的公共接地端改为直接接单片机的io口,扫描按键的时候io口输出为0,扫描数码管的时候设定为输入模式,按键按下或长按时,这样不会影响数码管的亮度。