使用单片机非AD方式实现温度测测量

最近在一个新的开发项目中,因一个需要一个简小的外联功能模块,考虑到体积尺寸和单一的功能需求,故而思琢采用性价比较高的STC51单片机。项目需求中需要用到温度测量,但是后来发现,自身未带AD口,无奈,遂想到之前在图书馆借阅的老外著作的《模拟电路》中有讲解到使用GPIO+TIMER+RC实现温度测量的原理步骤,当时觉得就蛮新奇的,在此之前也听闻过网友使用此法实现了温度测量,效果说也不错,于是就决定尝试使用该方法。

https://blog.csdn.net/weixin_43940932/article/details/84783036?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-4.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-4.control

原理如下:
已知电容充电放电时间计算公式:
设,V0 为电容上的初始电压值;
Vu 为电容充满终止电压值;
Vt 为任意时刻t,电容上的电压值。
则,
Vt=V0+(Vu-V0)* [1-exp(-t/RC)] -----1
如果,电压为E的电池通过电阻R向初值为0的电容C充电
V0=0,充电极限Vu=E,
故,任意时刻t,电容上的电压为:
Vt=E*[1-exp(-t/RC)] -----2
t=RCLn[E/(E-Vt)] -----3
如果已知某时刻电容上的电压Vt,根据常数可以计算出时间t。

分别计算两路的充电时间Tntc;Tref;
据公式3有:Rntc=Rref*(Tntc/Tref)

然后根据手册查表即可得到当前温度。

可能当时记漏啦,后来PCB样板回来后,发现我画的原理,使用的是两个GPIO口,如图1,
在这里插入图片描述
但是后来翻看那本书,上面使用的是三个GPIO口,如图2。
在这里插入图片描述
为了保证先实现,遂在PCB上找一个空GPIO引脚飞一下。按照书上的步骤,最后总算实现了对环境温度的测量,无论是精度,稳定度,效果还是不错的。

在实现完这个之后,我就想了想,应该是可以用两个GPIO口实现温度测量,因为我那个漏掉的GPIO口,按书上逻辑是直接用来给电容C直接充放电通道的。
但是实际应该也可以使用上面两个自身的GPIO口就可以进行充放电动作。故而我更改了一下思路步骤,嘿嘿,最后还真实现啦,效果跟三线制一样的效果。

当然该方法可以在AD资源匮乏的情况下使用,如有AD建议使用AD采集方式更为可靠。

具体实现代码,可参阅如下:
两线制法

//-----two wire
#define Rntc_CAP_DISCHARGE()  {P34_PP_MODE();GP1=0;Delay1ms(5);}  //GP1 //use for charging and discharging port//the capitor discharge equel to zero;
#define Rntc_CAP_CHARGE()     {P34_PP_MODE();GP1=1;}

#define Rref_CAP_DISCHARGE()  {P35_PP_MODE();GP2=0;Delay1ms(5);} 
#define Rref_CAP_CHARGE()     {P35_PP_MODE();GP2=1;}

void two_element_charge_action()
{
        ntc_charge_over_flag=0;//NTC路 充电完成标志置初值0
      ntc_charge_t=0;//NTC路 充电时间置初值0
      P35_HZ_MODE();//GPIO设置为高阻抗模式
        Rntc_CAP_DISCHARGE();//NTC路 电容放完电
      Rntc_CAP_CHARGE();//对电容充电
      while(0==GP2)//开启计时并检测GPIO电平的翻转
        {
            T0_ON();
        }
      T0_OFF();    //关闭计时 
    ntc_charge_over_flag=1;//充电完成标志置位
/
        ref_charge_over_flag=0;//REF路 充电完成标志置初值0
        ref_charge_t=0;//REF路 充电时间置初值0
        P34_HZ_MODE();//GPIO设置为高阻抗模式
        Rref_CAP_DISCHARGE();//REF路 电容放完电
      Rref_CAP_CHARGE();//对电容充电
      while(0==GP1)//开启计时并检测GPIO电平的翻转
        {
            T0_ON();
        }
      T0_OFF();    //关闭计时         
        ref_charge_over_flag=1;        //充电完成标志置位
}
 

三线制法

//-----three wire 
#define CAP_INIT_CLEAR()    {P12_PP_MODE();GP0=0;Delay1ms(1);}//set the GPIO mode as PP;//as discharge channal of the capitor 
#define NTC_TO_CAP_CHARGE() {P34_PP_MODE();GP1=1;}//the capitor start to charge
#define REF_TO_CAP_CHARGE() {P35_PP_MODE();GP2=1;}
void three_element_charge_action(void)//

        ntc_charge_over_flag=0;//NTC路 充电完成标志置初值0
          ntc_charge_t=0;//NTC路 充电时间置初值0
        P34_HZ_MODE();//GPIO设置为高阻抗模式
      P35_HZ_MODE();//GPIO设置为高阻抗模式
      CAP_INIT_CLEAR() ;//电容先放完电
        P12_HZ_MODE();//GPIO设置为高阻抗模式
      NTC_TO_CAP_CHARGE();//对电容充电
        while(0==GP0)//开启计时并检测GPIO电平的翻转
        {
             T0_ON();
        }
        T0_OFF();    //关闭计时
        ntc_charge_over_flag=1;//充电完成标志置位
