Proteus仿真-数码管显示温度(实验三)

文章参考资料
http://www.51hei.com/bbs/dpj-91394-1.html (基于DS18B20温度传感器温控系统的Proteus仿真)
https://wenku.baidu.com/view/662b48eda0116c175e0e4857.html (LCD1602液晶显示完全资料)
https://max.book118.com/html/2017/0609/112708606.shtm (单片机与液晶显示器的接口)

一、实验目的

1.了解温度传感器DS18B20原理
2.了解液晶显示器的工作原理
3.学会DS18B20温度传感器数码管显示
4.学会DS18B20温度传感器液晶显示.




二、实验原理

DS18B20 传感器具有以下一些特性:
(1) 测温范围-55℃至+125℃,在-10℃至+85℃时的精度为正负 0.5℃; (2) 适应电压的范围在 3.0 至 5.5V;
(3) 单线接口,只用一条口线就可以与微处理器的双向通信;
(4) 支持多点组网,多个 DS18B20 并接在一根口线上就可实现多点测温;
(5) 测量结果直接输出数字温度信号,通过单线串行传输给微处理器;
(6) 具有负压特性,电源极性接反芯片不会烧坏,只是不能正常工作;
(7) 可编程分辨率为 9 至 12 位,对应的分辨温度分别是 0.5℃,0.25℃,0.125℃,
0.0625℃,能够实现高精度测温。
(8) 在 9 位分辨率时可在 93.75ms 内把温度值转换为数字;在 12 位分辨率时可在
750us 内把温度值转换为数字;
(9) 传送数据时可传送 CRC 校验码,抗干扰纠错能力强
在这里插入图片描述
DQ 端外接一个上拉电阻,与处理器的任一端口连接
在这里插入图片描述

DS18B20控制命令.

33H——读ROM(读取温度传感器ROM中的编码)
55H——匹配ROM(发出该指令后,再发64位ROM编码,用于匹配相应的DS18B20)
F0H——搜索ROM用于确定挂接在同一总线上DS18B20的数量(DS18B20支持多点组网)
CCH——跳过ROM,忽略64位ROM地址,直接向DS18B20发温度变换命令
ECH——告警搜索命令,执行后只有温度超过设定值的上下限才做出响应.
44H——温度转换,启动DS18B20进行温度转换
BEH——读温度暂存器,读内部RAM中9字节的温度数据
4EH——写暂存器.

主机与单个 DS18B20 连接时,不需要读取或者匹配 ROM,只要使用跳过指令 CCH,就可以进行数据转换和读取操作。




工作时序图

在这里插入图片描述
Step1:数据线置低电平
Step2:延时 800us 左右(时间范围为 480us 至 960us)
Step3:数据线拉高电平
Step4:延时 40us 左右(时间范围为 15us 至 60us)

在这里插入图片描述
逐位读取数据,然后把 8 位数据组成 1 个字节。编写程序时分为两个部分,一个实现读
取一位数据,另一个实现读取一个字节数据。
读取数据步骤
Step1:数据线置低电平
Step2:延时5us左右(大于1us)
Step3:数据线置高电平
Step4:延时10us(这次延时和第一次延时之和接近15us左右)
Step5:读取一位数据
Step6:延时60us左右(大于45us)
Step7:重复上面步骤,直到读完一个字节

在这里插入图片描述
写入数据分为写数据位1和数据位0
写数据1步骤:
Step1:数据线置低电平
Step2:延时5us左右(大于1us左右)
Step3:数据线置高电平
Step4:延时70us左右(大于55us即可)
写数据0步骤:
Step1:数据线置低电平
Step2:延时70us左右(大于60us左右)
Step3:数据线置高电平
Step4:延时5us左右

我们已经了解了温度传感器的工作方式,但如何从温度传感器读取数据显示到液晶上面来呢?这里虽然也可以用数码管显示,但相比数码管,液晶似乎更好一点,在此之前,我们必须先了解一下液晶的工作原理.

在这里插入图片描述
温度寄存器由两个字节组成,分为低8位和高8位。一共16位。
其中,第0位到第3位,存储的是温度值的小数部分。
第4位到第10位存储的是温度值的整数部分。
第11位到第15位为符号位。全0表示是正温度,全1表示是负温度。
表格中的数值,如果相应的位为1,表示存在。如果相应的位为0,表示不存在




液晶显示

