基于金沙滩51单片机的单点测温程序
之前学51单片机的时候做了一个单点测温程序,现在分享一下。
用的是金沙滩的51单片机开发板,这个很好,推荐一下。
零、完成功能
本项目完成以下功能:
- 单点温度测量
- 测温范围 10℃-40℃
- 分辨率 1℃
- 两位温度显示
- 超出上下限(18℃-25℃)蜂鸣器响起警报
壹、硬件电路图
贰、软件代码
代码的注释很详细,程序很简单,就不一一介绍了。
#include <reg52.h>
#include <intrins.h>
#define T_MAX 25 // 最大温度限定值
#define T_MIN 18 // 最小温度限定值
sbit BUZZ = P1^6;
//_nop_()函数所在头文件
/*----------------音乐函数申明------------------------------*/
void InitBuzz();
bit isBuzz = 0; //蜂鸣器是否在响
/*----------------温度传感器申明----------------------------*/
bit Start18B20(); //初始化DS18B20
bit Get18B20Temp(int *temp);//读取温度
bit isGetTemp = 0; //是否在获取温度
/*----------------LCD1602显示模块申明------------------------*/
void InitLcd1602(); //LCD1602初始化函数
void display(); //显示控制模块
/*-------------------LCD1602显示缓存-------------------------*/
//LCD1602函数调用申明
void LcdShowStr(unsigned char x, unsigned char y,unsigned char *str, unsigned char len);
unsigned char strbuff[4];//格式:“25°C”
unsigned char code waringStrHot[] = " Hot! ";//报警显示文字
unsigned char code waringStrCol[] = " Cold! ";//报警显示文字
unsigned char code striswaring[] = " ";//取消报警显示文字
/*----------------------其他全局变量-------------------------*/
int Temp = 0; //读取到的当前温度值(16bit二进制)
int intT; //温度值的整数和小数部分
bit iswaring = 0; //是否报警标志位
void main()
{
// int n = 0;
// char s[1];
bit isReay = 0;
bit sta; //是否成功读取标志
unsigned int cnt = 0; //检测标志,主要用于控制检测温度的频率
InitBuzz(); //蜂鸣器初始化
Start18B20(); //启动DS18B20
InitLcd1602(); //初始化LCD1602液晶模块
while(1)
{
if(isReay == 0)
{
cnt++;
}
if((cnt>28000&&isBuzz == 0)||(cnt>14000&&isBuzz == 1)) //大约0.8s(仿真得到) DS18B20最多750ms转化好
{
cnt = 0;
isReay = 1;
}
if(isReay == 1 && isBuzz == 0)
{
// n++;
// s[0] = n+'0';
// LcdShowStr(0, 0,s, 1);
isGetTemp = 1;
sta = Get18B20Temp(&Temp); //读取当前温度
isGetTemp = 0;
if (sta) //读取成功时,刷新当前温度显示
{
intT = Temp >> 4; //分离出温度值整数部分
}
Start18B20(); //重新启动下一次转换
if(intT > T_MAX || intT < T_MIN)
{
iswaring = 1;
}else{
iswaring = 0;
}
isReay = 0;
}
display();//显示
}
}
/*-----------------------以下是LCD1602显示驱动------------------*/
//定义LCD1602显示相关的IO接口
#define LCD1602_DB P0
sbit LCD1602_RS = P1^0;
sbit LCD1602_RW = P1^1;
sbit LCD1602_E = P1^5;
//显示控制模块
void display()
{
static int intTb; //温度值的整数部分备份
static bit isBuzzb;
if(isBuzzb != isBuzz)
{
if(isBuzz == 0 && iswaring == 1)
{
if(intT > T_MAX)
{
LcdShowStr(0,1,waringStrHot,16);
}else{
LcdShowStr(0,1,waringStrCol,16);
}
}else{
LcdShowStr(0,1,striswaring,11);
}
isBuzzb = isBuzz;
}
if(intTb != intT)//如果有变化
{
/*备份当前值*/
intTb = intT;
if((intT/10) == 0)strbuff[0] = ' ';else strbuff[0] = ((intT/10)%10)+0x30;//十位
strbuff[1] = ((intT/1)%10)+0x30;//个位
LcdShowStr(6,0,strbuff,4); //显示,初始位置随意,只要能显示完整就好
}
}
//等待液晶准备好
void LcdWaitReady()
{
unsigned char sta;
LCD1602_DB = 0xFF;
LCD1602_RS = 0;
LCD1602_RW = 1;
do {
LCD1602_E = 1; //使能LCD1602
sta = LCD1602_DB; //读取状态字
LCD1602_E = 0; //避免干扰其他器件
} while (sta & 0x80); //第七位等于1表示液晶正忙,重复检测直到第七位等于0为止
}
//向LCD1602液晶写入一字节命令,cmd为待写入命令值
void LcdWriteCmd(unsigned char cmd)
{
LcdWaitReady();
LCD1602_RS = 0;
LCD1602_RW = 0;
LCD1602_DB = cmd;
LCD1602_E = 1;
LCD1602_E = 0;
}
//向LCD1602液晶写入一字节数据,dat为待写入数据值
void LcdWriteDat(unsigned char dat)
{
LcdWaitReady();
LCD1602_RS = 1;
LCD1602_RW = 0;
LCD1602_DB = dat;
LCD1602_E = 1;
LCD1602_E = 0;
}
//设置显示RAM起始地址,亦即光标位置,(x,y)对应屏幕上的字符的坐标
void LcdSetCursor(unsigned char x, unsigned char y)
{
unsigned char addr;
if (y == 0) //由输入的屏幕坐标计算显示RAM的地址
addr = 0x00 + x; //第一行字符地址从0x00起始
else
addr = 0x40 + x; //第二行字符地址从0x40起始
LcdWriteCmd(addr | 0x80); //设置RAM地址
}
//在液晶上显示字符串,(x,y)-对应屏幕上的起始坐标,
//str-字符串指针,len-需显示的字符长度
void LcdShowStr(unsigned char x, unsigned char y,unsigned char *str, unsigned char len)
{
LcdSetCursor(x, y); //设置起始地址
while (len--) //连续写入len个字符数据
{
LcdWriteDat(*str++); //先取str指向的数据,然后str自加1
}
}
void InitLcd1602()//初始化1602液晶
{
strbuff[2] = 0XDF;
strbuff[3] = 'C';
LcdWriteCmd(0x38); //16*2显示,5*7点阵,8位数据接口
LcdWriteCmd(0x0C); //显示器开,光标关闭
LcdWriteCmd(0x06); //文字不动,地址自动+1
LcdWriteCmd(0x01); //清屏
}
/*-----------------------以下是温度传感器驱动------------------*/
//DS18B20通信引脚
sbit IO_18B20 = P3^2;
void DelayX10us(unsigned char t)
{
do {
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
} while (--t);
/*_nop_()函数在12M晶振中延迟1us,为什么这里是8个_nop_()
因为while和--t也是需要时间的,这里不一定是准确的10us/循环
只是大致的时间*/
}
bit Get18B20Ack() //DS18B20存在检测函数
{
bit ack;
EA = 0; //关中断
IO_18B20 = 0; //拉低引脚
DelayX10us(50); //延时500us(480us - 960us)
IO_18B20 = 1; //释放总线
DelayX10us(6); //延时60us(15us - 60us)
ack = IO_18B20; //读取响应(60us - 240us)
while(!IO_18B20); //等待DS18B20释放总线 (60us - 240us)
EA = 1; //取消关中断
return ack; //返回是否存在 (0:存在 1:不存在)
}
void Write18B20(unsigned char dat) //写DS18B20
{
unsigned char mask; //临时变量定义
EA = 0; //关中断
for(mask=0x01; mask!= 0; mask<<=1) //循环发送单个bit位
{
IO_18B20 = 0; //拉低(请求读写操作)
_nop_(); //延时(1us < time <= 15us)
_nop_();
if((mask&dat) == 0) //按位读取dat
IO_18B20 = 0; //本位是0,拉低
else
IO_18B20 = 1; //本位是1,拉高
//上面这个操作DS18B20读取(最小时间 0us<time<15us,
//典型时间 15us,最大时间45us)
DelayX10us(6); //等待60us(足够DS18B20读取)
IO_18B20 = 1; //释放总线
}
EA = 1; //取消关中断
}
unsigned char Read18B20() //读DS18B20
{
unsigned char dat; //数据缓存变量
unsigned char mask; //临时变量
EA = 0; //关中断
for(mask=0x01; mask!=0; mask<<=1)//同上循环按位操作
{
IO_18B20 = 0; //读写请求
_nop_(); //等待(1us < time < 15us)
_nop_();
IO_18B20 = 1; //初始化读操作
_nop_(); //等待DS18B20输出
_nop_();
if(!IO_18B20) //读
dat &= ~mask; //“0”
else
dat |= mask; //“1”
DelayX10us(6); //等待DS18B20释放总线
}
EA = 1; //取消关中断
return dat; //返回数据
}
bit Start18B20() //初始化DS18B20
{
bit ack; //存在标志
ack = Get18B20Ack();//检测存在
if(ack == 0) //存在
{ //写命令使工作
Write18B20(0xCC); //跳过ROM检测
Write18B20(0x44); //启动温度转换
}
return ~ack; //返回是否成功(1是,0否)
}
bit Get18B20Temp(int *temp) //获取DS18B20温度存于temp
{
bit ack; //存在标志
unsigned char LSB, MSB; //数据低/高位
ack = Get18B20Ack(); //检测存在
if(ack == 0) //存在
{ //写指令
Write18B20(0xCC); //跳过ROM检测
Write18B20(0xBE); //读寄存器
LSB = Read18B20(); //读低位
MSB = Read18B20(); //读高位
*temp = ((int)MSB<<8) + LSB; //合并
}
return ~ack; //返回结果(1成功,0失败)
}
//下面是蜂鸣器
void InterruptTimer0() interrupt 1
{
static unsigned int timer;
TH0 = 0x00;
TL0 = 0x00;
timer++;
if(iswaring)
{
if(timer>3000)
{
isBuzz = 1;
if(timer%5==1)
{
BUZZ = ~BUZZ;
}
if(timer>6000)
{
timer = 0;
}
}else{
isBuzz = 0;
}
}else{
isBuzz = 0;
}
}
void InitBuzz()
{
TMOD = 0x02;
TR0 = 1;
ET0 = 1;
}
叁、运行效果
视频演示:https://www.bilibili.com/video/BV1Fy4y1y7BP/
成功完成以上功能,哈哈~
喜欢的小伙伴支持一下吧