当前位置:网站首页>单片机:温度控制DS18B20
单片机:温度控制DS18B20
2022-08-05 10:10:00 【最早的早安...】
题目概述:
使用单片机DS18B20进行温度检测。
编程:
//DS18B20温度检测及其液晶显示
#include<reg51.h> //包含单片机寄存器的头文件
#include<intrins.h> //包含_nop_()函数定义的头文件
unsigned char code digit[10]={
"0123456789"}; //定义字符数组显示数字
unsigned char code Str[]={
"Test by DS18B20"}; //说明显示的是温度
unsigned char code Error[]={
"Error!Check!"}; //说明没有检测到DS18B20
unsigned char code Temp[]={
"Temp:"}; //说明显示的是温度
unsigned char code Cent[]={
"Cent"}; //温度单位
volatile unsigned char sending;
sbit beep=P2^3;
sbit dula=P2^0;
sbit wela=P2^1;
sbit JD=P0^6;
sbit FM=P2^3;
sbit P20 = P2^0;//这是为了关闭开发板上的数码管实际应用去掉
sbit P21 = P2^1;//这是为了关闭开发板上的数码管实际应用去掉
sbit CS88 = P2^2;//这是为了关闭开发板上的点阵实际应用去掉
void ioin() //IO口继电器、数码管锁存函数
{
wela=1;
P0 = 1;
JD = 0;
wela=0;
dula=1;
P0=0;
dula=0;
}
/******************************************************************************* 以下是对液晶模块的操作程序 *******************************************************************************/
sbit RS=P1^0; //寄存器选择位,将RS位定义为P2.0引脚
sbit RW=P1^1; //读写选择位,将RW位定义为P2.1引脚
sbit E=P2^5; //使能信号位,将E位定义为P2.2引脚
sbit BF=P0^7; //忙碌标志位,,将BF位定义为P0.7引脚
/***************************************************** 函数功能:延时1ms (3j+2)*i=(3×33+2)×10=1010(微秒),可以认为是1毫秒 ***************************************************/
void delay1ms()
{
unsigned char i,j;
for(i=0;i<4;i++)
for(j=0;j<33;j++)
;
}
/***************************************************** 函数功能:延时若干毫秒 入口参数:n ***************************************************/
void delaynms(unsigned char n)
{
unsigned char i;
for(i=0;i<n;i++)
delay1ms();
}
/***************************************************** 函数功能:判断液晶模块的忙碌状态 返回值:result。result=1,忙碌;result=0,不忙 ***************************************************/
bit BusyTest(void)
{
bit result;
RS=0; //根据规定,RS为低电平,RW为高电平时,可以读状态
RW=1;
E=1; //E=1,才允许读写
_nop_(); //空操作
_nop_();
_nop_();
_nop_(); //空操作四个机器周期,给硬件反应时间
result=BF; //将忙碌标志电平赋给result
E=0; //将E恢复低电平
return result;
}
/***************************************************** 函数功能:将模式设置指令或显示地址写入液晶模块 入口参数:dictate ***************************************************/
void WriteInstruction (unsigned char dictate)
{
while(BusyTest()==1); //如果忙就等待
RS=0; //根据规定,RS和R/W同时为低电平时,可以写入指令
RW=0;
E=0; //E置低电平(根据表8-6,写指令时,E为高脉冲,
// 就是让E从0到1发生正跳变,所以应先置"0"
_nop_();
_nop_(); //空操作两个机器周期,给硬件反应时间
P0=dictate; //将数据送入P0口,即写入指令或地址
_nop_();
_nop_();
_nop_();
_nop_(); //空操作四个机器周期,给硬件反应时间
E=1; //E置高电平
_nop_();
_nop_();
_nop_();
_nop_(); //空操作四个机器周期,给硬件反应时间
E=0; //当E由高电平跳变成低电平时,液晶模块开始执行命令
}
/***************************************************** 函数功能:指定字符显示的实际地址 入口参数:x ***************************************************/
void WriteAddress(unsigned char x)
{
WriteInstruction(x|0x80); //显示位置的确定方法规定为"80H+地址码x"
}
/***************************************************** 函数功能:将数据(字符的标准ASCII码)写入液晶模块 入口参数:y(为字符常量) ***************************************************/
void WriteData(unsigned char y)
{
while(BusyTest()==1);
RS=1; //RS为高电平,RW为低电平时,可以写入数据
RW=0;
E=0; //E置低电平(根据表8-6,写指令时,E为高脉冲,
// 就是让E从0到1发生正跳变,所以应先置"0"
P0=y; //将数据送入P0口,即将数据写入液晶模块
_nop_();
_nop_();
_nop_();
_nop_(); //空操作四个机器周期,给硬件反应时间
E=1; //E置高电平
_nop_();
_nop_();
_nop_();
_nop_(); //空操作四个机器周期,给硬件反应时间
E=0; //当E由高电平跳变成低电平时,液晶模块开始执行命令
}
/***************************************************** 函数功能:对LCD的显示模式进行初始化设置 ***************************************************/
void LcdInitiate(void)
{
delaynms(15); //延时15ms,首次写指令时应给LCD一段较长的反应时间
WriteInstruction(0x38); //显示模式设置:16×2显示,5×7点阵,8位数据接口
delaynms(5); //延时5ms ,给硬件一点反应时间
WriteInstruction(0x38);
delaynms(5); //延时5ms ,给硬件一点反应时间
WriteInstruction(0x38); //连续三次,确保初始化成功
delaynms(5); //延时5ms ,给硬件一点反应时间
WriteInstruction(0x0c); //显示模式设置:显示开,无光标,光标不闪烁
delaynms(5); //延时5ms ,给硬件一点反应时间
WriteInstruction(0x06); //显示模式设置:光标右移,字符不移
delaynms(5); //延时5ms ,给硬件一点反应时间
WriteInstruction(0x01); //清屏幕指令,将以前的显示内容清除
delaynms(5); //延时5ms ,给硬件一点反应时间
}
/************************************************************************ 以下是DS18B20的操作程序 ************************************************************************/
sbit DQ=P2^4;
unsigned char time; //设置全局变量,专门用于严格延时
/***************************************************** 函数功能:将DS18B20传感器初始化,读取应答信号 出口参数:flag ***************************************************/
bit Init_DS18B20(void)
{
bit flag; //储存DS18B20是否存在的标志,flag=0,表示存在;flag=1,表示不存在
DQ = 1; //先将数据线拉高
for(time=0;time<2;time++) //略微延时约6微秒
;
DQ = 0; //再将数据线从高拉低,要求保持480~960us
for(time=0;time<200;time++) //略微延时约600微秒
; //以向DS18B20发出一持续480~960us的低电平复位脉冲
DQ = 1; //释放数据线(将数据线拉高)
for(time=0;time<10;time++)
; //延时约30us(释放总线后需等待15~60us让DS18B20输出存在脉冲)
flag=DQ; //让单片机检测是否输出了存在脉冲(DQ=0表示存在)
for(time=0;time<200;time++) //延时足够长时间,等待存在脉冲输出完毕
;
return (flag); //返回检测成功标志
}
/***************************************************** 函数功能:从DS18B20读取一个字节数据 出口参数:dat ***************************************************/
unsigned char ReadOneChar(void)
{
unsigned char i=0;
unsigned char dat; //储存读出的一个字节数据
for (i=0;i<8;i++)
{
DQ =1; // 先将数据线拉高
_nop_(); //等待一个机器周期
DQ = 0; //单片机从DS18B20读书据时,将数据线从高拉低即启动读时序
dat>>=1;
_nop_(); //等待一个机器周期
DQ = 1; //将数据线"人为"拉高,为单片机检测DS18B20的输出电平作准备
for(time=0;time<2;time++)
; //延时约6us,使主机在15us内采样
if(DQ==1)
dat|=0x80; //如果读到的数据是1,则将1存入dat
else
dat|=0x00;//如果读到的数据是0,则将0存入dat
//将单片机检测到的电平信号DQ存入r[i]
for(time=0;time<8;time++)
; //延时3us,两个读时序之间必须有大于1us的恢复期
}
return(dat); //返回读出的十进制数据
}
/***************************************************** 函数功能:向DS18B20写入一个字节数据 入口参数:dat ***************************************************/
WriteOneChar(unsigned char dat)
{
unsigned char i=0;
for (i=0; i<8; i++)
{
DQ =1; // 先将数据线拉高
_nop_(); //等待一个机器周期
DQ=0; //将数据线从高拉低时即启动写时序
DQ=dat&0x01; //利用与运算取出要写的某位二进制数据,
//并将其送到数据线上等待DS18B20采样
for(time=0;time<10;time++)
;//延时约30us,DS18B20在拉低后的约15~60us期间从数据线上采样
DQ=1; //释放数据线
for(time=0;time<1;time++)
;//延时3us,两个写时序间至少需要1us的恢复期
dat>>=1; //将dat中的各二进制位数据右移1位
}
for(time=0;time<4;time++)
; //稍作延时,给硬件一点反应时间
}
/****************************************************************************** 以下是与温度有关的显示设置 ******************************************************************************/
/***************************************************** 函数功能:显示没有检测到DS18B20 ***************************************************/
void display_error(void)
{
unsigned char i;
WriteAddress(0x00); //写显示地址,将在第1行第1列开始显示
i = 0; //从第一个字符开始显示
while(Error[i] != '\0') //只要没有写到结束标志,就继续写
{
WriteData(Error[i]); //将字符常量写入LCD
i++; //指向下一个字符
delaynms(100); //延时100ms较长时间,以看清关于显示的说明
}
while(1) //进入死循环,等待查明原因
;
}
/***************************************************** 函数功能:显示说明信息 ***************************************************/
void display_explain(void)
{
unsigned char i;
WriteAddress(0x00); //写显示地址,将在第1行第1列开始显示
i = 0; //从第一个字符开始显示
while(Str[i] != '\0') //只要没有写到结束标志,就继续写
{
WriteData(Str[i]); //将字符常量写入LCD
i++; //指向下一个字符
delaynms(100); //延时100ms较长时间,以看清关于显示的说明
}
}
/***************************************************** 函数功能:显示温度符号 ***************************************************/
void display_symbol(void)
{
unsigned char i;
WriteAddress(0x40); //写显示地址,将在第2行第1列开始显示
i = 0; //从第一个字符开始显示
while(Temp[i] != '\0') //只要没有写到结束标志,就继续写
{
WriteData(Temp[i]); //将字符常量写入LCD
i++; //指向下一个字符
delaynms(50); //延时1ms给硬件一点反应时间
}
}
/***************************************************** 函数功能:显示温度的小数点 ***************************************************/
void display_dot(void)
{
WriteAddress(0x49); //写显示地址,将在第2行第10列开始显示
WriteData('.'); //将小数点的字符常量写入LCD
delaynms(50); //延时1ms给硬件一点反应时间
}
/***************************************************** 函数功能:显示温度的单位(Cent) ***************************************************/
void display_cent(void)
{
unsigned char i;
WriteAddress(0x4c); //写显示地址,将在第2行第13列开始显示
i = 0; //从第一个字符开始显示
while(Cent[i] != '\0') //只要没有写到结束标志,就继续写
{
WriteData(Cent[i]); //将字符常量写入LCD
i++; //指向下一个字符
delaynms(50); //延时1ms给硬件一点反应时间
}
}
/***************************************************** 函数功能:显示温度的整数部分 入口参数:x ***************************************************/
void display_temp1(unsigned char x)
{
unsigned char j,k,l; //j,k,l分别储存温度的百位、十位和个位
j=x/100; //取百位
k=(x%100)/10; //取十位
l=x%10; //取个位
WriteAddress(0x46); //写显示地址,将在第2行第7列开始显示
WriteData(digit[j]); //将百位数字的字符常量写入LCD
SBUF=digit[j];
while (!TI); //等待发送数据完成
TI = 0;
WriteData(digit[k]); //将十位数字的字符常量写入LCD
SBUF=digit[k];
while (!TI); //等待发送数据完成
TI = 0;
WriteData(digit[l]); //将个位数字的字符常量写入LCD
SBUF=digit[l];
while (!TI); //等待发送数据完成
TI = 0;
delaynms(50); //延时1ms给硬件一点反应时间
}
/***************************************************** 函数功能:显示温度的小数数部分 入口参数:x ***************************************************/
void display_temp2(unsigned char x)
{
WriteAddress(0x4a); //写显示地址,将在第2行第11列开始显示
WriteData(digit[x]); //将小数部分的第一位数字字符常量写入LCD
SBUF='.';
while (!TI); //等待发送数据完成
TI = 0;
SBUF=digit[x];
while (!TI); //等待发送数据完成
TI = 0;
SBUF=' ';
while (!TI); //等待发送数据完成
TI = 0;
delaynms(50); //延时1ms给硬件一点反应时间
}
/***************************************************** 函数功能:做好读温度的准备 ***************************************************/
void ReadyReadTemp(void)
{
Init_DS18B20(); //将DS18B20初始化
WriteOneChar(0xCC); // 跳过读序号列号的操作
WriteOneChar(0x44); // 启动温度转换
for(time=0;time<100;time++)
; //温度转换需要一点时间
Init_DS18B20(); //将DS18B20初始化
WriteOneChar(0xCC); //跳过读序号列号的操作
WriteOneChar(0xBE); //读取温度寄存器,前两个分别是温度的低位和高位
}
#define jingzhen 11059200UL /*使用22.1184M晶体*/
#define botelv 9600UL /*波特率定义为9600*/
void init(void) //串口初始化
{
EA=0; //暂时关闭中断
TMOD&=0x0F; //定时器1模式控制在高4位
TMOD|=0x20; //定时器1工作在模式2,自动重装模式
SCON=0x50; //串口工作在模式1
TH1=256-jingzhen/(botelv*12*16); //计算定时器重装值
TL1=256-jingzhen/(botelv*12*16);
PCON|=0x80; //串口波特率加倍
ES=1; //串行中断允许
TR1=1; //启动定时器1
REN=1; //允许接收
EA=1; //允许中断
}
/***************************************************** 函数功能:主函数 ***************************************************/
void main(void)
{
float tt;
int temp;
unsigned char TL; //储存暂存器的温度低位
unsigned char TH; //储存暂存器的温度高位
unsigned char TN; //储存温度的整数部分
unsigned char TD; //储存温度的小数部分
ioin();
init();
LcdInitiate(); //将液晶初始化
delaynms(5); //延时5ms给硬件一点反应时间
if(Init_DS18B20()==1)
display_error();
display_explain();
display_symbol(); //显示温度说明
display_dot(); //显示温度的小数点
display_cent(); //显示温度的单位
P0=0x00;//这是为了关闭开发板上的数码管实际应用去掉
P20=0; //这是为了关闭开发板上的数码管实际应用去掉
P21=0; //这是为了关闭开发板上的数码管实际应用去掉
CS88=0; //这是为了关闭开发板上的点阵实际应用去掉
while(1) //不断检测并显示温度
{
ReadyReadTemp(); //读温度准备
TL=ReadOneChar(); //先读的是温度值低位
TH=ReadOneChar(); //接着读的是温度值高位
TN=TH*16+TL/16; //实际温度值=(TH*256+TL)/16,即:TH*16+TL/16
temp=TH; //这样得出的是温度的整数部分,小数部分被丢弃了
temp<<=8;
temp=temp|TL;
tt=temp*0.0625;
temp=tt*10+0.5;
TD=(TL%16)*10/16; //计算温度的小数部分,将余数乘以10再除以16取整,
//这样得到的是温度小数部分的第一位数字(保留1位小数)
display_temp1(TN); //显示温度的整数部分
display_temp2(TD); //显示温度的小数部分
if(temp>=310) //当温度超过31度(仅作试验用,实际可设为其他更高的值),蜂鸣器便会报警。
{
P1=0x00;
beep=0;
}
else
{
beep=1;
P1=0xff;
}
}
}
上机实践:
边栏推荐
- Which big guy has the 11G GI and ojvm patches in April or January 2020, please help?
- 什么是CRM决策分析管理?
- The century-old Nordic luxury home appliance brand ASKO smart wine cabinet in the three-temperature area presents the Chinese Valentine’s Day, and tastes the love of the delicacy
- 19. Server-side session technology Session
- MySQL data view
- DFINITY 基金会创始人谈熊市沉浮,DeFi 项目该何去何从
- 首次去中心化抢劫?近2亿美元损失:跨链桥Nomad 被攻击事件分析
- What is CRM Decision Analysis Management?
- Brief Analysis of WSGI Protocol
- Pycharm 常用外部工具
猜你喜欢
随机推荐
Getting started with Polkadot parachain development, this article is enough
three.js调试工具dat.gui使用
IDEA performs the Test operation, resulting in duplicate data when data is inserted
hcip BGP enhancement experiment
js劫持数组push方法
静态链接和动态链接
自定义过滤器和拦截器实现ThreadLocal线程封闭
Data Middle Office Construction (10): Data Security Management
Brief Analysis of WSGI Protocol
第五章:多线程通信—wait和notify
语音社交软件开发——充分发挥其价值
MySQL使用聚合函数可以不搭配GROUP BY分组吗?
Pycharm 常用外部工具
第八章:activiti多用户任务分配
茄子科技CEO仇俊:以用户为中心,做用户真正需要的产品
three.js debugging tool dat.gui use
The JVM collection that Alibaba's top architects have summarized for many years, where can't I check it!
创建一个 Dapp,为什么要选择波卡?
Where is your most secretive personality?
【温度预警程序de开发】事件驱动模型实例运用









![[强网杯2022]WP-UM](/img/3d/caeab05ddca278af274dbf6e2f8ba1.png)