proteus51单片机引脚怎样合并(基于proteus的51单片机开发实例29

生活常识 2023-04-19 18:20生活常识www.baidianfengw.cn

如何在protues中找到电源?基于proteus 29的51单片机开发实例——单总线DS18B20的读写

1. 基于proteus的51单片机开发实例29-单总线DS18B20的读写

1.1. 实验目的

图1单总线DS18B20温度显示电路

我们已经了解了几种串行通信技术,如RS-232、I2C和SPI。在本例中,我们将继续学习另一种串行通信技术单总线串行通信。介绍了DS18B20的一些基础知识特点、结构、原理、控制时序、与单片机的接口 等。通过一个实例实现了最简单的温度测量,并用液晶显示测量的温度值。

1.2. 设计思路

本例的设计思路是在proteus环境下建立一个基于51单片机单总线通讯和LCD1602液晶显示的电路。通过控制单总线温度传感器DS18B20,由1602 LCD读出并显示温度值。

本例分为三个功能模块,描述如下

单片机系统51单片机与DS18B20温度传感器通信,控制温度采集过程,并将采集到的温度值发送给1602 LCD。

外围电路外围电路分为两部分1602液晶显示控制电路(显示采集的温度值)和DS18B20温度采集电路(采集环境温度)。

软件程序编写软件实现温度测量和液晶显示数据的功能。

1.3. 基础知识

DS18B20是DALLAS公司推出的单总线数字温度传感器。单总线的技术特点是只使用一条通信线路,这条线路既可以完成时钟传输,也可以完成数据传输,数据通信是双向的。什么?s更多的是,这条线还可以完成供电功能(有兴趣的话,请看DS18B20技术手册中寄生电源的介绍)。

1.3.1. 单总线温度传感器DS18B20

DS18B20的引脚和封装如下所示

NC空引脚,未连接到外部信号。

VDD电源引脚,电压范围3.0-5.5V

GND接地引脚。

DQ数据引脚,传输数据的输入和输出。此引脚通常为开漏输出,输出高电平。

图2 ds18b 20的引脚和封装

1.3.2. DS18B20的内部结构

DS18B20的内部结构如下图所示。DS18B20的内部结构主要由四部分组成64位ROM、温度敏感元件、内部存储器和配置寄存器。

图3 ds18b 20的内部结构

64位ROM:64位ROM的内容是一个64位的序列号,出厂前用激光刻上去的。它可以用作DS18B20的地址序列代码。每个DS18B20的64位ROM是不同的,这样就可以达到在一条总线上挂多个DS18B20的目的。

感温元件感温元件测量温度,测量结果存储在两个8位寄存器中,定义如下图所示。温度寄存器高字节的高五位为符号位,温度为负时为1;温度为正,这5位为0。高字节寄存器的低3位和低字节寄存器的高4位构成温度的整数部分,低字节寄存器的低4位是温度的小数部分。当温度大于0时,温度值存储在原始代码中。当温度低于0时,以两 s补码。

图4温度寄存器的定义

当转换位数为12时,温度的精度为1/16(小数点后4位,所以是16)=0.0625度。类似地,当转换位数为11时,精度为1/8=0.125度。

对于温度的计算,以12位转换位数为例对于正温度,只需将测量值的整数部分取出,转换成小数,然后将小数部分乘以0.0625,即可得到小数小数小数小数位的温度值。对于负温度,需要在采集值上加1,就可以得到实际温度的十六进制表示。根据正温度的计算 ,可以得到小数负温度。

12位转换数字情况下的温度转换值和温度对照表。

图5温度值对照表

1.3.3. DS18B20的内部存储器

DS18B20的内部存储器包括一个便笺式RAM和一个非易失性电可擦除EEPROM

暂存RAM和EEPROM的结构如下图所示。暂存RAM由9个字节组成。发出温度转换命令时,转换后的温度值以两个 s补码。单片机通过读取时低位在前,高位在后. DQ单线接口读取数据第二和第三个字节是温度的上(th)和下(TL)报警值,没有小数位。第四个字节是配置寄存器,主要用于设置工作模式和转换位数。第五、六、七字节是保留位,没有实际意义。第八个字节是之前所有8个字节的CRC校验码。EEPROM由3个字节组成,用于存储温度的上限和下限报警值以及配置寄存器的内容。

图6内部存储器

1.3.4. DS18B20控制流程

rong>

根据DS18B20的通信协议,主机控制DS18B20完成一次温度转换必须经过3个步骤

一)、每次读写之前都要对DS18B20进行复位操作

