一、绪论
- 智能温度仪设计的背景
随着科学技术的不断进步与发展,温度传感器的种类日益繁多,应用逐渐广泛。数字温度传感器因其适用于各种微处理器接口,具有较高的市场占有率。其中,DS18B20具有全数字温度转换及输出、先进的单总线数据通信、可选择工作方式、检测温度范围广、内置EEPROM和限温报警功能等优点。但其精度在-10°C ~ +85°C下仅能达到±0.5°C,这与其测温原理有关。 - 智能温度仪的现状
前几年,由于新冠病毒疫情的原因,智能温度检测仪需求量大幅增加,在各行业得到广泛应用。同时,智能温度检测仪也在不断升级和完善,检测的准确性和便捷性不断提高。然而,仍有一些智能温度检测仪存在误差较大、操作复杂等问题,需要进一步改进和优化。智能温度计在市场上越来越受欢迎,其技术不断提升,可选性更加丰富,价格逐渐下降,市场潜力持续增长。 - 智能温度仪研究的意义
传感器是一种检测装置,能将检测感受到的信息按一定规律变换成为电信号或其他所需形式的信息输出,以满足信息的传输、处理、存储、显示、记录和控制等要求。智能温度仪能够实现自动测量和自动控制,对于提高生产效率和生活质量具有重要意义。
二、智能温度仪的相关理论与总体设计概述
- 智能温度仪系统功能概述
该智能温度检测仪可以通过DS18B20温度传感器进行温度的采集,使用AT24C02存储模块实现五次温度采集的掉电保存,还具有最大采集温度的计算以及最近一次采集温度的保存功能。温度的采集以及计算功能与矩阵键盘相结合,按下不同的按键,LCD1602显示屏会有不同的显示界面,包括实时温度显示界面、最大温度显示界面、保存此刻温度界面、最近一次保存温度显示界面、平均温度显示界面、闪烁LED和蜂鸣器显示界面。 - 智能温度仪的整体设计
本设计主要由主控制器STC89C52、DS180B20温度传感器、LED灯显示、蜂鸣器和按键部分组成。通过DS18B20进行外部温度的采集,矩阵键盘输入控制模式切换,AT24C02进行温度数据的存储和掉电保护,蜂鸣器和LED实现闪烁功能。
三、智能温度仪的硬件设计
- 硬件总体设计
采用集成的单片机主控,通过温度传感器、A/D转换采集数据信息,经过含有单片机的检测系统检测,将结果传送到单片机控制的主控器,数据通过LCD显示器显示。 - 智能温度仪的选型及电路
本设计中温度传感器选择DS18B20,其具有接线方便、耐磨耐碰、体积小、使用方便、封装形式多样等优点,适应电压范围更宽,支持多点组网功能,在使用中不需要任何外围元件,具有极强的抗干扰纠错能力。显示模块采用LCD1602显示屏,它是一种专门用来显示字母、数字、符号的点阵型液晶模块。
四、智能温度仪的软件设计
- 主控制器的软件设计
主控制器程序流程包括LCD1602初始化、采集温度、按键处理、LCD1602显示界面和LED处理函数等。
- 智能温度仪的子函数的软件设计
- 按键判断函数:通过keyjudge函数执行按键判断,根据按键扫描结果执行相应功能,并通过LCD1602显示。
- LCD显示温度函数:由lcdwendu子函数完成,先进行温度的转换和读取,根据温度大小进行显示,包括整数、小数点和小数部分。
- 按键扫描函数:扫描I/O口,检测按键按下、延时、再次检测按键按下以及按键释放等情况,执行相应代码。
五、智能温度仪设计的调试与运行
在调试过程中遇到了一些问题,如AT24C02中数据存储范围与温度数据显示位数不匹配、LCD1602显示字符串时有重影以及按键读取不稳定等。通过将温度数据分为整数和小数部分储存、在字符串中加入空格保证覆盖显示效果以及调整按键扫描方式等解决了这些问题。
六、总结
本设计能够较为准确地显示实时温度、最近一次保存的温度、最近五次内保存的最高温度和最近几次内的平均温度,还具有led闪烁和蜂鸣器的功能。但存在按键K2保存温度有时不成功的问题,其他按键功能正常。
七、代码
main.c
#include <REGX52.H>
#include "LCD1602.h"
#include "DS18B20.h"
#include "Delay.h"
#include "MatrixKey.h"
#include "display.h"
extern unsigned char KeyNum;
void main()
{
DS18B20_ConvertT(); //上电先转换一次温度,防止第一次读数据错误
Delay(1000); //等待转换完成
LCD_Init(); //LCD初始化
LCD_ShowString(1,1,"T:");
while(1)
{
KeyNum = MatrixKey(); //按键扫描
keyjudge(); //按键的判断
flagjudge(); //标志位的判断和lcd显示
}
}
lcd1602.c
#include <REGX52.H>
//引脚配置:
sbit LCD_RS = P2^6;
sbit LCD_RW = P2^5;
sbit LCD_EN = P2^7;
#define LCD_DataPort P0
//函数定义:
/**
* @brief LCD1602延时函数,12MHz调用可延时1ms
* @param 无
* @retval 无
*/
void LCD_Delay()
{
unsigned char i, j;
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
/**
* @brief LCD1602写命令
* @param Command 要写入的命令
* @retval 无
*/
void LCD_WriteCommand(unsigned char Command)
{
LCD_RS = 0;
LCD_RW = 0;
LCD_DataPort = Command;
LCD_EN = 1;
LCD_Delay();
LCD_EN = 0;
LCD_Delay();
}
/**
* @brief LCD1602写数据
* @param Data 要写入的数据
* @retval 无
*/
void LCD_WriteData(unsigned char Data)
{
LCD_RS = 1;
LCD_RW = 0;
LCD_DataPort = Data;
LCD_EN = 1;
LCD_Delay();
LCD_EN = 0;
LCD_Delay();
}
/**
* @brief LCD1602设置光标位置
* @param Line 行位置,范围:1~2
* @param Column 列位置,范围:1~16
* @retval 无
*/
void LCD_SetCursor(unsigned char Line, unsigned char Column)
{
if(Line == 1)
{
LCD_WriteCommand(0x80 | (Column - 1));
}
else if(Line == 2)
{
LCD_WriteCommand(0x80 | (Column - 1 + 0x40));
}
}
/**
* @brief LCD1602初始化函数
* @param 无
* @retval 无
*/
void LCD_Init()
{
LCD_WriteCommand(0x38); //八位数据接口,两行显示,5*7点阵
LCD_WriteCommand(0x0c); //显示开,光标关,闪烁关
LCD_WriteCommand(0x06); //数据读写操作后,光标自动加一,画面不动
LCD_WriteCommand(0x01); //光标复位,清屏
}
/**
* @brief 在LCD1602指定位置上显示一个字符
* @param Line 行位置,范围:1~2
* @param Column 列位置,范围:1~16
* @param Char 要显示的字符
* @retval 无
*/
void LCD_ShowChar(unsigned char Line, unsigned char Column, char Char)
{
LCD_SetCursor(Line, Column);
LCD_WriteData(Char);
}
/**
* @brief 在LCD1602指定位置开始显示所给字符串
* @param Line 起始行位置,范围:1~2
* @param Column 起始列位置,范围:1~16
* @param String 要显示的字符串
* @retval 无
*/
void LCD_ShowString(unsigned char Line, unsigned char Column, char *String)
{
unsigned char i;
LCD_SetCursor(Line, Column);
for(i = 0; String[i]!= '\0'; i++)
{
LCD_WriteData(String[i]);
}
}
/**
* @brief 返回值 = X的Y次方
*/
int LCD_Pow(int X, int Y)
{
unsigned char i;
int Result = 1;
for(i = 0; i < Y; i++)
{
Result *= X;
}
return Result;
}
/**
* @brief 在LCD1602指定位置开始显示所给数字
* @param Line 起始行位置,范围:1~2
* @param Column 起始列位置,范围:1~16
* @param Number 要显示的数字,范围:0~65535
* @param Length 要显示数字的长度,范围:1~5
* @retval 无
*/
void LCD_ShowNum(unsigned char Line, unsigned char Column, unsigned int Number, unsigned char Length)
{
unsigned char i;
LCD_SetCursor(Line, Column);
for(i = Length; i > 0; i--)
{
LCD_WriteData(Number / LCD_Pow(10, i - 1) % 10 + '0');
}
}
/**
* @brief 在LCD1602指定位置开始以有符号十进制显示所给数字
* @param Line 起始行位置,范围:1~2
* @param Column 起始列位置,范围:1~16
* @param Number 要显示的数字,范围:-32768~32767
* @param Length 要显示数字的长度,范围:1~5
* @retval 无
*/
void LCD_ShowSignedNum(unsigned char Line, unsigned char Column, int Number, unsigned char Length)
{
unsigned char i;
unsigned int Number1;
LCD_SetCursor(Line, Column);
if(Number >= 0)
{
LCD_WriteData('+');
Number1 = Number;
}
else
{
LCD_WriteData('-');
Number1 = -Number;
}
for(i = Length; i > 0; i--)
{
LCD_WriteData(Number1 / LCD_Pow(10, i - 1) % 10 + '0');
}
}
/**
* @brief 在LCD1602指定位置开始以十六进制显示所给数字
* @param Line 起始行位置,范围:1~2
* @param Column 起始列位置,范围:1~16
* @param Number 要显示的数字,范围:0~0xFFFF
* @param Length 要显示数字的长度,范围:1~4
* @retval 无
*/
void LCD_ShowHexNum(unsigned char Line, unsigned char Column, unsigned int Number, unsigned char Length)
{
unsigned char i, SingleNumber;
LCD_SetCursor(Line, Column);
for(i = Length; i > 0; i--)
{
SingleNumber = Number / LCD_Pow(16, i - 1) % 16;
if(SingleNumber < 10)
{
LCD_WriteData(SingleNumber + '0');
}
else
{
LCD_WriteData(SingleNumber - 10 + 'A');
}
}
}
/**
* @brief 在LCD1602指定位置开始以二进制显示所给数字
* @param Line 起始行位置,范围:1~2
* @param Column 起始列位置,范围:1~16
* @param Number 要显示的数字,范围:0~1111 1111 1111 1111
* @param Length 要显示数字的长度,范围:1~16
* @retval 无
*/
void LCD_ShowBinNum(unsigned char Line, unsigned char Column, unsigned int Number, unsigned char Length)
{
unsigned char i;
LCD_SetCursor(Line, Column);
for(i = Length; i > 0; i--)
{
LCD_WriteData(Number / LCD_Pow(2, i - 1) % 2 + '0');
}
}