收藏和点赞,您的关注是我创造的动力
概要
时代每时每刻都在飞速地变化着,科学技术每分每秒也在不断发展,这是你我都有目共睹的。现代社会许多专业的机器都正在或多或少地向高精尖的技术靠近,变得更加数字化、智能化。那么想要达到更加智能化的控制,对于不管是现代科技化的农业,还是更加复杂化的工业,这些与生产相关的产业来说,对于温度的调整、测量和控制都是至关重要的。另一方面,在生活水平不断提高的今天,服务业更需要运用大量的数字智能化技术从而满足人们对高质量生活的追求。高级的电子技术的运用不仅使人们的生活变得更加的便利,而且在一定程度上减少了资源、能源消耗。
从前使用的非常传统的温度测量系统,基本原理和测量方法相较于现在都是稍落后的测量技术,可想而知这其中产生的误差肯定会比现在的更加精细准确的电子测量技术要多的多,这其中一点点误差产生的蝴蝶效应会导致整个系统或设备的性能大幅降低。传统的测量技术往往产生较大的由多点测量产生的切换误差,信号调节电路产生的误差,读取误差等等。由此本论文设计出一种数字测控的智能温度测控报警系统,由DS18B20作为温度传感器,LCD液晶数码管进行显示,搭配软件编程进行调试的报警系统。这种设计运用到的传感器发展方向是更加小型化,集成化和数字化。放眼现实生活,我想到做一种带有温度测控报警系统的保温杯服务于人们。
我们这次用的单片机是STM32型号的,用到的温度传感器是DS18B20型号的,用到的温度显示装置是1602版本的LCD液晶输出装置,最后用到的报警器是蜂鸣器。用到这些装置设计出来的保温杯不仅方便读取杯中液体的温度,最重要的是可以设置温度的范围,当温度不在设定范围内时进行报警。满足了人们对水温适宜把控的要求,尤其是很好地照顾到了婴幼儿。并且操作简单,体积微小,还可以使用一条总线和两个以上的功能元件进行连接,这样更能节省电压、能源。就算是在环境比较恶劣的情况下也可进行检测,非常耐用。
一、系统总体设计
1电路总体设计
我们用到检测温度的装置是DS18B20温度传感器,一般情况下,单片机的设计电路中都是用到传感器。DS18B20温度传感器有许多优点,它既可以快速又方便地检测出温度,还可以把检测的温度转换成电信号,完全达到了我们要求的标准。
图2.1是这种保温杯的温度测控系统的电路总设计方框图。把单片机STM32当作控制装置,DS18B20当作温度检测装置,然后用LCD1602液晶显示管来显示测量后的温度值。LCD1602显示电路、DB18B20温度传感器、单片机的接口电路、振荡电路、复位电路、电源电路和警报电路组成了硬件部分的电路。
2电路总原理图
原理图如下:
图2-2保温杯温度自动控制系统电路设计总体设计方框图
在图2.2,有三个独立的键用于调整保温杯温度自动测控系统的上限和下限报警设置。图里面的蜂鸣报警电路的作用是当温度没有在设定范围内的时候发出报警。主程序在这个时候发送指令使得LED数码管就不会显示出测量的温度值。这样是对警报装置的触发范围设置一个界限值。当温度没在测定范围内时,数码管上不出现测量值,这样报警装置就被限定了触发范围。
我们还设计了一个复位电路,目的是增加手动复位,变得更容易操作了。当我们要进行程序运行调试,只需要按一下按钮就可以了,不需要重启电源键。
二、主程序流程图
软件部分设计的整个系统除了主控程序之外还有三个模块,包括温度检测模块,信息转换传递模块和输出模块。
DS18B20具有强大的温度测量能力,并且所需要的时间非常短暂,每一秒钟可以进行一次测量包括信号转换、传输结果共用的时间。图数据处理程序结束后转到主程序的流程是可以一直显示温度在数码管上,这样可以在一开始使用的阶段知道要不要对上下限做出调整。流程图如下:
图4-1键盘显示系统电路图
数码管可以将当前环境中的用户规定的温度上限和下限值输出,当检测的温度超过了规定的上限值时,会触发警报,此时D4会闪亮,然后程序下达散热器打开的指令进行降温,当温度下降直至温度值低于设置的下限温度值,报警器也会响起,此时D3灯亮,系统下达指令打开加热器进行升温。本系统可以达到智能化测控温度。
仿真电路图
如图5.1所示。
图5-1仿真电路图
三、 主要代码
主程序:
源代码:
#include <reg52.h> //调用单片机头文件
#define uchar unsigned char //无符号字符型 宏定义 变量范围0~255
#define uint unsigned int //无符号整型 宏定义 变量范围0~65535
#include <intrins.h>
sbit dq = P1^5; //18b20 IO口的定义
sbit fengshan = P1^4; //风扇IO口定义
uint temperature ; //
bit flag_300ms ;
bit flag_lj_en; //按键连加使能
bit flag_lj_3_en; //按键连3次连加后使能 加的数就越大了
uchar key_time,key_value; //用做连加的中间变量
bit key_500ms ;
uchar code table_num[]="0123456789abcdefg";
sbit rs=P1^0; //寄存器选择信号 H:数据寄存器 L:指令寄存器
sbit rw=P1^1; //寄存器选择信号 H:数据寄存器 L:指令寄存器
sbit e =P1^2; //片选信号 下降沿触发
uchar menu_1; //菜单设计的变量
uint t_high = 350,t_low = 100;
sbit relay1 = P1^6; //温度报警继电器IO口定义
sbit relay2 = P1^3; //湿度报警继电器IO口定义
/***********************1ms延时函数*****************************/
void delay_1ms(uint q)
{
uint i,j;
for(i=0;i<q;i++)
for(j=0;j<110;j++);
}
/********************************************************************
* 名称 : delay_uint()
* 功能 : 小延时。
* 输入 : 无
* 输出 : 无
***********************************************************************/
void delay_uint(uint q)
{
while(q--);
}
/********************************************************************
* 名称 : write_com(uchar com)
* 功能 : 1602命令函数
* 输入 : 输入的命令值
* 输出 : 无
***********************************************************************/
void write_com(uchar com)
{
e=0;
rs=0;
rw=0;
P0=com;
delay_uint(25);
e=1;
delay_uint(100);
e=0;
}
/********************************************************************
* 名称 : write_data(uchar dat)
* 功能 : 1602写数据函数
* 输入 : 需要写入1602的数据
* 输出 : 无
***********************************************************************/
void write_data(uchar dat)
{
e=0;
rs=1;
rw=0;
P0=dat;
delay_uint(25);
e=1;
delay_uint(100);
e=0;
}
/********************************************************************
* 名称 : write_string(uchar hang,uchar add,uchar *p)
* 功能 : 改变液晶中某位的值,如果要让第一行,第五个字符开始显示"ab cd ef" ,调用该函数如下
write_string(1,5,"ab cd ef;")
* 输入 : 行,列,需要输入1602的数据
* 输出 : 无
***********************************************************************/
void write_string(uchar hang,uchar add,uchar *p)
{
if(hang==1)
write_com(0x80+add);
else
write_com(0x80+0x40+add);
while(1)
{
if(*p == '\0') break;
write_data(*p);
p++;
}
}
/***********************lcd1602上显示特定的字符************************/
void write_zifu(uchar hang,uchar add,uchar date)
{
if(hang==1)
write_com(0x80+add);
else
write_com(0x80+0x40+add);
write_data(date);
}
/***********************lcd1602上显示两位十进制数************************/
void write_sfm3_18B20(uchar hang,uchar add,uint date)
{
if(hang==1)
write_com(0x80+add);
else
write_com(0x80+0x40+add);
write_data(0x30+date/100%10);
write_data(0x30+date/10%10);
write_data('.');
write_data(0x30+date%10);
}
/***********************lcd1602初始化设置************************/
void init_1602()
{
write_com(0x38); //
write_com(0x0c);
write_com(0x06);
delay_uint(1000);
write_string(1,0," temp: . ");
write_string(2,0,"H: . L: . ");
write_zifu(1,12,0xdf); //显示度
write_zifu(2,6, 0xdf); //显示度
write_zifu(2,14,0xdf); //显示度
}
/***********************18b20初始化函数*****************************/
void init_18b20()
{
bit q;
dq = 1; //把总线拿高
delay_uint(1); //15us
dq = 0; //给复位脉冲
delay_uint(80); //750us
dq = 1; //把总线拿高 等待
delay_uint(10); //110us
q = dq; //读取18b20初始化信号
delay_uint(20); //200us
dq = 1; //把总线拿高 释放总线
}
/*************写18b20内的数据***************/
void write_18b20(uchar dat)
{
uchar i;
for(i=0;i<8;i++)
{ //写数据是低位开始
dq = 0; //把总线拿低写时间隙开始
dq = dat & 0x01; //向18b20总线写数据了
delay_uint(5); // 60us
dq = 1; //释放总线
dat >>= 1;
}
}
/*************读取18b20内的数据***************/
uchar read_18b20()
{
uchar i,value;
for(i=0;i<8;i++)
{
dq = 0; //把总线拿低读时间隙开始
value >>= 1; //读数据是低位开始
dq = 1; //释放总线
if(dq == 1) //开始读写数据
value |= 0x80;
delay_uint(5); //60us 读一个时间隙最少要保持60us的时间
}
return value; //返回数据
}
/*************读取温度的值 读出来的是小数***************/
uint read_temp()
{
uint value;
uchar low; //在读取温度的时候如果中断的太频繁了,就应该把中断给关了,否则会影响到18b20的时序
init_18b20(); //初始化18b20
write_18b20(0xcc); //跳过64位ROM
write_18b20(0x44); //启动一次温度转换命令
delay_uint(50); //500us
init_18b20(); //初始化18b20
write_18b20(0xcc); //跳过64位ROM
write_18b20(0xbe); //发出读取暂存器命令
low = read_18b20(); //读温度低字节
value = read_18b20(); //读温度高字节
value <<= 8; //把温度的高位左移8位
value |= low; //把读出的温度低位放到value的低八位中
value *= 0.625; //转换到温度值 小数
return value; //返回读出的温度 带小数
}
/*************定时器0初始化程序***************/
void time_init()
{
EA = 1; //开总中断
TMOD = 0X01; //定时器0、定时器1工作方式1
ET0 = 1; //开定时器0中断
TR0 = 1; //允许定时器0定时
}
/********************独立按键程序*****************/
uchar key_can; //按键值
void key() //独立按键程序
{
static uchar key_new;
key_can = 20; //按键值还原
P3 |= 0xf0;
if(key_500ms == 1) //连加
{
key_500ms = 0;
key_new = 1;
}
if((P3 & 0xf0) != 0xf0) //按键按下
{
delay_1ms(1); //按键消抖动
if(((P3 & 0xf0) != 0xf0) && (key_new == 1))
{ //确认是按键按下
key_new = 0;
switch(P3 & 0xf0)
{
case 0xd0: key_can = 3; break; //得到k1键值
case 0xb0: key_can = 2; break; //得到K2键值
case 0x70: key_can = 1; break; //得到k3键值
}
flag_lj_en = 1; //连加使能
}
}
else
{
if(key_new == 0)
{
key_new = 1;
flag_lj_en = 0; //关闭连加使能
key_value = 0; //清零
key_time = 0;
}
}
}
/****************按键显示函数***************/
void key_with()
{
if(key_can == 1) //设置键
{
menu_1 ++;
if(menu_1 >= 3)
{
menu_1 = 0;
}
if(menu_1 == 0)
{
write_com(0x0c); //关闭光标
}
}
if(menu_1 == 1) //设置高温报警
{
if(key_can == 2)
{
if(flag_lj_3_en == 0)
t_high ++ ; //按键按下未松开自动加三次
else
t_high += 10; //按键按下未松开自动加三次之后每次自动加10
if(t_high > 990)
t_high = 990;
}
if(key_can == 3)
{
if(flag_lj_3_en == 0)
t_high -- ; //按键按下未松开自动减三次
else
t_high -= 10; //按键按下未松开自动减三次之后每次自动减10
if(t_high <= t_low)
t_high = t_low + 1;
}
write_sfm3_18B20(2,2,t_high);
write_com(0x80+0x40+2); //将光标移动到秒个位
write_com(0x0f); //显示光标并且闪烁
}
if(menu_1 == 2) //设置低温报警
{
if(key_can == 2)
{
if(flag_lj_3_en == 0)
t_low ++ ; //按键按下未松开自动加三次
else
t_low += 10; //按键按下未松开自动加三次之后每次自动加10
if(t_low >= t_high)
t_low = t_high - 1;
}
if(key_can == 3)
{
if(flag_lj_3_en == 0)
t_low -- ; //按键按下未松开自动减三次
else
t_low -= 10; //按键按下未松开自动加三次之后每次自动加10
if(t_low <= 10)
t_low = 10;
}
write_sfm3_18B20(2,10,t_low);
write_com(0x80+0x40+10); //将光标移动到秒个位
write_com(0x0f); //显示光标并且闪烁
}
}
/****************报警函数***************/
void clock_h_l()
{
static uchar value;
if((temperature <= t_low) || (temperature >= t_high))
{
value ++; //消除实际距离在设定距离左右变化时的干扰
if(value >= 2)
{
if(temperature <= t_low)
relay1 = 0; //打开继电器
if(temperature >= t_high)
relay2 = 0; //打开继电器
fengshan = 1;
}
}
else
{
fengshan = 0; //风扇转
value = 0;
relay1 = 1; //关闭继电器
relay2 = 1; //关闭继电器
}
}
/****************主函数***************/
void main()
{
init_1602(); //1602初始化
time_init(); //初始化定时器
while(1)
{
if(flag_300ms == 1) //300ms 处理一次温度程序
{
flag_300ms = 0;
temperature = read_temp(); //先读出温度的值
clock_h_l(); //报警函数
write_sfm3_18B20(1,8,temperature);
}
key(); //按键程序
if(key_can < 10)
{
key_with(); //设置报警温度
}
}
}
/*************定时器0中断服务程序***************/
void time0_int() interrupt 1
{
static uchar value;
TH0 = 0x3c;
TL0 = 0xb0; // 50ms
value ++;
if(value % 6 == 0)
{
flag_300ms = 1; //300ms
value = 0;
}
if(flag_lj_en == 1) //按下按键使能
{
key_time ++;
if(key_time >= 10) //500ms
{
key_value ++;
if(key_value > 3)
{
key_value = 10;
flag_lj_3_en = 1; //3次后1.5秒连加大些
}
}
}
}
四、 内容截图
五、 文章目录
目 录
摘要…………………………………………………………Ⅰ
Abstract…………………………………………………………Ⅱ
1绪论……………………………………………………………… 1
2系统总体设计……………………………………………………4
2.1电路总体设计…………………………………………2
2.2电路总原理图………………………………………………2
3系统各部分硬件电路……………………………………………4
3.1显示电路………………………………………………………2
3.2温度传感器与单片机的接口电路……………………………2
3.3振荡电路………………………………………………………2
3.4复位电路………………………………………………………2
3.5报警电路………………………………………………………2
3.6键盘显示电路…………………………………………………2
4软件部分设计……………………………………………………4
4.1主程序流程图…………………………………………………2
4.2各子程序流程图………………………………………………2
5系统测试…………………………………………………………4
5.1系统测试………………………………………………………2
5.2测试结果………………………………………………………2
6结论………………………………………………………………60
参考文献………………………………………………………… 61
致谢………………………………………………………………62
附录………………………………………………………………62