在这里插入图片描述
LM016L的基本构造与引脚说明:
VSS-接地.
VDD-电源正极
VEE—液晶对比度调整端,接正电源时对比度最弱,接地电源时对比度最高,对比度过高时会产生“鬼影”,使用时可以通过一个10K的电位器调整对比度
RS—数据/命令选择—寄存器选择,高电平时选择数据寄存器、低电平时选择指令寄存器
RW—读写信号选择,高电平时进行读操作,低电平时进行写操作。当RS和RW共同为低电平时可以写入指令或者显示地址,当RS为低电平RW为高电平时可以读忙信号,当RS为高电平RW为低电平时可以写入数据。
E—使能信号;当E端由高电平跳变成低电平时,液晶模块执行命令。
D0~D7—8位双向数据口;




关于RW,RS的操作时序

在这里插入图片描述

在软件控制问题中,需要注意几个问题—基本问题:各时段的端口状态(电平)

  1. 液晶显示器的初始化—设置初始状态—置显示状态(电源、控制、数据端口等电平)

  2. 控制口RS/RW的控制指令变化—检测、延时、检测—发送数据问题(电平)

  3. 输出数据的获取与传递(读取/写入电平)

在编写 LCD1602 程序前,我们必须了解其手册上一些非常重要的
信息,如果这些信息不能理解透彻,编程可能会遇到或多或少的
问题.

指令集:

LCD_1602 初始化指令小结:

0x38 设置 162 显示,57 点阵,8 位数据接口
0x01 清屏
0x0F 开显示,显示光标,光标闪烁
0x08 只开显示
0x0e 开显示,显示光标,光标不闪烁
0x0c 开显示,不显示光标
0x06 地址加 1,当写入数据的时候光标右移
0x02 地址计数器 AC=0;(此时地址为 0x80) 光标归原点,但
是 DDRAM 中断内容不变

数据位如下
在这里插入图片描述
在这里插入图片描述
0x80是第一行的第一个字符,0x80+1是第一行第二个,0x80+0x40是第二行第一个地址
写入显示地址时,要求最高位D7恒为高电平,即1000 0000 + 0100 0000 = 0x80 + 0x40




三、实验器件

1.DS18B20温度传感器
2.共阴数码管7SEG
3.LM016L液晶显示



四、实验实现


数码管实现

在这里插入图片描述

#include <reg52.h>                 
unsigned char code seg7code[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,
                       0x07,0x7f,0x6f};
code unsigned char seg7codeB[]={0xbf,0x86,0xdb,0xcf,0xe6,0xed,
                               0xfd,0x87,0xff,0xef,0x00}; //带小数点的共阴数码管段码

sbit DQ=P3^5; //数据传输线接单片机的相应的引脚 
unsigned char tempL=0; 	//设全局变量
unsigned char tempH=0; 
unsigned int sdata;		//测量到的温度的整数部分
unsigned char xiaoshu1; //小数第一位
unsigned char xiaoshu2; //小数第二位
unsigned char xiaoshu;  //两位小数
bit  fg=1;              //温度正负标志


//******************延时子程序*******************************

//这个延时程序的具体延时时间是time=i*8+10,适用于小于2ms的延时

//************************************************************
void delay(unsigned char i)
{
	 for(i;i>0;i--);
}

//***********************************************************

//                     延时子程序

//************************************************************
void delay1ms(int n)
{
	 unsigned char i;
	 for(i=124*n;i>0;i--);  //延时124*8+10=1002us
}

//*****************************初始化程序 *********************************//

void Init_DS18B20(void) 
{
	unsigned char x=0;
	DQ=1; //DQ先置高 
	delay(8); //稍延时
	DQ=0; //发送复位脉冲 
	delay(80); //延时(>480us) 
	DQ=1; //拉高数据线 
	delay(5); //等待(15~60us) 
	x=DQ; //用X的值来判断初始化有没有成功,18B20存在的话X=0,否则X=1 
	delay(20); 
} 


//**********读一个字节************//

ReadOneChar(void)  //主机数据线先从高拉至低电平1us以上,再使数据线升为高电平,从而产生读信号
{
	unsigned char i=0; //每个读周期最短的持续时间为60us,各个读周期之间必须有1us以上的高电平恢复期
	unsigned char dat=0; 
	for (i=8;i>0;i--) //一个字节有8位 
	{
		DQ=1; 
		delay(1); 
		DQ=0;
		dat>>=1; 	   //数据移位
		DQ=1; 
		if(DQ) 
		dat|=0x80; 	   //得读取数据线得到一个状态
		delay(4);
} 
return(dat);
} 