二)、复位成功后发送一条ROM指令

三)、发送RAM指令,这样才能够对DS18B20进行正确的操作。

● 复位复位要求主机将数据线拉低最少480us,然后释放,当DS18B20收到信号后,等待15-60us,然后把总线拉低60-240us,主机接收到此信号表示复位成功。

● ROM指令ROM指令表明了主机寻址一个或多个DS18B20中的某个或某几个,或者是读取某个DS18B20的64位序列号。

● RAM指令RAM指令用于主机对DS18B20内部RAM的操作(如启动温度转换、读取温度等)。

1.3.5. ROM操作命令

必须先完成ROM设定,否则记忆和控制功能将无法使用。一旦总线检测到从属器件的存在,它便可以发出器件ROM操作指令,所有ROM操作指令均为8位长度,主要提供以下功能命令

1 )读ROM(指令码0X33H)当总线上只有一个节点(器件)时,读此节点的64位序列号。如果总线上存在多于一个的节点,则此指令不能使用。

2 )ROM匹配(指令码0X55H)此命令后跟64位的ROM序列号,总线上只有与此序列号相同的DS18B20才会做出反应;该指令用于选中某个DS18B20,然后对该DS18B20进行读写操作。

3 )搜索ROM(指令码0XF0H) 用于确定接在总线上DS18B20的个数和识别所有的64位ROM序列号。当系统开始工作,总线主机可能不知道总线上的器件个数或者不知道其64位ROM序列号,搜索命令用于识别所有连接于总线上的64位ROM序列号。

4 )跳过ROM(指令码0XCCH) 此指令只适合于总线上只有一个节点;该命令通过允许总线主机不提供64位ROM序列号而直接访问RAM,以节省操作时间。

5 )报警检查(指令码0XECH)此指令与搜索ROM指令基本相同,差别在于只有温度超过设定的上限或者下限值的DS18B20才会作出响应。只要DS18B20一上电,告警条件就保持在设置状态,直到另一次温度测量显示出非告警值,或者改变TH或TL的设置使得测量值再一次位于允许的范围之内。储存在EEPROM内的触发器用于告警。

这些指令操作作用在每一个器件的64位光刻ROM序列号,可以在挂在一线上多个器件选定某一个器件,,总线也可以知道总线上挂有有多少,什么样的设备。

1.3.6. RAM指令

1)温度转换(指令码0X44H):启动DS18B20进行温度转换,结果存入内部RAM。

2)读暂存器(指令码0XBEH)读暂存器9个字节内容,此指令从RAM的第1个字节(字节0)开始读取,直到九个字节(字节8,CRC值)被读出为止。如果不需要读出所有字节的内容,那么主机可以在任何时候发出复位信号以终止读操作。

3)写暂存器(指令码0X4EH) 将上下限温度报警值和配置数据写入到RAM的2、3、4字节,此命令后跟需要写入到这三个字节的数据。

4)复制暂存器(指令码0X48H)把暂存器的2、3、4字节复制到EEPROM中,用以掉电保存。

5)重新调E2RAM(指令码0XB8H)把EEROM中的温度上下限及配置字节恢复到RAM的2、3、4字节,用以上电后恢复以前保存的报警值及配置字节。

6)读电源供电方式(指令码0XB4H)启动DS18B20发送电源供电方式的信号给主CPU。对于在此命令送至DS18B20后所发出的之一次读出数据的时间片,器件都会给出其电源方式的信号。“0”表示寄生电源供电。“1”表示外部电源供电。

图6 DS18B20两种电源供电电路

1.3.7. DS18B20的操作时序

1、DS18B20的初始化

(1) 先将数据线置高电平“1”。

(2) 延时(该时间要求的不是很严格,尽可能的短一点)。