ntc resistor test over!
        ref_charge_over_flag=0;//对比路 充电完成标志置初值0
        ref_charge_t=0;//对比路 充电时间置初值0
        P35_HZ_MODE();//GPIO设置为高阻抗模式
        P34_HZ_MODE();//GPIO设置为高阻抗模式
        CAP_INIT_CLEAR() ;//电容先放完电
        P12_HZ_MODE();//GPIO设置为高阻抗模式
        REF_TO_CAP_CHARGE();//对电容充电
        while(0==GP0)//开启计时并检测GPIO电平的翻转
        {
            T0_ON();            
        }    
        T0_OFF();    //关闭计时
        ref_charge_over_flag=1;        //充电完成标志置位
        P35_HZ_MODE();//GPIO设置为高阻抗模式
//ref resistor test over!    
}
 

主函数

void main(void)
{
    EA=0;
    P37_PP_MODE();
    P36_PP_MODE();
    timer0_Init();
    timer1_Init();
    EA = 1;
    while(1)
    {
        two_element_charge_action();
//        three_element_charge_action();
        
    }

}


定时时基配置

//
// t_base=(2^16-X)/f0/12(us)
//set:f0=12MHz
//x=65535  t_base=1us;
#define T0_ON()  {TR0 = 1;ET0 =1;}
#define T0_OFF() {TR0 = 0;ET0 =0;}
void timer0_Init(void) //use for charge timer
{
    TMOD |= 0x00;                 //模式0
    TL0 = 0xff;                
    TH0 = 0xff;
    T0_OFF();    
}
//
// t_base=(2^16-X)/f0/12(us)
//set:f0=12MHz
//x=65535  t_base=1ms;
#define T1_ON()  {TR1 = 1;ET1 =1;}
#define T1_OFF() {TR1 = 0;ET1 =0;}
void timer1_Init(void)
{
    TMOD|= 0x00;                 //模式0    
    TL1 = 0x66;                 
    TH1 = 0xfc;
    T1_ON();
}
 

定时中断处理


void TM0_Isr() interrupt 1 
{

    if(0==ntc_charge_over_flag)  ntc_charge_t++;
    if(0==ref_charge_over_flag)  ref_charge_t++;
}


void TM1_Isr() interrupt 3
{
  seg_fresh_t++;
    if(0==seg_fresh_t%5)//
    {
        seg_fresh_t=0;
        if(ntc_charge_over_flag&&ref_charge_over_flag)
        cur_temp_equel_resistor_val=(float)(ntc_charge_t*1.0/ref_charge_t*1.0)*10.0;//10.0即Rref的阻值(KR)
        cur_temp_val=Find_Tab(cur_temp_equel_resistor_val,tempH_tab,69);
        DisplayScanHc595();
     }
}
 

注意这个是NTC热敏电阻datasheet中自带的R-T对应表,不同于AD采集方法变换后的ADC-R对应表

const float xdata tempH_tab[] = {
//0            1           2         3          4           5           6           7       8          9    
32.116,30.570,29.105,27.716,26.399,25.150,23.965,22.842,21.776,20.764,
//10        11     12         13         14         15         16         17         18         19    
19.783,18.892,18.026,17.204,16.423,15.681,14.976,14.306,13.669,13.063,
//20   21    22    23    24   25   26   27    28    29
12.487,11.939,11.418,10.449,10,9.571,9.164,8.775,8.405,
//30    31    32    33    34   35    36     37   38    39  
8.052,7.716,7.396,7.090,6.798,6.520,6.255,6.002,5.760,5.529,
//40    41    42    43    44    45    46    47   48    49
5.309,5.098,4.897,4.704,4.521,4.345,4.177,4.016,3.863,3.716,
//50   51     52   53     54    55    56    57    58   59
3.588,3.440,3.311,3.188,3.069,2.956,2.848,2.744,2.644,2.548,
//60   61     62    63    64   65    66   67   68   69
2.457,2.369,2.284,2.204,2.126,2.051,1.980,1.911,1.845,1.782,
};
 

相关变量定义及声明

float cur_temp_equel_resistor_val=0;
unsigned int ntc_charge_t=0; //ntc resistor  charge time 
unsigned int ref_charge_t=0; //ref resistor  charge time 
unsigned int seg_fresh_t=0;//segment fresh time
bit ntc_charge_over_flag=0;
bit ref_charge_over_flag=0;
 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值