文章参考资料
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 端外接一个上拉电阻,与处理器的任一端口连接
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位双向数据口;
在软件控制问题中,需要注意几个问题—基本问题:各时段的端口状态(电平)
液晶显示器的初始化—设置初始状态—置显示状态(电源、控制、数据端口等电平)
控制口RS/RW的控制指令变化—检测、延时、检测—发送数据问题(电平)
输出数据的获取与传递(读取/写入电平)
在编写 LCD1602 程序前,我们必须了解其手册上一些非常重要的
信息,如果这些信息不能理解透彻,编程可能会遇到或多或少的
问题.
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
#include
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); //显示温度
}
}
}
#include
#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.