1. 单片机型号:STC15F2K32S2,NTC电阻,内部自带ADC检测ADC,
2. 怎么样把ADC值转为温度是最容易让大家不知从何下手,有查表等思路,但是我自己分析的不是查表,查表速度慢,单片机内存也只有那么大,我选择的方法是ADC值和温度直接联系,我下午特意去奶茶店找了一点冰块,来测了几十个点的温度,然后建立ADC值与温度的关系,参考温度是胜利万用表的温度。
注意:这个地方测ADC值不要测一段连续的温度的ADC值(要分点测试比如,16,18,20等 ),相信你有更好的办法,我测高温度是用热水测得,低温度是在奶茶店找的冰测得。
3.我们用的分析软件是新建 Excel 表
注意:这个数据曲线不是随便乱选的,你测了那么多点,你要看经过的点最多的,当然不可能是性线关系,这个要根据你自己的数据去分析,你公式出来了,然后用C语言可以把这个每一个温度的ADC值算出来,然后用NTC电阻测几个温度对比一下我们得出来公式的。我的参考温度还是是胜利万用表测出来的温度。
如以上还有不懂的,可以加我QQ:2681075556
/* ***************************************************** */
// 工 程 : my
// 文件名 : main.c
// 处理器 : STC
// 编译环境 : Keil4 C51
// 系统时钟 : 内部自带22.1184MHZ
// 版 本 : V1.0
// 生成日期 : 2017-005-02
// 修改日期 :
// 简单描述 : 八路NTC温度
// 开发人才 :Made in Liu Ren fu(大白菜)
/* ***************************************************** */
#include <STC15F2K60S2.H>
#include "adc.h"
#include "lcd12864.h"
#include "uart.h"
#include "math.h"
#include "key.h"
/******************全局变量***********************/
u16 tab[8]={0}; //存储ADC值
float ADC_Value[8]={0};//存储温度
u8 L_num[8]={15,15,15,15,15,15,15,15}; //设置低报警温度值,默认
u8 H_num[8]={40,40,40,40,40,40,40,40}; //设置高报警温度值
/************************************************/
sbit OE1_573 = P2^7;
sbit OE2_573 = P4^6;
sbit OE3_573 = P4^5;
//========================================================================
// 函数: void IO_Inti()
// 描述: 初始化IO
// 参数: ch:选择要转换的ADC通道
//========================================================================
void IO_Inti()
{
P0M1=0;
P0M0=0XFF;
P1M1 = 0Xff;
P1M0 = 0X00;
P2M1=0;
P2M0=0;
P3M1=0;
P3M0=0;
P4M1=0;
P4M0=0;
P5M1=0;
P5M0=0;
}
//========================================================================
// 函数: float Get_Temperature(u8 ch)
// 描述: (log(y)-log(635.69))/-0.029=x
// 参数: ch:选择要转换的ADC通道
//========================================================================
float Get_Temperature(u8 ch)
{
const float XS = 635.69;
u16 ADC_V=0;
float temp = Get_ADC10bitResult(ch);
temp = log(temp);
temp -= log(XS);
temp /= -0.029;
return temp;
}
//========================================================================
// 函数: int filter(u8 ch)
// 描述: 软件滤波
// 参数: ch滤波值
//========================================================================
#define N 12
int filter(u8 ch)
{
float sum = 0;
u8 count=0;
for(count=0;count<N;count++)
{
sum += Get_Temperature(ch);
_nop_();
_nop_();
_nop_();
}
return (int)(sum/N);
}
//========================================================================
// 函数: void UART_Test()
// 描述: 数据读取与串口测试
// 参数: 无
//========================================================================
void UART_Test()
{
tab[0]=Get_ADC10bitResult(0); //读取通道0的ADC值
ADC_Value[0] = (float)filter(0); //读取通道0的温度
tab[1]=Get_ADC10bitResult(1); //读取通道1的ADC值
ADC_Value[1] = (float)filter(1); //读取通道1的温度
tab[2]=Get_ADC10bitResult(2); //读取通道2的ADC值
ADC_Value[2] = (float)filter(2); //读取通道2的温度
tab[3]=Get_ADC10bitResult(3); //读取通道3的ADC值
ADC_Value[3] = (float)filter(3); //读取通道3的温度
tab[4]=Get_ADC10bitResult(4); //读取通道4的ADC值
ADC_Value[4] = (float)filter(4); //读取通道4的温度
tab[5]=Get_ADC10bitResult(5); //读取通道5的ADC值
ADC_Value[5] = (float)filter(5); //读取通道5的温度
tab[6]=Get_ADC10bitResult(6); //读取通道6的ADC值
ADC_Value[6] = (float)filter(6); //读取通道6的温度
tab[7]=Get_ADC10bitResult(7); //读取通道7的ADC值
ADC_Value[7] = (float)filter(7); //读取通道7的温度
//发送串口监控显示
// printf("通道0的AD值%d\n",tab[0]);
// printf("通道0的温度值%f℃\n",ADC_Value[0]);
// printf("通道1的AD值%d\n",tab[1]);
// printf("通道1的温度值%f℃\n",ADC_Value[1]);
// printf("通道2的AD值%d\n",tab[2]);
// printf("通道2的温度值%f℃\n",ADC_Value[2]);
// printf("通道3的AD值%d\n",tab[3]);
// printf("通道3的温度值%f℃\n",ADC_Value[3]);
// printf("通道4的AD值%d\n",tab[4]);
// printf("通道4的温度值%f℃\n",ADC_Value[4]);
// printf("通道5的AD值%d\n",tab[5]);
// printf("通道5的温度值%f℃\n",ADC_Value[5]);
// printf("通道6的AD值%d\n",tab[6]);
// printf("通道6的温度值%f℃\n",ADC_Value[6]);
// printf("通道7的AD值%d\n",tab[7]);
// printf("通道7的温度值%f℃\n\n\n",ADC_Value[7]);
}
void Timer0Init(void) //1000微秒@22.1184MHz
{
AUXR &= 0x7F; //定时器时钟12T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0xCD; //设置定时初值
TH0 = 0xF8; //设置定时初值
TR0 = 0; //定时器0关闭计时
ET0 = 1; //打开定时器0中断
EA = 1; //打开总中断
}
//========================================================================
// 函数: void Timer1Init(void)
// 描述: 定时器1初始化
// 参数: 无
//========================================================================
void Timer1Init(void) //1000微秒@22.1184MHz
{
AUXR &= 0xBF; //定时器时钟12T模式
TMOD &= 0x0F; //设置定时器模式
TL1 = 0xCD; //设置定时初值
TH1 = 0xF8; //设置定时初值
TF1 = 0; //清除TF1标志
TR1 = 0; //定时器1开始计时
ET1 = 1; //打开定时器0中断
EA = 1; //打开总中断
}
//========================================================================
// 函数: void Dis_play(u8 x,u8 y,u8 dat)
// 描述: LCD12864显示数据
// 参数: 无
//========================================================================
void Dis_play(u8 x,u8 y,u8 dat)
{
u8 ge=0,shi=0; //用于显示个,十位
ge = dat%10; //取各位
shi = dat/10; //取十位
Single_Data(x,y,shi);//发送十位显示
Write_data(ge+'0'); //发送个位显示
_nop_();_nop_();
}
//========================================================================
// 函数: display_start()
// 描述: LCD12864显示数据
// 参数: 无
//========================================================================
void display_start()
{
LCD_PutString(0,1,"ch0: ℃ch4: ℃");//温度显示界面
LCD_PutString(0,2,"ch1: ℃ch5: ℃");
LCD_PutString(0,3,"ch2: ℃ch6: ℃");
LCD_PutString(0,4,"ch3: ℃ch7: ℃");
}
//========================================================================
// 函数: empty_inti()
// 描述: LCD12864清空显示数据
// 参数: 无
//========================================================================
void empty_inti()
{
LCD_PutString(0,1,"0:开1:开2:开3:开");//清空LCD12864显示
LCD_PutString(0,2,"4:开5:开6:开7:开");
LCD_PutString(0,3," ");
LCD_PutString(0,4," ");
}
//========================================================================
// 函数: Control_KEY()
// 描述: 设置温度报警
// 参数: 无
//========================================================================
void Control_KEY()
{
static u8 flag_1=0;//用于设置那一路温度标志位
if(SW1 == 0)//判断是否有按键按下
{
DelayMS(1);//延时消抖
if(SW1 == 0)//判断是否有按键按下
{
while(!SW1);//松手检测
flag_1++;
switch(flag_1)
{
case 1:
TR1 = 0;
TR0 = 1;
LCD_PutString(0,1,"0: -- 4: -- ");
LCD_PutString(0,2,"1: -- 5: -- ");
LCD_PutString(0,3,"2: -- 6: -- ");
LCD_PutString(0,4,"3: -- 7: -- ");
break; //
case 2:
LCD_PutString(0,1,"0: 设 4: -- ");//设置0通道
break;
case 3:
LCD_PutString(0,1,"0: -- 4: -- "); //设置1通道
LCD_PutString(0,2,"1: 设 5: -- ");
break;
case 4:
LCD_PutString(0,2,"1: -- 5: -- ");//设置2通道
LCD_PutString(0,3,"2: 设 6: -- ");
break;
case 5:
LCD_PutString(0,3,"2: -- 6: -- ");//设置3通道
LCD_PutString(0,4,"3: 设 7: -- ");
break;
case 6:
LCD_PutString(0,4,"3: -- 7: -- ");//设置4通道
LCD_PutString(0,1,"0: -- 4: 设 ");
break;
case 7:
LCD_PutString(0,1,"0: -- 4: -- ");//设置5通道
LCD_PutString(0,2,"1: -- 5: 设 ");
break;
case 8:
LCD_PutString(0,2,"1: -- 5: -- ");//设置6通道
LCD_PutString(0,3,"2: -- 6: 设 ");
break;
case 9:
LCD_PutString(0,3,"2: -- 6: -- ");//设置7通道
LCD_PutString(0,4,"3: -- 7: 设 ");
break;
case 10:
TR0 = 0;
TR1 = 1;
break;
default:break;
}
if(flag_1 == 10) flag_1=0;
}
}
///
if((SW2 == 0) && (flag_1 > 1))//判断高报警位按键与是否可以设置温度
{
DelayMS(2);//延时消抖
if((SW2 == 0) && (flag_1 > 1))//判断高报警位按键与是否可以设置温度
{
while(!SW2);//松手检测
switch(flag_1)
{
case 2:H_num[0]++;
if(H_num[0]==99)
{
H_num[0]=30;
}break;
case 3:H_num[1]++;
if(H_num[1]==99)
{
H_num[1]=30;
}break;
case 4:H_num[2]++;
if(H_num[2]==99)
{
H_num[2]=30;
}break;
case 5:H_num[3]++;
if(H_num[3]==99)
{
H_num[3]=30;
}break;
case 6:H_num[4]++;
if(H_num[4]==99)
{
H_num[4]=30;
}break;
case 7:H_num[5]++;
if(H_num[5]==99)
{
H_num[5]=30;
}break;
case 8:H_num[6]++;
if(H_num[6]==99)
{
H_num[6]=30;
}break;
case 9:H_num[7]++;
if(H_num[7]==99)
{
H_num[7]=30;
}break;
default:break;
}
}
}
///
if((SW3 == 0) && (flag_1 > 1))//判断低报警位按键与是否可以设置温度
{
DelayMS(2);//延时消抖
if((SW3 == 0) && (flag_1 > 1))//判断低报警位按键与是否可以设置温度
{
while(!SW3); //松手检测
switch(flag_1)
{
case 2:L_num[0]--;
if(L_num[0]==0)
{
L_num[0]=30;
}break;
case 3:L_num[1]--;
if(L_num[1]==0)
{
L_num[1]=30;
}break;
case 4:L_num[2]--;
if(L_num[2]==0)
{
L_num[2]=30;
}break;
case 5:L_num[3]--;
if(L_num[3]==0)
{
L_num[3]=30;
}break;
case 6:L_num[4]--;
if(L_num[4]==0)
{
L_num[4]=30;
}break;
case 7:L_num[5]--;
if(L_num[5]==0)
{
L_num[5]=30;
}break;
case 8:L_num[6]--;
if(L_num[6]==0)
{
L_num[6]=30;
}break;
case 9:L_num[7]--;
if(L_num[7]==0)
{
L_num[7]=30;
}break;
default:break;
}
}
}
/
if(SW4 == 0)//判断是否有按键按下
{
DelayMS(1);//延时消抖
if(SW4 == 0)//判断是否有按键按下
{
while(!SW1);//松手检测
TR1=1;
}
}
}
void main()
{
IO_Inti(); //IO初始化
LCD_inti();//初始化LCD12864
Timer1Init();//初始化定时器1
Timer0Init();//初始化定时器0
UART_init();//初始化串口
AD_Inti(); //ADC初始化
while(1)
{
Control_KEY();//按键检测
UART_Test(); //ADC读取
if((L_num[0] >= ADC_Value[0])) //温度少于设定低温度是加热水
{
OE1_573 = 1;//打开573使能端
OE2_573 = 0;//573使关闭能端
P0 = 0xef;
}
if((H_num[0] <= ADC_Value[0])) //温度大于设定高温度是加冷水
{
OE1_573 = 0;//打开573使能端
OE2_573 = 1;//573使关闭能端
P0 = 0xef;
}
}
}
void tm0() interrupt 1
{
static u16 flag=0;
flag++;
if(flag>=300)
{
flag=0;
Dis_play(3,1,L_num[0]); //报警值显示
Dis_play(3,2,L_num[1]);
Dis_play(3,3,L_num[2]);
Dis_play(3,4,L_num[3]);
Dis_play(7,1,L_num[4]);
Dis_play(7,2,L_num[5]);
Dis_play(7,3,L_num[6]);
Dis_play(7,4,L_num[7]);
Dis_play(1,1,H_num[0]);
Dis_play(1,2,H_num[1]);
Dis_play(1,3,H_num[2]);
Dis_play(1,4,H_num[3]);
Dis_play(5,1,H_num[4]);
Dis_play(5,2,H_num[5]);
Dis_play(5,3,H_num[6]);
Dis_play(5,4,H_num[7]);
}
}
void tm1() interrupt 3
{
static u16 flag=0;
flag++;
if(flag>=300) //10ms
{
flag = 0;
display_start();
Dis_play(2,1,(u8)ADC_Value[0]); //温度显示
Dis_play(2,2,(u8)ADC_Value[1]);
Dis_play(2,3,(u8)ADC_Value[2]);
Dis_play(2,4,(u8)ADC_Value[3]);
Dis_play(6,1,(u8)ADC_Value[4]);
Dis_play(6,2,(u8)ADC_Value[5]);
Dis_play(6,3,(u8)ADC_Value[6]);
Dis_play(6,4,(u8)ADC_Value[7]);
}
}
#ifndef __ADC_H_
#define __ADC_H_
#include "config.h"
#include "lcd12864.h"
#include <STC15F2K60S2.H>
#include "intrins.h"
#include "uart.h"
#include <stdio.h> // 为使用KEIL自带的库函数printf而加入
#define ADC_POWER 0x80 //ADC电源控制位
#define ADC_FLAG 0x10 //ADC完成标志
#define ADC_START 0x08 //ADC起始控制位
#define ADC_SPEEDLL 0x00 //540个时钟
#define ADC_SPEEDL 0x20 //360个时钟
#define ADC_SPEEDH 0x40 //180个时钟
#define ADC_SPEEDHH 0x60 //90个时钟
void AD_Inti(void);
u16 Get_ADC10bitResult(u8 channel);
#endif
#include "adc.h"
void AD_Inti(void)
{
ADC_RESL=0; //清除结果寄存器
ADC_RES=0; //清除结果寄存器
ADC_CONTR &= 0x10;//清除转换完成标志位
P1ASF = 0xff; //P1做ADC
ADC_CONTR = 0xE0; //90T, ADC power on
_nop_();
_nop_();
_nop_();
_nop_();
}
//========================================================================
// 函数: u16 Get_ADC10bitResult(u8 channel)
// 描述: 查询法读一次ADC结果.
// 参数: channel: 选择要转换的ADC.
// 返回: 10位ADC结果.
// 版本: V1.0, 2012-10-22
//========================================================================
u16 Get_ADC10bitResult(u8 channel) //channel = 0~7
{
u16 AD_v = 0;
ADC_RES = 0;
ADC_RESL = 0;
ADC_CONTR = (ADC_CONTR & 0xe0) | 0x08 | channel; //start the ADC
_nop_();
_nop_();
_nop_();
_nop_();
while((ADC_CONTR & 0x10) == 0) ; //wait for ADC finish
ADC_CONTR &= ~0x10; //清除ADC结束标志
AD_v = ((u16)ADC_RES << 2) | (ADC_RESL & 3);
return (AD_v);
}