一起玩儿Proteus仿真(C51)——08 基于DS18B20和LCD1602的数字温度计(二)

摘要:本文介绍如何使用DS18B20和LCD1602实现一个数字温度计

LCD1602与单片机的连接通常有两种方式,一种是直接控制方式,另一种是所谓的间接控制方式。它们的区别只是所用的数据线的数量不同,其他都一样。在这里我们采用直接控制的方式,将LCD1602的8根数据线和3根控制线E,RS和R/W与单片机直接相连。VO引脚是液晶对比度调试端,连接一个10kΩ的电位器即可实现对比度的调整,实际项目中也可以采用将一个适当大小的电阻从该引脚接地的方法进行调整,不过该电阻的大小应通过事先的调试来决定。

DS18B20只有三个引脚,电源、数据线和接地。将数据线直接连接到单片机的引脚就可以了。整个仿真系统的原理图如下所示:

下面就来逐步的看一下仿真程序的实现方法。在程序的最开始还是引入头文件、宏定义和配置常量参数部分。具体内容如下所示:

#include <reg51.h>

#include <intrins.h>

#include <string.h>

#include <stdio.h>

#define uchar unsigned char

#define uint unsigned int

// LCD1602控制引脚定义

sbit RS = P2^0;

sbit RW = P2^1;

sbit E = P2^2;

// 18B20引脚定义

sbit DQ = P2^3;

这些引脚的定义需要按照实际的接线方法来进行,如果与上面的原理图不同,那么请进行修改。

接下来就是在C51中最经常使用到的延时函数的声明和实现了。在这里定义了2个延时函数,如下所示:

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

//     延时函数

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

void delayUs2x(uchar t)

{   

 while(--t);

}

void delayMs(uchar t)

{

 while(t--)

 {

   //大致延时1mS

   delayUs2x(245);

 delayUs2x(245);

 }

}

接下来就是对LCD1602进行控制的各个函数了。对LCD1602进行控制的关键点在于把握对三个控制信号RS、R/W和E的组合使用。在这里实现了以下几个函数:

busyCheck():检查LCD1602是否处于忙状态,用于确定是否可以接收新的指令。

lcdExec():通知LCD1602执行刚刚下发的命令。

lcdWCmd():写入命令函数。

lcdPos():设置光标位置,也就是下一个字符显示位置函数。

lcdWDat():写入数据指令,用于写入要显示的字符。

disChar():显示字符指令。

lcdDisplay():在指定位置显示字符串指令。

这些函数的实现方法如下:

// 检查1602是否处于忙碌状态

uchar busyCheck(void)

{

uchar lcdStatus;

RS = 0;

RW = 1;

E = 1;

_nop_();

_nop_();

_nop_();

_nop_();

lcdStatus = P0&0x80;

E = 0;

return lcdStatus;

}

// LCD执行命令

void lcdExec(void)

{

_nop_();

_nop_();

_nop_();

_nop_();

  E = 1;

_nop_();

_nop_();

_nop_();

_nop_();

E = 0;

}

// 写入1602命令

void lcdWCmd(uchar cmd)

{

RS = 0;

RW = 0;

E = 0;

_nop_();

_nop_();

P0 = cmd;

lcdExec();

}

// 设置显示位置

void lcdPos(uchar pos)

{

lcdWCmd(pos|0x80);

}

// 写入字符

void lcdWDat(char dat)

{

while(busyCheck());

RS = 1;

RW = 0;

E = 0;

P0 = dat;

lcdExec();

}

// 显示字符

void disChar(char a)

{

lcdWDat(a);

while(busyCheck());

}

// 显示字符串

void lcdDisplay(uchar p, uchar *s, uchar len)

{

uchar i;

lcdPos(p);

for(i=0; i<len; i++)

{

disChar(s[i]);

}

}

最后还有一个LCD1602模块初始化的函数,在这里设置了其初始工作状态,并将屏幕显示内容清空。具体实现方法如下,有不清楚指令含义的可以参考前一篇文章中的介绍:

// 1602初始化

void lcdInit(void)

{

lcdWCmd(0x38); //设置显示格式

delayMs(1);

lcdWCmd(0x0C);

delayMs(1);

lcdWCmd(0x06);

delayMs(1);

lcdWCmd(0x01);

delayMs(1);

}

接下来就是读取DS18B20温度数值的函数了。使用DS18B20读取数据的过程在之前的文章中都介绍过了,下面就来看一下每一步都是如何实现的吧。

首先实现的是DS18B20初始化函数,如下所示:

/*------------------------------------------------

                  DS18B20函数声明

------------------------------------------------*/

bit initDS18B20() //18b20初始化

