智能温度系统(C51+DS18B20温度传感器+LM016L显示屏)

单片机课程设计,C51+DS18B20温度传感器+LM016L显示屏
重点在于两个外设的时序控制
模块化的设计结构清晰明了
一、题目
温度测量系统的设计

二、要求
1.温度测量范围:-55℃ ~ 125℃,测量精度 ±0.1℃
2.DS18B20作温度传感器,LCD1602作显示控制器
3.LCD1602显示器显示测量的温度值(一位符号,三位整数,一位小数)
显示分两行,如:
temperature is:
056.3℃

4.用proteus画出电器原理图并能仿真
5.程序清单
6.书写设计报告

三、使用软件及仿真环境
Keil uVision5
Proteus7.8

四、课程设计步骤
1.画出电路图
首先根据实验需求在proteus仿真软件中画出电路

需要选取的元器件有:
AT89C51(mcu) DS18B20(温度传感器)
LM016L(温度传感器) RES(上拉电阻)

电路图说明:
针对液晶显示器LM016L,D0D7引脚连接到C51的P1.0P1.7引脚,同时选取51单片机的P3.5、P3.6 、P3.7引脚作为LCD的控制输入端
针对DS18B20温度传感器,选取P2.0引脚作为数据传送、数据接收引脚。同时使用4.7K的上拉电阻连接P2.0
电路图连接完毕后,开始构建keil工程

2.keil工程构建
项目的整体构建使用Keil5进行完成,由于keil5主要编写stm32程序,对于c51程序需要导入相应的pack才能进行编写。
(1)安装C51 pack包
按照网上的教程进行操作较为简单
(2)构建项目结构
打开keil5工程,可以看到左侧的工作区脉络
在这里插入图片描述

Source Group 1为系统文件夹,文件夹中只存放main文件和STARTUP.A51启动文件
Bsp文件夹为自己创建的文件夹,自己写的.c文件和头文件都存放在这里,可以看到文件夹中包含了
delay.c:有关延迟的函数
lcd.c:LM016L的相关显示函数
temperature.c:DS18B20传感器相关函数
通过bsp_system.h头文件将bsp文件夹中的内容和Soure Group 1文件夹中的内容链接起来,保证函数能够进行调用。同时通过
#ifndef
#define
#endif
这三条预处理命令保证bsp_system.h头文件只会被编译一次,防止重复编译的问题出现。(其它头文件也添加这三段代码,防止重复编译)
在这里插入图片描述

可以看到在此头文件中,对LCD与温度传感器的控制引脚做了相对应的定义。如果硬件需要改变连接引脚,能够较快的进行程序的移植。
(3)功能函数
这一小节着重介绍各个C函数文件中的函数含义,以及核心代码。
1.delay.c

delay.c

#include "delay.h"

void delay1ms(uint timer) 
{
    unsigned char a, b, c;
    while (timer--)
    {
        for (c = 1; c > 0; c--)
            for (b = 142; b > 0; b--)
                for (a = 2; a > 0; a--)
                    ;
    }
}

void Delay_DS18B20(int num)
{
    while (num--)
        ;
}

delay.h

#ifndef _DElAY_H
#define _DELAY_H

#include "bsp_system.h"
#include "main.h"

void delay1ms(uint timer);
void Delay_DS18B20(int num);

#endif

void delay1ms(uint timer) 延迟1ms通过传入的timer参数进行延迟时间的控制
void Delay_DS18B20(int num) 微妙级延迟,由于DS18B20温度传感器对时序要求非常严格,经过多次函数编写才设计出这个us级的延迟函数。主要针对温度传感器的时序进行计时,控制传感器初始化、通信等过程。

2.lcd.c
LM016L液晶模块采用HD44780控制器。HD44780具有简单而功能较强的指令集,可以实现字符移动、闪烁等功能。LM016L与单片机MCU通讯可以采用8位或者4位并行传输两种方式。
要想控制LCD屏幕显示,需要通过对HD44780写入控制指令,HD44780产生显示驱动信号来驱动LM016L。
根据以上的信息描述,我们参照LM016L的操作手册进行程序的编写
lcd.c

#include "lcd.h"

unsigned char code dis1[] = {"temperature is :"};
//unsigned char code dis2[] = {"021.8 C"};