//*********************** **写一个字节**************************//

void WriteOneChar(unsigned char dat) 
{ 
	unsigned char i=0; //数据线从高电平拉至低电平,产生写起始信号。15us之内将所需写的位送到数据线上,
	for(i=8;i>0;i--) //在15~60us之间对数据线进行采样,如果是高电平就写1,低写0发生。 
	{
		DQ=0; //在开始另一个写周期前必须有1us以上的高电平恢复期。 
		DQ=dat&0x01;  //按低位发送数据
		delay(5); 
		DQ=1; 
		dat>>=1;
	} 
	delay(4);
} 


//读温度值(低位放tempL;高位放tempH;)
void ReadTemperature(void) 
{ 
	Init_DS18B20(); //初始化
	WriteOneChar(0xcc); //跳过读序列号的操作
	WriteOneChar(0x44); //启动温度转换
	delay(125); //转换需要一点时间,延时 
	Init_DS18B20(); //初始化
	WriteOneChar(0xcc); //跳过读序列号的操作 
	WriteOneChar(0xbe); //读温度寄存器(头两个值分别为温度的低位和高位) 
	tempL=ReadOneChar(); //读出温度的低位LSB
	tempH=ReadOneChar(); //读出温度的高位MSB 
	
	if(tempH>0x7f)      //最高位为1时温度是负
	{
		 tempL=~tempL;         //补码转换,取反加一
		 tempH=~tempH+1;       
		 fg=0;      //读取温度为负时fg=0
	}
	sdata = tempL/16+tempH*16;      //整数部分
	xiaoshu1 = (tempL&0x0f)*10/16; //小数第一位
	xiaoshu2 = (tempL&0x0f)*100/16%10;//小数第二位
	xiaoshu=xiaoshu1*10+xiaoshu2; //小数两位
}


//********************显示函数****************
void Led(unsigned int date)
{ 
	/*
		困惑很久,之前有问题,现在没了.
	*/
	P1=0xfb;     //P1.0=0,选通第一位
	P0=seg7code[date/10];  //十位数,查表,输出
	delay1ms(1);

	P1=0xfd;     //P1.1=0,选通第二位,个位数
	P0=seg7codeB[date%10];
	delay1ms(1);
 	
	P1=0xfe;     //P1.3=0,选通第三位,小数点第一位
	P0=seg7code[xiaoshu1];
	delay1ms(1);
}

//**************************** //主程序 
void main()
{  	
	unsigned int i;
	while(1)
	{
		ReadTemperature(); //读取温度 
		for(i=0;i<20;i++)
		{
			Led(sdata);		  //显示温度
		}
	}
}



LM016L实现

在这里插入图片描述

#include <reg52.h>                 
#define uchar unsigned char
#define uint unsigned int
sbit LCDEN = P2^0;
sbit LCDRW = P2^1;
sbit LCDRS = P2^2;
sbit LCDTP = P2^3;	   //数据传输线接单片机的相应的引脚
unsigned char tempL=0; 	//设全局变量
unsigned char tempH=0; 
unsigned int sdata;		//测量到的温度的整数部分
unsigned char xiaoshu; //小数第一位
uchar code DisplayNums[] = "0123456789";
uchar code DisplayTips[] = "Temperature";


//******************延时子程序*******************************

//这个延时程序的具体延时时间是time=i*8+10,适用于小于2ms的延时