(3) 数据线拉到低电平“0”。

(4) 延时490微秒(该时间的时间范围可以从480到960微秒)。

(5) 数据线拉到高电平“1”。

(6) 延时等待(如果初始化成功则在15到60毫秒时间之内产生一个由DS18B20所返回的低电平“0”。据该状态可以来确定它的存在,应注意不能无限的进行等待,不然会使程序进入死循环,所以要进行超时控制)。

(7) 若CPU读到了数据线上的低电平“0”后,还要做延时,其延时的时间从发出的高电平算起(第(5)步的时间算起)最少要480微秒。

(8) 将数据线拉高到高电平“1”后结束。  

2、DS18B20的写操作

(1) 数据线先置低电平“0”。

(2) 延时确定的时间为2(小于15)微秒。

(3) 按从低位到高位的顺序发送字节(一次只发送一位)。

(4) 延时时间为62(大于60)微秒。

(5) 将数据线拉到高电平,延时2(小于15)微秒。

(6) 重复上(1)到(6)的操作直到所有的字节全部发送完为止。

(7) 将数据线拉高。  

3、 DS18B20的读操作

(1)将数据线拉高“1”。

(2)延时2微秒。

(3)将数据线拉低“0”。

(4)延时2(小于15)微秒。

(5)将数据线拉高“1”,端口应为输入状态。

(6)延时4(小于15)微秒。

(7)读数据线的状态得到1个状态位,并进行数据处理。

(8)延时62(大于60)微秒。

1.4. 电路设计

本例中电路图如图1所示。

DS18B20的数据线要求空闲状态为高电平,所以应该在DS18B20的数据线与电源线VCC之间加一个4.7K的上拉电阻

DS18B20的数据线DQ连到单片机的P3.3口。单片机通过控制P3.3口实现对DS18B20的操作。

LCD1602液晶的8位数据线连接到单片机的P口,液晶的控制端口RS、RW、E分别连接到单片机的P2.4、P2.5、P2.6这三个端口。

1.5. 程序设计

1、程序功能

程序的功能是使用单片机的P3.3口的实现对DS18B20的操作,然后将读出的温度值通过LCD1602液晶显示。

本实例的程序代码如下。

