单片机课程设计,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
五、效果截图
(如果程序有什么缺失的地方留言一下~)