//ÅжÏLCDÊÇ·ñæµ
bit LCD_Buzy()
{
    bit result;
    rs = 0;
    rw = 1;
    ep = 1;
    _nop_();
    _nop_();
    _nop_();
    _nop_();
    result = (bit)(P1 & 0x80);
    ep = 0;
    return result;
}

void LCD_WriteByte(unsigned char cmd)
{
    while (LCD_Buzy())
        ;
    rs = 0;
    rw = 0;
    ep = 0;
    _nop_();
    _nop_();
    P1 = cmd;
    _nop_();
    _nop_();
    _nop_();
    _nop_();
    ep = 1;
    _nop_();
    _nop_();
    _nop_();
    _nop_();
    ep = 0;
}

void LCD_Pos(unsigned char pos)
{
    LCD_WriteByte(pos | 0x80);
}

void LCD_Display(unsigned char dat)
{
    while (LCD_Buzy())
        ;
    rs = 1;
    rw = 0;
    ep = 0;
    P1 = dat;
    _nop_();
    _nop_();
    _nop_();
    _nop_();
    ep = 1;
    _nop_();
    _nop_();
    _nop_();
    _nop_();
    ep = 0;
}

void LCD_Init()
{
    LCD_WriteByte(0x38);
    delay1ms(1);
    LCD_WriteByte(0x0c);
    delay1ms(1);
    LCD_WriteByte(0x06);
    delay1ms(1);
    LCD_WriteByte(0x01);
    delay1ms(1);
}

lcd.h

#ifndef _LCD_H
#define _LCD_H

#include "bsp_system.h"

extern unsigned char code dis1[];
extern unsigned char code dis2[];

bit LCD_Buzy();
void LCD_WriteByte(unsigned char cmd);
void LCD_Pos(unsigned char pos);
void LCD_Display(unsigned char dat);
void LCD_Init();

#endif

首先是 void LCD_Init() 对LCD进行初始化,需要向LCD中写入数据,于是引入
void LCD_WriteByte(unsigned char cmd) 函数对数据进行写入操作,通过LCD的操作时序图进行编写
在程序的写入过程中还需对进行判忙操作,也就是 bit LCD_Buzy() 函数,当LCD忙碌时,也就是result的值为1时,不能对LCD进行操作;result = 0 可以进行读写

最后是LCD显示操作,按照上面的函数编写,LCD的初始化已经完成,需要让LCD显示出我们想要展示的内容。
在显示字符时需要先输入显示字符地址,也就是告诉模块在哪里显示字符,同时在初始化的过程中先设置其显示模式。
在显示字符时,LCD显示模块内部的字符发生存储器(CGROM)已经存储了160个不同的点阵字符图形,每个字符都有一个固定的该骂,显示时模块把41H中的点阵字符图形显示出来,我们就能看到字符。
通过以上的描述可以知道,只需要知道LCD中字符代码与字符图形之间的对应关系,就能够让LCD显示对应的字符。
由此,编写出 void LCD_Display(unsigned char dat) 函数,对函数传入类型为 unsigned char类型的dat参数,反映了LCD显示的字符信息。每次显示一个字符,光标向后移位,然后显示下一个字符。

3.temperature.c
DS18B20是常用的数字温度传感器,具有体积小,硬件开销低,抗干扰性能力强,精度高的特点。
DS18B20数字温度计提供9位温度读数。信息经过单线接口送入DS118B20或从DS18B20送出,因此从中央处理器到DS18B20仅需要一条线。读写和完成温度变换所需的电源可以由数据本身提供,而不需要外部电源。
文件中描述了DS18B20的相关函数,包括温度传感器的初始化、读字符、写字符、读取温度、字符转换函数、温度显示函数,其中读取温度函数和温度显示函数为核心函数。
在编写函数时,特别注意延迟函数的准确性,DS18B20对时序要求极其严格,延迟函数不准确,传感器将不能进行初始化和读写操作。
同LCD显示一样,首先需要对温度传感器进行初始化。
通过 uchar DS18B20_Init(void) 函数对传感器进行初始化操作,主机首先发出一个480-960微秒的低电平脉冲,然后释放总线变为高电平,并在随后的480微秒时间内对总线进行检测,如果有低电平出现说明总线上有器件已做出应答。若无低电平出现一直都是高电平说明总线上无器件应答。
在调试传感器的过程中,可以通过temp变量承载DS18B20初始化函数的返回值,并通过LCD进行显示,便于我们进行调试。
temperature.c