{

 bit dat=0;

 DQ = 1;    //DQ复位

 delayUs2x(5);   //稍做延时

 DQ = 0;         //单片机将DQ拉低

 delayUs2x(200); //精确延时 大于 480us 小于960us

 delayUs2x(200);

 DQ = 1;        //拉高总线

 delayUs2x(50); //15~60us 后 接收60-240us的存在脉冲

 dat=DQ;        //如果x=0则初始化成功, x=1则初始化失败

 delayUs2x(25); //稍作延时返回

 return dat;

}

在这里需要特别注意的就是对脉冲宽度的要求,一定要满足DS18B20的要求,否则是无法完成正常的初始化工作的。

接下来是两个工具函数,分别实现了向DS18B20读取一个字节的数据和写入一个字节的数据,重点注意的也是对时序的规定和脉冲宽度的要求。具体实现方法如下:

//读取一个字节

unsigned char readOneByte()

{

unsigned char i=0;

unsigned char dat = 0;

for (i=8;i>0;i--)

{

DQ = 0; // 给脉冲信号

dat>>=1;

DQ = 1; // 给脉冲信号

if(DQ)

dat|=0x80;

delayUs2x(25);

}

return(dat);

}

//写入一个字节

void writeOneByte(unsigned char dat)

{

unsigned char i=0;

for (i=8; i>0; i--)

{

DQ = 0;

DQ = dat&0x01;

delayUs2x(25);

DQ = 1;

dat>>=1;

}

delayUs2x(25);

}

接下来的方法是读取2个字节的温度值函数,如下所示:

// 读取温度

unsigned int readTemperature()

{

unsigned char a=0;

unsigned int b=0;

unsigned int t=0;

initDS18B20();

writeOneByte(0xCC); // 跳过读序号列号的操作

writeOneByte(0x44); // 启动温度转换

delayMs(10);

initDS18B20();

writeOneByte(0xCC); //跳过读序号列号的操作

writeOneByte(0xBE); //读取温度寄存器等(共可读9个寄存器) 前两个就是温度

a=readOneByte();   //低位

b=readOneByte();   //高位

b<<=8;

t=a+b;

return(t);

}

这就是指令一级的与DS18B20的交互过程,关于交互的指令顺序和格式在之前的文章中都已经介绍过了。这个方法最终返回2个字节的测量结果。

接下来,就是将这2个字节的测量结果转换成我们所要的温度值,在转换的过程中所要注意的就是温度值是有正负的,要区别处理,具体的实现方法如下:

// 得到浮点数的温度值

float getTemperature()

{

unsigned int temp;

float tempture;

temp = readTemperature();

if( temp&0x8000 ) {

temp = ~temp;

temp++;

tempture = -0.0625*temp;

} else {

tempture = 0.0625*temp;

}

return tempture;

}

好了,所有的准备工作都完成了,接下来该实现主程序了。这个主程序就比较简单了。首先需要完成初始化工作,然后就是循环读取DS18B20的温度值,并显示在LCD1602上就可以了。如下所示:

// 主程序

void main(void)

{

float temperature;

char tempStr[8];

lcdInit();

delayMs(10);

while(1)

{

temperature = getTemperature();

memset(tempStr, 0, sizeof(tempStr));

sprintf( tempStr, "Temp:%.2f", temperature );

lcdDisplay(0, tempStr, strlen(tempStr));

delayMs(500);

}

}

好了,所有的程序就全部完成了,接下来看一下仿真的结果吧。

数字温度计

  • 30
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
51单片机是一种常用的微控制器,具有广泛的应用领域。 DS18B20是一种数字温度传感器,具有高精度、数字输出、单总线接口等特点。Proteus是一种虚拟电路设计仿真软件,能够帮助我们验证电路的功能和性能。 要设计一个可调上下限的温度报警器,我们可以使用51单片机DS18B20传感器进行连接,并在Proteus中进行仿真。 首先,将DS18B20传感器的VCC引脚(3.3V或5V)、GND引脚(地)和DQ引脚(数字接口)分别连接到51单片机的对应引脚上。然后,在Proteus中导入51单片机的库文件,并绘制出相应的电路图。 接下来,我们可以使用51单片机的GPIO口读取DS18B20传感器的温度数据,并将其与预设的上下限进行比较。如果温度超过设定的上限或低于设定的下限,可以设置51单片机的某个引脚输出高电平,触发报警器。 为了实现可调的上下限,我们可以通过外部电位器或软件编程的方式,来调节报警器的温度阈值。可以选择将电位器与51单片机的某个模拟输入引脚相连,通过读取电位器的电阻值来调节阈值。或者在程序中通过用户界面,设置上下限的数值并存储在非易失性存储器中。 最后,我们可以在Proteus中进行仿真测试,输入不同的温度值,观察51单片机的输出状态和报警器是否正常工作。 通过以上步骤,我们可以在Proteus设计一个可调上下限的51单片机DS18B20温度报警器,实现温度监测和报警的功能。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一起玩儿科技

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值