- 打卡等级:偶尔看看III
- 打卡总天数:39
- 最近打卡:2025-10-15 18:27:22
已绑定手机
中级会员
- 积分
- 255
|
发表于 2025-10-2 07:18:34
|
显示全部楼层
第二十集 ADC_NTC测温,学习笔记
一.ADC的用途分析
虽然ADC只能测量电压,但是通过配合外部的传感器,就可以实现多种的信号检测!
NTC(Negative Temperature Coefficient)是指随温度上升电阻呈指数关系减小、具有负温度系数的热敏电阻现象和材料。该材料是利用锰、铜、硅、钴、铁、镍、锌等两种或两种以上的金属氧化物进行充分混合、成型、烧结等工艺而成的半导体陶瓷,可制成具有负温度系数(NTC)的热敏电阻。其电阻率和材料常数随材料成分比例、烧结气氛、烧结温度和结构状态不同而变化。现在还出现了以碳化硅、硒化锡、氮化钽等为代表的非氧化物系NTC热敏电阻材料。
Rt = RT0*EXP(Bn*(1/T-1/T0))
式中RT、RT0分别为温度T、T0时的电阻值,Bn为材料常数.陶瓷晶粒本身由于温度变化而使电阻率发生变化,这是由半导体特性决定的。
要想做一个电压表,就必须要有电压基准,如果直接用锂电池供电,电压基准会变化。如果加额外的电源芯片会浪费成本,故而可以用内部1.19V直接反推出电源电压!
二.ADC采集NTC换算内温度
P5.1推挽输出,10K电阻,加NTC
用P1.3引脚进行采集,设置为高阻输入
R2/(R1+R2)
端口初始化,用ISP的端口配置功能,
在main.c中输入
#include ”adc.h”
Sys_init(); //系统初始化
usb_init(); //USB CDC接口配置
IE2 |= 0x80; //使能USB中断
Timer0_Init(); //定时器初始化
Init_595();
Timer1_Init();
ADC_Init(); //在EA= 1之前
在 while中增加
Task_Pro_Handle_Callback(); //执行功能函数
SEG_Show_U32(Temp+Cal(ADC_Read(3))); //P1.0,且设为高阻状态
在adc.c中,输入
(由ISP生成)
#include "adc.h"
void AdcSetRate (void) //50KSPS@24.000MHz
{
ADCCFG &= ~0x0f;
ADCCFG |= 0x04; //SPEED(4)
ADCTIM = 0xbf; //CSSETUP(1), CSHOLD(1), SMPDUTY(31)
}
void ADC_Init (void)
{
P5M0 |= 0x02; P5M1 &= ~0x02; //P51推挽输出
P1M0 &= ~0x08; P1M1 |= 0x08; //P13高阻输入
P51 = 1;
//1.初始化IO为高阻输入
P1M0 &= ~0x01;
P1M1 |= 0x01;
//2.初始化ADC速度
AdcSetRate();
//3.对齐模式,右对齐
ADCCFG |= 0x20;
//4.打开ADC电源
ADC_POWER = 1;
}
u16 code Temp_Table[]=
{
140,
149,
159,
168,
178,
188,
199,
210,
222,
233,
246,
259,
272,
286,
。。。。,
};
u16 Temp+Cal(u16 adc) //返回结果是放大了10倍后的数值
{
u8 j = 0;
u16 k = 0;
u16 min; //最小值
u16 max; //最大值
u16 i; //温度
adc = 4096 - adc; //得到当前的adc数值
if( adc < Temp_Tab[0] ) //温度最小值检测
return 0xfffe;
if( adc > Temp_Tab[160] ) //温度最大值检测
return 0xfffF;
min = 0;
max = 160;
for( j=0;j<5;j++ ) //实现5次二分法查询
{
k = (min + max)/2;
if( adc <= Temp_Tab[k] )
max = k;
else
min = k;
}
if( adc == Temp_Tab[min] )
i = min *10; //(20*10 - 400)/10 = -20.0
else if( adc == Temp_Tab[max] )
i = max * 10;
else //50 -51之间
{
while(min <= max )
{
min++;
if( Temp_Tab[min] == adc )
{
i = min * 10;
break;
}
else if( adc < Temp_Tab[min] ) //超过这一档的温度的adc
{
min --;
i = Temp_Tab[min]; //上一档的adc数值记录下来
j = Temp_Tab[min+1] -Temp_Tab[min] ; //两档之前的差值2-8
j = ( adc - i )*10/j;
i = min*10+j;
break;
}
}
}
return i;
}
u16 ADC_Read(u8 no)
{//参考手册
u16 adcval = 0;
ADC_CONTR &= 0Xf0; //清空低四位
ADC_CONTR |= no;
ADC_START = 1; //启动ADC转化
_nop_();
_nop_();
while( !ADC_FLAG ); //等待采集完成
ADC_FLAG = 0; //手动清空
adcval = (((u16)ADC_RES) << 8) + (ADC_RESL); //获取到最终的ADC数值
return adcval;
}
在adc.h中输入
#ifndef __ADC_H
#define __ADC_H
#include "config.h" //调用头文件
void ADC_Init(void);
u16 ADC_Read(u8 no);
u8 ADC_KEY_READ( u16 adc );
u16 Temp+Cal(u16 adc);
#endif
在task.c中增加一个任务
(0,1,1,SEG-Task());
编译下载,运行正常,至此,任务1完成,实际温度=显示值-40
三.使用ADC15测量内部1.19V信号源,反推电源电压
锂电池越来越低,此时就要用到15通道的基准值
仅把main.c中SEG_Show_U32改一下
SEG_Show_U32 ( (4096 * 119 / (u32) ADC+Read ( 15 ) ) ); //实际显示330,正确
课后小练
简易温度检测器:
1.前位数码管显示当前的电压
2.后四位数码管显示当前温度
3.按下设置键设置报警温度,后四位以1秒的闪烁频率显示当前的高温预警温度数值,可通过几个按键修改这个数值,按确认键退出
4.如当前温度超过这个预警温度,后四位数码管显示“- - - -”,恢复正常后显示当前温度
|
|