#include "temperature.h"

//×Ö·ûת»»º¯Êý
uchar change(int a)
{
	uchar b;
	if (a == 0)
		b = '0';
	if (a == 1)
		b = '1';
	if (a == 2)
		b = '2';
	if (a == 3)
		b = '3';
	if (a == 4)
		b = '4';
	if (a == 5)
		b = '5';
	if (a == 6)
		b = '6';
	if (a == 7)
		b = '7';
	if (a == 8)
		b = '8';
	if (a == 9)
		b = '9';

	return b;
}

//DS18B20³õʼ»¯º¯Êý
uchar DS18B20_Init(void)
{
	unsigned char x = 0;
	DQ = 1;
	Delay_DS18B20(8);
	DQ = 0;
	Delay_DS18B20(80);
	DQ = 1;
	Delay_DS18B20(14);
	x = DQ;
	Delay_DS18B20(20);

	return x;
}

unsigned char DS18B20_ReadChar(void)
{
	unsigned char i = 0;
	unsigned char dat = 0;
	for (i = 8; i > 0; i--)
	{
		DQ = 0;
		dat >>= 1;
		DQ = 1;
		if (DQ)
			dat |= 0x80;
		Delay_DS18B20(4);
	}
	return dat;
}

void DS18B20_WriteChar(unsigned char dat)
{
	unsigned char i = 0;
	for (i = 8; i > 0; i--)
	{
		DQ = 0;
		DQ = dat & 0x01;
		Delay_DS18B20(5);
		DQ = 1;
		dat >>= 1;
	}
}

//¶ÁȡζÈ
int DS18B20_ReadTemperature(void)
{
	unsigned char a = 0;
	unsigned char b = 0;
	int t = 0;
	float tt = 0;
	DS18B20_Init();
	DS18B20_WriteChar(0xCC);
	DS18B20_WriteChar(0x44);
	DS18B20_Init();
	DS18B20_WriteChar(0xCC);
	DS18B20_WriteChar(0xBE);
	
	//µÚ°Ëλ¸ß°Ëλ
	a = DS18B20_ReadChar();
	b = DS18B20_ReadChar();
	t = b;
	t <<= 8;
	t = t | a;

	//ÕýÊý¡¢¸ºÊýµÄÊýÖµ´¦Àí
	if (t > 63488)
	{
		tt = ((~t) + 1) * 0.0625;
		t = tt * 10 + 0.5;
		return (-t);
	}

	else
	{
		tt = t * 0.0625;
		t = tt * 10 + 0.5;
		return (t);
	}
}

//ζÈÏÔʾº¯Êý
void Temp_Display(int temp)
{
	//ζȵİÙλ¡¢Ê®Î»¡¢¸öλ¡¢Ð¡Êý룬abs×÷ΪÖмä±äÁ¿²ÎÓëÊýÖµ´¦Àí
	int temp100, temp10, temp1, temp01, abs;
	uchar i;
	uchar local;	
	unsigned char temperature[7];
	//ÏÔʾӢÎÄ  temperature£º
	LCD_Pos(0x01);
	i = 0;
	while (dis1[i] != '\0')
	{
		LCD_Display(dis1[i]);
		i++;
	}

	//ÕýÊýζȺ͸ºÊýζȵķֿªÏÔʾ
	if (temp < 0)
	{
		temp = (~temp) + 1 + 1;
		abs = temp / 10;
		temp100 = abs / 100;				
		temp10 = (abs - temp100 * 100) / 10; 
		temp1 = abs % 10;					 
		temp01 = temp % 10;					 

		temperature[0] = '-';
		temperature[1] = change(temp10);
		temperature[2] = change(temp1);
		temperature[3] = '.';
		temperature[4] = change(temp01);
		temperature[5] = ' ';
		temperature[6] = 'C';

		local = 0x41;
		i = 0;
		//lcd_wcmd(0x0d);
		while (i < 7)
		{
			LCD_Pos(local);
			local++;
			LCD_Display(temperature[i]);
			i++;
		}
	}
	
	//ÕýÊýζÈ
	else
	{
		abs = temp / 10;
		temp100 = abs / 100;				 
		temp10 = (abs - temp100 * 100) / 10; 
		temp1 = abs % 10;					
		temp01 = temp % 10;					 

		temperature[0] = change(temp100);
		temperature[1] = change(temp10);
		temperature[2] = change(temp1);
		temperature[3] = '.';
		temperature[4] = change(temp01);
		temperature[5] = ' ';
		temperature[6] = 'C';

		local = 0x41;
		i = 0;

		//lcd_wcmd(0x0d);
		while (i < 7)
		{
			LCD_Pos(local);
			local++;
			LCD_Display(temperature[i]);
			i++;
		}
	}
}