//************************************************************
void delay(unsigned char i)
{
	 for(i;i>0;i--);
}
void delay1ms(int n)
{
	 unsigned char i;
	 for(i=124*n;i>0;i--);  //延时124*8+10=1002us
}
/**********LCD部分******************/
void Write_Com(uchar Com){
	/*
		液晶写指令,对应操作
	*/
	LCDRS = 0;
	P0 = Com;
	delay1ms(5);
	LCDEN = 1;
	delay1ms(5);
	LCDEN = 0;
	delay1ms(5);
}
void Write_Data(uchar Data){
	/*
		液晶写数据
	*/
	LCDRS = 1;
	P0 = Data;
	delay1ms(5);
	LCDEN = 1;
	delay1ms(5);
	LCDEN = 0;
	delay1ms(5);
}
void Lcd_Init(){
	LCDEN = 0;
	LCDRW = 0;
	Write_Com(0x38);	//设置 16*2 显示,每个字符是5*7 点阵,8 位数据接口
	Write_Com(0x0c);    //开显示,不显示光标
	Write_Com(0x06);    //地址加 1,当写入数据的时候光标右移
	Write_Com(0x01);    //清屏,清楚之前的内容.
}
void Display_Temperature(uint Data){
	//Data转换成三位数
	//Data = 0x;
	uint Decade,Uint;
	Decade = Data/10;
	Uint = Data%10;
	/*	0x80是第一行的第一个字符,0x80+1是第一行第二个,0x80+0x40是第二行第一个地址
		写入显示地址时,要求最高位D7恒为高电平,即1000 0000 + 0100 0000 = 0x80 + 0x40
		单片机规定
	*/
	Write_Com(0x80+0x40+5);	
	Write_Data(DisplayNums[Decade]);	//写入数据.
	Write_Data(DisplayNums[Uint]);
	Write_Data('.');
	Write_Data(DisplayNums[xiaoshu]);
}
void Display_Static_Temperature(){
	uchar i;
	Write_Com(0x80+3);
	for(i=0;i<10;i++){
		Write_Data(DisplayTips[i]);
	}
   	Write_Com(0x80+0x40+10);
	Write_Data('^');	//°C
	Write_Data('C');
}

//*****************************初始化程序 *********************************//

void Init_DS18B20(void) 
{
	unsigned char x=0;
	LCDTP=1; //DQ先置高 
	delay(8); //稍延时
	LCDTP=0; //发送复位脉冲 
	delay(80); //延时(>480us) 
	LCDTP=1; //拉高数据线 
	delay(5); //等待(15~60us) 
	x=LCDTP; //用X的值来判断初始化有没有成功,18B20存在的话X=0,否则X=1 
	delay(20); 
} 


//**********读一个字节************//

ReadOneChar(void)  //主机数据线先从高拉至低电平1us以上,再使数据线升为高电平,从而产生读信号
{
	unsigned char i=0; //每个读周期最短的持续时间为60us,各个读周期之间必须有1us以上的高电平恢复期
	unsigned char dat=0; 
	for (i=8;i>0;i--) //一个字节有8位 
	{
		LCDTP=1; 
		delay(1); 
		LCDTP=0;
		dat>>=1; 	   //数据移位
		LCDTP=1; 
		if(LCDTP) 
		dat|=0x80; 	   //得读取数据线得到一个状态
		delay(4);
} 
return(dat);
} 

//*********************** **写一个字节**************************//

void WriteOneChar(unsigned char dat) 
{ 
	unsigned char i=0; //数据线从高电平拉至低电平,产生写起始信号。15us之内将所需写的位送到数据线上,
	for(i=8;i>0;i--) //在15~60us之间对数据线进行采样,如果是高电平就写1,低写0发生。 
	{
		LCDTP=0; //在开始另一个写周期前必须有1us以上的高电平恢复期。 
		LCDTP=dat&0x01;  //按低位发送数据
		delay(5); 
		LCDTP=1; 
		dat>>=1;
	} 
	delay(4);
} 


//读温度值(低位放tempL;高位放tempH;)
void ReadTemperature(void) 
{ 
	Init_DS18B20(); //初始化
	WriteOneChar(0xcc); //跳过读序列号的操作
	WriteOneChar(0x44); //启动温度转换
	delay(125); //转换需要一点时间,延时 
	Init_DS18B20(); //初始化
	WriteOneChar(0xcc); //跳过读序列号的操作 
	WriteOneChar(0xbe); //读温度寄存器(头两个值分别为温度的低位和高位) 
	tempL=ReadOneChar(); //读出温度的低位LSB
	tempH=ReadOneChar(); //读出温度的高位MSB 
	
	if(tempH>0x7f)      //最高位为1时温度是负
	{
		 tempL=~tempL;         //补码转换,取反加一
		 tempH=~tempH+1;       
	}
	sdata = tempL/16+tempH*16;      //整数部分
	xiaoshu = (tempL&0x0f)*10/16; //小数第一位
}

//**************************** //主程序 
void main()
{  	
	unsigned int i;
	Lcd_Init();
	Display_Static_Temperature();
	while(1)
	{
		ReadTemperature(); //读取温度
		for(i=0;i<20;i++)
		{
			Display_Temperature(sdata);
		}
	}
}

为简化代码,下次改进会将源码上传至Github.

  • 56
    点赞
  • 325
    收藏
    觉得还不错? 一键收藏
  • 28
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值