#includeltreg51.hgt #includeltintrins.hgt unsigned char code digit[10]={#340123456789#34} //定义字符数组显示数字unsigned char code Str[]={#34laomashitu MCU#34} //说明显示的是温度unsigned char code Error[]={#34Check Error!#34} //说明没有检测到DS18B20unsigned char code Temp[]={#34wendu:#34} //说明显示的是温度unsigned char code Cent[]={#34du#34} //温度单位/以下是对液晶模块的操作程序/ it RS=P2^4 //寄存器选择位,将RS位定义为P2.0引脚 it RW=P2^5 //读写选择位,将RW位定义为P2.1引脚 it E=P2^6 //使能信号位,将E位定义为P2.2引脚 it BF=P0^7 //忙碌标志位,,将BF位定义为P0.7引脚 it DQ=P3^3unsigned char time //设置全局变量,专门用于严格延时/函数功能延时1ms(3j+2)i=(3×33+2)×10=1010(微秒),可以认为是1毫秒/void delay1ms()/函数功能延时若干毫秒入口参数n/ void delaynms(unsigned int n)/函数功能判断液晶模块的忙碌状态返回值result。result=1,忙碌result=0,不忙/bit BusyTest(void)/函数功能将模式设置指令或显示地址写入液晶模块入口参数dictate/void WriteInstruction (unsigned char dictate)/函数功能指定字符显示的实际地址入口参数x/ void WriteAddress(unsigned char x)/函数功能将数据(字符的标准ASCII码)写入液晶模块入口参数y(为字符常量)/ void WriteData(unsigned char y)/函数功能对LCD的显示模式进行初始化设置/void LcdInitiate(void)/以下是DS18B20的操作程序 / /函数功能将DS18B20传感器初始化,读取应答信号出口参数flag /bit Init_DS18B20(void)/函数功能从DS18B20读取一个字节数据出口参数dat/ unsigned char ReadOneChar(void)/函数功能向DS18B20写入一个字节数据入口参数dat/ WriteOneChar(unsigned char dat)/以下是与温度有关的显示设置 / /函数功能显示没有检测到DS18B20/ void display_error(void)/函数功能显示说明信息/ void display_explain(void)/函数功能显示温度符号/ void display_symbol(void)/函数功能显示温度的小数点/ void display_dot(void)/函数功能显示温度的单位(Cent)/ void display_cent(void)/函数功能显示温度的整数部分入口参数x/ void display_temp1(unsigned char x) /函数功能显示温度的小数数部分入口参数x/ void display_temp2(unsigned char x)/函数功能做好读温度的准备/ void ReadyReadTemp(void)/函数功能主函数/ void main(void) { unsigned char TL //储存暂存器的温度低位 unsigned char TH //储存暂存器的温度高位 unsigned char TN //储存温度的整数部分 unsigned int TD //储存温度的小数部分 LcdInitiate() //将液晶初始化 delaynms(5) //延时5ms给硬件一点反应时间 if(Init_DS18B20()==1) display_error() display_explain() display_symbol() //显示温度说明 display_dot() //显示温度的小数点 display_cent() //显示温度的单位 while(1) //不断检测并显示温度 { ReadyReadTemp() //读温度准备 TL=ReadOneChar() //先读的是温度值低位 TH=ReadOneChar() //接着读的是温度值高位 TN=TH16+TL/16 //实际温度值=(TH256+TL)/16,即TH16+TL/16 //这样得出的是温度的整数部分,小数部分被丢弃了 TD=(TL%16)10/16 //计算温度的小数部分,将余数乘以10再除以16取整, //这样得到的是温度小数部分的之一位数字(保留1位小数) display_temp1(TN) //显示温度的整数部分 display_temp2(TD) //显示温度的小数部分 delaynms(10) } }/函数功能延时1ms(3j+2)i=(3×33+2)×10=1010(微秒),可以认为是1毫秒/void delay1ms(){ unsigned char i,j for(i=0ilt10i++) for(j=0jlt33j++) }/函数功能延时若干毫秒入口参数n/ void delaynms(unsigned int n) { unsigned int i for(i=0iltni++) delay1ms() }/函数功能判断液晶模块的忙碌状态返回值result。result=1,忙碌result=0,不忙/bit BusyTest(void) { bit result RS=0 //根据规定,RS为低电平,RW为高电平时,可以读状态 RW=1 E=1 //E=1,才允许读写 _nop_() //空操作 _nop_() _nop_() _nop_() //空操作四个机器周期,给硬件反应时间 result=BF //将忙碌标志电平赋给result E=0 //将E恢复低电平 return result }/函数功能将模式设置指令或显示地址写入液晶模块入口参数dictate/void WriteInstruction (unsigned char dictate){ while(BusyTest()==1) //如果忙就等待 RS=0 //根据规定,RS和R/W为低电平时,可以写入指令 RW=0 E=0 //E置低电平(根据表8-6,写指令时,E为高脉冲, // 就是让E从0到1发生正跳变,所以应先置#340#34 _nop_() _nop_() //空操作两个机器周期,给硬件反应时间 P0=dictate //将数据送入P0口,即写入指令或地址 _nop_() _nop_() _nop_() _nop_() //空操作四个机器周期,给硬件反应时间 E=1 //E置高电平 _nop_() _nop_() _nop_() _nop_() //空操作四个机器周期,给硬件反应时间 E=0 //当E由高电平跳变成低电平时,液晶模块开始执行命令 }/函数功能指定字符显示的实际地址入口参数x/ void WriteAddress(unsigned char x) { WriteInstruction(x|0x80) //显示位置的确定 规定为#3480H+地址码x#34 }/函数功能将数据(字符的标准ASCII码)写入液晶模块入口参数y(为字符常量)/ void WriteData(unsigned char y) { while(BusyTest()==1) RS=1 //RS为高电平,RW为低电平时,可以写入数据 RW=0 E=0 //E置低电平(根据表8-6,写指令时,E为高脉冲, // 就是让E从0到1发生正跳变,所以应先置#340#34 P0=y //将数据送入P0口,即将数据写入液晶模块 _nop_() _nop_() _nop_() _nop_() //空操作四个机器周期,给硬件反应时间 E=1 //E置高电平 _nop_() _nop_() _nop_() _nop_() //空操作四个机器周期,给硬件反应时间 E=0 //当E由高电平跳变成低电平时,液晶模块开始执行命令 }/函数功能对LCD的显示模式进行初始化设置/void LcdInitiate(void){ delaynms(15) //延时15ms,写指令时应给LCD一段较长的反应时间 WriteInstruction(0x38) //显示模式设置16×2显示,5×7点阵,8位数据接口 delaynms(5) //延时5ms ,给硬件一点反应时间 WriteInstruction(0x38) delaynms(5) //延时5ms ,给硬件一点反应时间 WriteInstruction(0x38) //连续三次,确保初始化成功 delaynms(5) //延时5ms ,给硬件一点反应时间 WriteInstruction(0x0c) //显示模式设置显示开,无光标,光标不闪烁 delaynms(5) //延时5ms ,给硬件一点反应时间 WriteInstruction(0x06) //显示模式设置光标右移,字符不移 delaynms(5) //延时5ms ,给硬件一点反应时间 WriteInstruction(0x01) //清屏幕指令,将以前的显示内容清除 delaynms(5) //延时5ms ,给硬件一点反应时间 } /以下是DS18B20的操作程序 / /函数功能将DS18B20传感器初始化,读取应答信号出口参数flag /bit Init_DS18B20(void) { bit flag //储存DS18B20是否存在的标志,flag=0,表示存在;flag=1,表示不存在 DQ = 1 //先将数据线拉高 for(time=0timelt2time++) //略微延时约6微秒 DQ = 0 //再将数据线从高拉低,要求保持480~960us for(time=0timelt200time++) //略微延时约600微秒 //以向DS18B20发出一持续480~960us的低电平复位脉冲 DQ = 1 //释放数据线(将数据线拉高) for(time=0timelt10time++) //延时约30us(释放总线后需等待15~60us让DS18B20输出存在脉冲) flag=DQ //让单片机检测是否输出了存在脉冲(DQ=0表示存在) for(time=0timelt200time++) //延时足够长时间,等待存在脉冲输出完毕 return (flag) //返回检测成功标志}/函数功能从DS18B20读取一个字节数据出口参数dat/ unsigned char ReadOneChar(void) { unsigned char i=0 unsigned char dat //储存读出的一个字节数据 for (i=0ilt8i++) { DQ =1 // 先将数据线拉高 _nop_() //等待一个机器周期 DQ = 0 //单片机从DS18B20读书据时,将数据线从高拉低即启动读时序 datgtgt=1 _nop_() //等待一个机器周期 DQ = 1 //将数据线#34人为#34拉高,为单片机检测DS18B20的输出电平作准备 for(time=0timelt2time++) //延时约6us,使主机在15us内采样 if(DQ==1) dat|=0x80 //如果读到的数据是1,则将1存入dat else dat|=0x00//如果读到的数据是0,则将0存入dat //将单片机检测到的电平信号DQ存入r[i] for(time=0timelt8time++) //延时3us,两个读时序之间必须有大于1us的恢复期 } return(dat) //返回读出的十进制数据}/函数功能向DS18B20写入一个字节数据入口参数dat/ WriteOneChar(unsigned char dat){ unsigned char i=0 for (i=0 ilt8 i++) { DQ =1 // 先将数据线拉高 _nop_() //等待一个机器周期 DQ=0 //将数据线从高拉低时即启动写时序 DQ=dat0x01 //利用与运算取出要写的某位二进制数据, //并将其送到数据线上等待DS18B20采样 for(time=0timelt10time++) //延时约30us,DS18B20在拉低后的约15~60us期间从数据线上采样 DQ=1 //释放数据线 for(time=0timelt1time++) //延时3us,两个写时序间至少需要1us的恢复期 datgtgt=1 //将dat中的各二进制位数据右移1位 } for(time=0timelt4time++) //稍作延时,给硬件一点反应时间}/以下是与温度有关的显示设置 / /函数功能显示没有检测到DS18B20/ void display_error(void) { unsigned char i WriteAddress(0x00) //写显示地址,将在第1行第1列开始显示 i = 0 //从之一个字符开始显示 while(Error[i] != #39\0#39) //只要没有写到结束标志,就继续写 { WriteData(Error[i]) //将字符常量写入LCD i++ //指向下一个字符 delaynms(100) //延时100ms较长时间,以看清关于显示的说明 } while(1) //进入死循环,等待查明原因 }/函数功能显示说明信息/ void display_explain(void) { unsigned char i WriteAddress(0x00) //写显示地址,将在第1行第1列开始显示 i = 0 //从之一个字符开始显示 while(Str[i] != #39\0#39) //只要没有写到结束标志,就继续写 { WriteData(Str[i]) //将字符常量写入LCD i++ //指向下一个字符 delaynms(100) //延时100ms较长时间,以看清关于显示的说明 } }/函数功能显示温度符号/ void display_symbol(void) { unsigned char i WriteAddress(0x40) //写显示地址,将在第2行第1列开始显示 i = 0 //从之一个字符开始显示 while(Temp[i] != #39\0#39) //只要没有写到结束标志,就继续写 { WriteData(Temp[i]) //将字符常量写入LCD i++ //指向下一个字符 delaynms(50) //延时1ms给硬件一点反应时间 } }/函数功能显示温度的小数点/ void display_dot(void){ WriteAddress(0x49) //写显示地址,将在第2行第10列开始显示 WriteData(#39.#39) //将小数点的字符常量写入LCD delaynms(50) //延时1ms给硬件一点反应时间 }/函数功能显示温度的单位(Cent)/ void display_cent(void){ unsigned char i WriteAddress(0x4c) //写显示地址,将在第2行第13列开始显示 i = 0 //从之一个字符开始显示 while(Cent[i] != #39\0#39) //只要没有写到结束标志,就继续写 { WriteData(Cent[i]) //将字符常量写入LCD i++ //指向下一个字符 delaynms(50) //延时1ms给硬件一点反应时间 } }/函数功能显示温度的整数部分入口参数x/ void display_temp1(unsigned char x){ unsigned char j,k,l //j,k,l分别储存温度的百位、十位和个位 j=x/100 //取百位 k=(x%100)/10 //取十位 l=x%10 //取个位 WriteAddress(0x46) //写显示地址,将在第2行第7列开始显示 WriteData(digit[j]) //将百位数字的字符常量写入LCD WriteData(digit[k]) //将十位数字的字符常量写入LCD WriteData(digit[l]) //将个位数字的字符常量写入LCD delaynms(50) //延时1ms给硬件一点反应时间 } /函数功能显示温度的小数数部分入口参数x/ void display_temp2(unsigned char x){ WriteAddress(0x4a) //写显示地址,将在第2行第11列开始显示 WriteData(digit[x]) //将小数部分的之一位数字字符常量写入LCD delaynms(50) //延时1ms给硬件一点反应时间}/函数功能做好读温度的准备/ void ReadyReadTemp(void){ Init_DS18B20() //将DS18B20初始化 WriteOneChar(0xCC) // 跳过读序号列号的操作 WriteOneChar(0x44) // 启动温度转换 for(time=0timelt100time++) //温度转换需要一点时间 Init_DS18B20() //将DS18B20初始化 WriteOneChar(0xCC) //跳过读序号列号的操作 WriteOneChar(0xBE) //读取温度寄存器,前两个分别是温度的低位和高位 }

1.6. 实例仿真

在Proteus环境下建立图1所示的电路,将编译完成的hex文件装载到单片机中,开始仿真,仿真时可以点击DS18B20器件的上升和下降箭头,模拟温度的上升和下降,观察液晶显示结果。

视频加载中...

1.7.

通过本实例的学习,可以掌握以下内容

● DS18B20的特点、结构和原理和接口设计 。

● DS18B20的控制时序和控制 流程。

proteus8051单片机如何定义引脚 proteus8051单片机如何定义引脚

Copyright@2015-2025 白癜风网版板所有