temperature.h

#ifndef _TEMPERATURE_H
#define _TEMPERATURE_H

#include "bsp_system.h"

uchar change(int a);
uchar DS18B20_Init(void);
unsigned char DS18B20_ReadChar(void);
void DS18B20_WriteChar(unsigned char dat);
int DS18B20_ReadTemperature(void);
void Temp_Display(int temp);

#endif

初始化成功后,向温度传感器写入参数控制,即向单片机发送一条ROM指令,并发送存储器指令。
对于ROM的操作部分可以跳过,所以我们对传感器写入跳过ROM的操作指令(CCH)。然后对传感器写入转换温度的操作命令,让DS18B20完成专函的操作。在写命令时,要低字节先写。
下面要读取温度数据,首先主机复位,跳过ROM操作,读取RAM命令。同样,读取数据也是低位在前。
经过以上的时序分析,将读取温度函数整合起来。

此函数中,使用a,b两个变量值承载相应温度值的低八位和高八位。通过判断语句对正数值和负数值加以区分。
针对我们设置的传感器测量精度作相应的变换返回类型为 int 的温度值。
读取出温度后,自然要将温度显示出来,因此编写了
void Temp_Display(int temp) 函数
由 int DS18B20_ReadTemperature(void) 读取温度函数传递的值,是包含小数位在内的整数,需要对数据作一定的处理按位显示在LCD屏幕上。

4.main.c
当我们按照上面的模块化的设计方式,写出了硬件相关的函数后,main函数中的内容就变得十分简单。
首先通过 LCD_Init() 对液晶显示器进行初始化操作,然后调用DS18B20_Init(); 函数对温度传感器进行初始化,用flag变量标记传感器是否初始化成功。
然后调用 DS18B20_ReadTemperature(); 函数让温度传感器读取温度信息,并将温度储存在temp中。随后调用 Temp_Display(temp); 将温度数值显示出来。
最后通过延迟函数对系统的刷新频率作一定的控制。
main.c

#include <reg51.h>
#include "main.h"
#include "bsp_system.h"

void main()
{
	//uchar i;
	uchar flag;
	int temp;

	while (1)
	{
		//LCD³õʼ»¯¡¢ds18b20³õʼ»¯¡¢¶ÁȡζÈÏÔʾζÈ
		LCD_Init();
		flag = DS18B20_Init();
		temp = DS18B20_ReadTemperature();
		Temp_Display(temp);

		//Ò»¶¨µÄÑÓ³ÙζÈÏÔʾ¸üÎȶ¨
		delay1ms(750);
	}
}

main.h

#ifndef _MAIN_H
#define _MAIN_H

#define uint unsigned int
#define uchar unsigned char

#endif

bsp_system.h

#ifndef _BSP_SYSTEM_H
#define _BSP_SYSTEM_H

#include <stdio.h>
#include <reg51.h>
#include <intrins.h>
#include "delay.h"
#include "main.h"
#include "lcd.h"
#include "temperature.h"

//ÊäÈëÒý½Å¶¨Òå
sbit rs = P3 ^ 5;
sbit rw = P3 ^ 6;
sbit ep = P3 ^ 7;

//ζȴ«¸ÐÆ÷Òý½Å¶¨Òå
sbit DQ = P2 ^ 0;

//ÊäÈë×Ö·û´®¶¨Òå
extern unsigned char code dis1[];
extern unsigned char code dis2[];
//extern unsigned char temperature[7];

#endif

五、效果截图

在这里插入图片描述
在这里插入图片描述

(如果程序有什么缺失的地方留言一下~)

  • 10
    点赞
  • 123
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值