目录
微型计算器自20世纪70年代诞生以来,得以迅速发展、普及和应用。随着增强型8051单片机和嵌入式微处理器技术的飞速发展,以及单片机C语言应用的普及,单片机应用领域越来越广泛。
随着社会的快速发展,科技的加速进步,测温仪器在各个领域应用越来越广泛,自动化和智能化已经成为现代的温度控制系统的主流发展方向。因为各行各业对于温度控制有着越来越高的要求,所以对温度的控制和测量就显得较为重要。温度控制器的使用范围越来越广泛,各种能够应用于不同领域的智能自动温度控制器随着产生。自动温度控制系统主要完成数据采集,温度定时的显示,温度控制,温度定时的设定以及报警等功能.
对51单片机所学知识进一步强化理解和应用。
软件:Proteus (文章中使用Proteus 8.6)
Keil (文章中使用Keil C51)
掌握《C语言》、《单片机原理及应用》两门课程。
/*-----------------------------------------------
名称:18B20温度测量报警
内容:在LCD1602第一行可以显示当前温度,
第二行显示设定的温度区间,超过此温度区间,蜂鸣器报警。
温度区间可以通过用户按键设置
------------------------------------------------*/
#include<reg51.h> //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
#include<math.h>
#include<INTRINS.H>
#define uchar unsigned char
#define uint unsigned int
/******************************************************************/
/* 定义端口 */
/******************************************************************/
sbit led1=P1^3;// 温度超出范围指示灯
sbit led2=P1^4;
sbit buzzer=P3^3;//蜂鸣器引脚
sbit DQ=P3^7;//ds18b20 端口
sbit RS = P0^4;//1602数据/命令选择端(H:数据寄存器L:指令寄存器)
sbit RW = P0^5;//1602读/写选择端
sbit E = P0^6;//1602使能信号端
sbit key1=P3^4;//用户按键
sbit key2=P3^5;
sbit key3=P3^6;
/******************************************************************/
/* 全局变量 */
/******************************************************************/
int temp;//测得温度
char temp_max=40,temp_min=10;//设定的温度
char TempH,TempL;
uchar flag_get,num=0;
uchar code tab[]={'0','1','2','3','4','5','6','7','8','9'};//液晶显示
uchar tab1[]="min:010 max:040";//液晶第二行显示内容
uchar str[8];
/******************************************************************/
/* 延时函数 */
/******************************************************************/
void delay1(uint i)//短延时函数
{
while(i--);
}
void delay(uint z) //长延时函数
{
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
/******************************************************************/
/* DS18B20 初始化 */
/******************************************************************/
void Init_DS18B20(void)
{
uchar x=0;
DQ = 1; //拉高总线,等待
delay1(8);
DQ = 0; //单片机将DQ拉低
delay1(80); //精确延时 大于 480us
DQ = 1; //拉高总线,等待
delay1(10);
x=DQ; //稍做延时后 如果x=0则初始化成功 x=1则初始化失败
delay1(5);
}
/******************************************************************/
/* DS18B20读一个字节 */
/******************************************************************/
uchar ReadOneChar(void) // DS18B20读一个字节
{
uchar i=0;
uchar dat = 0;
for (i=8;i>0;i--)
{
DQ = 0; // 给脉冲信号
dat>>=1;
DQ = 1; // 给脉冲信号,主机在读时隙期间必须释放总线
if(DQ)
dat|=0x80;
delay1(5);
}
return(dat);
}
/******************************************************************/
/* DS18B20写一个字节 */
/******************************************************************/
void WriteOneChar(uchar dat) //DS18B20写一个字节
{
uchar i=0;
for (i=8; i>0; i--)
{
DQ = 0;
DQ = dat&0x01;//取最低位
delay1(5);
DQ = 1;
dat>>=1;//左移
}
delay1(5);
}
/******************************************************************/
/* DS18B20读取温度 */
/******************************************************************/
uint ReadTemperature(void) //DS18B20读取温度
{
uchar a=0;
uint b=0;
uint t=0;
Init_DS18B20();//DS18B20初始化
WriteOneChar(0xCC); // 跳过读序号列号的操作
WriteOneChar(0x44); // 启动温度转换
delay1(200); //延时以求信号的稳定
Init_DS18B20(); //DS18B20再次初始化
WriteOneChar(0xCC); //跳过读序号列号的操作
WriteOneChar(0xBE); //读取温度寄存器等(共可读9个寄存器) 前两个就是温度
a=ReadOneChar(); //低位
b=ReadOneChar(); //高位
b<<=8; //b左移8位
t=a+b; //把a与b结合,放在16位的t中 此处两行代码也可用t=((b*256)+1)替代 原理相同
return(t);
}
/******************************************************************/
/* LCD1602写命令操作 */
/******************************************************************/
void WriteCommand(uchar com)
{
delay(5);//操作前短暂延时,保证信号稳定
E=0;
RS=0;
RW=0;
P2=com;
E=1;
delay(5);
E=0;
}
/******************************************************************/
/* LCD1602写数据操作 */
/******************************************************************/
void WriteData(uchar dat)
{
delay(5); //操作前短暂延时,保证信号稳定
E=0;
RS=1;
RW=0;
P2=dat;
E=1;
delay(5);
E=0;
}
/******************************************************************/
/* LCD1602初始化程序 */
/******************************************************************/
void InitLcd()
{
uchar i;
delay(15);
WriteCommand(0x38); //display mode
WriteCommand(0x06); //显示光标移动位置
WriteCommand(0x0c); //显示开及光标设置
WriteCommand(0x01); //显示清屏
WriteCommand(0x80+0x40);//将光标移到第二行
for(i=0;i<16;i++)//显示初始化内容
{
WriteData(tab1[i]);
delay(10);
}
}
/******************************************************************/
/* 蜂鸣器报警程序 */
/******************************************************************/
void alarm()
{
if(TempH>=temp_max)//当温度高于设置的最高温报警
{ buzzer=0;
delay(50);
buzzer=1;
delay(50);
led1=0;
led2=1;
}
else if(TempH<temp_min)//当温度低于设置的最低温报警
{
buzzer=0;
delay(50);
buzzer=1;
delay(50);
led1=1;
led2=0;
}
else//报警解除
{
buzzer=1;
led1=1;
led2=1;
}
}
/******************************************************************/
/* 显示测得的温度 */
/******************************************************************/
void handle_T()
{
uchar i;
str[0]=0x20;//显示为空
str[1]=tab[TempH/100]; //百位温度
str[2]=tab[(TempH%100)/10]; //十位温度
str[3]=tab[(TempH%100)%10]; //个位温度,带小数点
str[5]=tab[TempL];
str[4]='.';
str[6]=0xdf;
str[7]='C';
if(flag_get==1) //定时读取当前温度
{
flag_get=0; //清标志位
temp=ReadTemperature();//读取温度值
if(temp&0x8000)
{
str[0]=0xb0;//负号标志
temp=~temp; // 取反加1
temp +=1;
}
TempH=temp>>4; //由权重表知移4位就是整数位
TempL=temp&0x0F;
TempL=TempL*6/10;//小数近似处理
alarm(); //判断是否需要报警
}
WriteCommand(0x80+0x04);//光标指向第一行第一个字符
for(i=0;i<8;i++)// 显示
{
WriteData(str[i]);
delay(10);
}
}
void display_range(uchar add,int t)
{
uchar i;
if(t<0)
{
str[0]=0xb0;//负号标志
}
else
{
str[0]=tab[abs(t)/100]; //百位温度
str[1]=tab[(abs(t)%100)/10]; //十位温度
str[2]=tab[(abs(t)%100)%10]; //个位温度
WriteCommand(0x80+0x40+add);
}
for(i=0;i<3;i++)
{
WriteData(str[i]);
delay(5);
}
}
/******************************************************************/
/* 独立键盘扫描函数并显示设定的温度 */
/******************************************************************/
void keyscan()
{
uchar flag1=0,flag2=0;//有按键按下标记
P3=0xff;//拉高P3口,以读取P3口的值
if(key1==0) //两个按键控制最高/最低温度的加减 按住key1时通过其他2个键控制最高温度的加减
{
delay(5);
if(key2==0)//最高温加
{
delay(5);//延时消抖
if(key2==0)
{
temp_max++;
if(temp_max>=85)
temp_max=85;
}
while(!key2);//松手检测
flag1=1;
}
if(key3==0)//最高温减
{
delay(5);
if(key3==0)
{
temp_max--;
if(temp_max<=temp_min)
temp_max=temp_min;
}
while(!key3);
flag1=1;
}
}
if(key1==1) //松开key1时通过其他2个键控制最低温度的加减
{
delay(5);
if(key2==0)//最低温加
{
delay(5);//延时消抖
if(key2==0)
{
temp_min++;
if(temp_min>=temp_max)
temp_min=temp_max;
}
while(!key2);//松手检测
flag2=1;
}
if(key3==0)//最低温减
{
delay(5);
if(key3==0)
{
temp_min--;
if(temp_min<=-10)
temp_min=-10;
}
while(!key3);
flag2=1;
}
}
if(flag1)//如有设置最高温度的键按下,更新设定的温度
{
flag1=0;// 清标记
display_range(0x0d,temp_max);
}
if(flag2)//如有设置最低温度的键按下,更新设定的温度
{
flag2=0;// 清标记
display_range(0x04,temp_min);
}
}
/****************************************************************/
/* 主函数 */
/******************************************************************/
void main()
{
TMOD|=0x01;//定时器设置
TH0=0xEF;//装初始值
TL0=0xF0;
EA=1;// 开总中断
ET0=1;//允许定时器0中断
TR0=1;//开定时器0中断
InitLcd();//lcd1602初始化
flag_get=1;
while(1)
{
handle_T();// 处理温度:获得、显示、报警
keyscan(); //独立按键扫描
}
}
/******************************************************************/
/* 定时0中断处理程序,用于温度检测间隔,大约1秒测一次温度 */
/******************************************************************/
void timer0(void) interrupt 1 using 1
{
TH0=0xEF;//定时器重装值
TL0=0xF0;
num++;
if (num==50)
{
num=0;
flag_get=1;//标志位有效,开始测温
}
}

PS:按键控制温度加减区块也可用此种类型做到松手检测 (具体如何操作不做叙述)当然如果觉得2个按键控制可能因为抖动影响结果,可以更换其他方法。
if(key2==0&&flag==0)
{
flag=1;
}
if(flag==1&&key2==1)
{
temp_max++;
if(temp_max>=85)
temp_max=85;
flag=0;
}
因为涉及到C语言部分知识的解析,分装代码将在下一篇文章中更新。(不是没有做出来,下图。下篇打包发出,需要自取。)

以Proteus 8.6为例 (PS:本人在使用Proteus 8.9过程中出现LCD1602显示屏第一行无法正常工作,被迫使用Proteus 8.6。没有找到问题原因,欢迎大佬留言解答。)

关于buzzer(蜂鸣器)的选择,选择第二个即可。

LCD1602在Proteus中选择LM016L。


(PS:框框里的红色部分可以不用画,多余的,自己测speaker的工作原理时用到了没有删。)
按键控制这块再说一下,此文章中使用的是两个的按键控制温度加减。
按住key0,key1-->最高温度加,key2-->最高温度减。
松开key0(即默认),key1-->最低温度加,key2-->最低温度减。
从上到下依次key0、key1、key2。

至于怎么按住第一个键,单击按键右侧按钮。(如图啊)

以上便是基于51单片机设计的温度报警系统。细致的讲解在后面更新。
导读:随着叮咚买菜业务的发展,不同的业务场景对数据分析提出了不同的需求,他们希望引入一款实时OLAP数据库,构建一个灵活的多维实时查询和分析的平台,统一数据的接入和查询方案,解决各业务线对数据高效实时查询和精细化运营的需求。经过调研选型,最终引入ApacheDoris作为最终的OLAP分析引擎,Doris作为核心的OLAP引擎支持复杂地分析操作、提供多维的数据视图,在叮咚买菜数十个业务场景中广泛应用。作者|叮咚买菜资深数据工程师韩青叮咚买菜创立于2017年5月,是一家专注美好食物的创业公司。叮咚买菜专注吃的事业,为满足更多人“想吃什么”而努力,通过美好食材的供应、美好滋味的开发以及美食品牌的孵
电脑0x0000001A蓝屏错误怎么U盘重装系统教学分享。有用户电脑开机之后遇到了系统蓝屏的情况。系统蓝屏问题很多时候都是系统bug,只有通过重装系统来进行解决。那么蓝屏问题如何通过U盘重装新系统来解决呢?来看看以下的详细操作方法教学吧。 准备工作: 1、U盘一个(尽量使用8G以上的U盘)。 2、一台正常联网可使用的电脑。 3、ghost或ISO系统镜像文件(Win10系统下载_Win10专业版_windows10正式版下载-系统之家)。 4、在本页面下载U盘启动盘制作工具:系统之家U盘启动工具。 U盘启动盘制作步骤: 注意:制作期间,U盘会被格式化,因此U盘中的重要文件请注
在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList()Obt
C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.
说在前面这部分我本来是合为一篇来写的,因为目的是一样的,都是通过独立按键来控制LED闪灭本质上是起到开关的作用,即调用函数和中断函数。但是写一篇太累了,我还是决定分为两篇写,这篇是调用函数篇。在本篇中你主要看到这些东西!!!1.调用函数的方法(主要讲语法和格式)2.独立按键如何控制LED亮灭3.程序中的一些细节(软件消抖等)1.调用函数的方法思路还是比较清晰地,就是通过按下按键来控制LED闪灭,即每按下一次,LED取反一次。重要的是,把按键与LED联系在一起。我打算用K1来作为开关,看了一下开发板原理图,K1连接的是单片机的P31口,当按下K1时,P31是与GND相连的,也就是说,当我按下去时
需求:要创建虚拟机,就需要给他提供一个虚拟的磁盘,我们就在/opt目录下创建一个10G大小的raw格式的虚拟磁盘CentOS-7-x86_64.raw命令格式:qemu-imgcreate-f磁盘格式磁盘名称磁盘大小qemu-imgcreate-f磁盘格式-o?1.创建磁盘qemu-imgcreate-fraw/opt/CentOS-7-x86_64.raw10G执行效果#ls/opt/CentOS-7-x86_64.raw2.安装虚拟机使用virt-install命令,基于我们提供的系统镜像和虚拟磁盘来创建一个虚拟机,另外在创建虚拟机之前,提前打开vnc客户端,在创建虚拟机的时候,通过vnc
因为我现在正在做一些时间测量,我想知道是否可以在不使用Benchmark类或命令行实用程序time的情况下测量用户时间或系统时间。使用Time类只显示挂钟时间,而不显示系统和用户时间,但是我正在寻找具有相同灵active的解决方案,例如time=TimeUtility.now#somecodeuser,system,real=TimeUtility.now-time原因是我有点不喜欢Benchmark,因为它不能只返回数字(编辑:我错了-它可以。请参阅下面的答案。)。当然,我可以解析输出,但感觉不对。*NIX系统的time实用程序也应该可以解决我的问题,但我想知道是否已经在Ruby中实
在Ruby中,以毫秒为单位获取自纪元(1970)以来的当前系统时间的正确方法是什么?我试过了Time.now.to_i,好像不是我想要的结果。我需要结果显示毫秒并且使用long类型,而不是float或double。 最佳答案 (Time.now.to_f*1000).to_iTime.now.to_f显示包含十进制数字的时间。要获得毫秒数,只需将时间乘以1000。 关于ruby-以毫秒为单位获取当前系统时间,我们在StackOverflow上找到一个类似的问题:
我正在寻找用于Rails的优质管理插件。似乎大多数现有的插件/gem(例如“restful_authentication”、“acts_as_authenticated”)都围绕着self注册等展开。但是,我正在寻找一种功能齐全的基于管理/管理角色的解决方案——但不是简单地附加到另一个非基于角色的解决方案。如果我找不到,我想我会自己动手......只是不想重新发明轮子。 最佳答案 RyanBates最近做了两个关于授权的railscast(注意身份验证和授权之间的区别;身份验证检查用户是否如她所说的那样,授权检查用户是否有权访问资源
关闭。这个问题需要更多focused.它目前不接受答案。想改进这个问题吗?更新问题,使其只关注一个问题editingthispost.关闭8年前。Improvethisquestion我们有以下(以及更多)系统,我们将数据从一个应用推送/拉取到另一个:托管CRM(InsideSales.com)Asterisk电话系统(内部)横幅广告系统(openx,我们托管)潜在客户生成系统(自行开发)电子商务商店(spree,我们托管)工作板(本土)一些工作网站抓取+入站工作提要电子邮件传送系统(如Mailchimp,自主开发)事件管理系统(如eventbrite,自主开发)仪表板系统(大量图表和