谁知道ds18b20

谁知道ds18b20,第1张

DS18B20数字温度传感器接线方便,封装成后可应用于多种场合,如管道式,螺纹式,磁铁吸附式,不锈钢封装式,型号多种多样,有LTM8877,LTM8874等等。主要根据应用场合的不同而改变其外观。封装后的DS18B20可用于电缆沟测温,高炉水循环测温,锅炉测温,机房测温,农业大棚测温,洁净室测温,d药库测温等各种非极限温度场合。耐磨耐碰,体积小,使用方便,封装形式多样,适用于各种狭小空间设备数字测温和控制领域。 1: 技术性能描述 ①、 独特的单线接口方式,DS18B20在与微处理器连接时仅需要一条口线即可实现微处理器与DS18B20的双向通讯。 ② 、测温范围 -55℃~+125℃,固有测温分辨率05℃。 ③、支持多点组网功能,多个DS18B20可以并联在唯一的三线上,最多只能并联8个,实现多点测温,如果数量过多,会使供电电源电压过低,从而造成信号传输的不稳定。 ④、工作电源: 3~5V/DC ⑤ 、在使用中不需要任何外围元件 ⑥、 测量结果以9~12位数字量方式串行传送 ⑦ 、不锈钢保护管直径 Φ6 ⑧ 、适用于DN15~25, DN40~DN250各种介质工业管道和狭小空间设备测温 ⑨、 标准安装螺纹 M10X1, M12X15, G1/2”任选 ⑩ 、PVC电缆直接出线或德式球型接线盒出线,便于与其它电器设备连接。
编辑本段应用范围
21 该产品适用于冷冻库,粮仓,储罐,电讯机房,电力机房,电缆线槽等测温和控制领域 22 轴瓦,缸体,纺机,空调,等狭小空间工业设备测温和控制。 23 汽车空调、冰箱、冷柜、以及中低温干燥箱等。 24 供热/制冷管道热量计量,中央空调分户热能计量和工业领域测温和控制
编辑本段产品型号与规格
型 号 测温范围 安装螺纹 电缆长度 适用管道 TS-18B20 -55~125 无 15 m TS-18B20A -55~125 M10X1 15m DN15~25 TS-18B20B -55~125 1/2”G 接线盒 DN40~ 60
编辑本段接线说明
特点 独特的一线接口,只需要一条口线通信 多点能力,简化了分布式温度传感应用 无需外部元件 可用数据总线供电,电压范围为30 V至55 V 无需备用电源 测量温度范围为-55 ° C至+125 ℃ 。华氏相当于是-67 ° F到257华氏度 -10 ° C至+85 ° C范围内精度为±05 ° C 温度传感器可编程的分辨率为9~12位 温度转换为12位数字格式最大值为750毫秒 用户可定义的非易失性温度报警设置 应用范围包括恒温控制,工业系统,消费电子产品温度计,或任何热敏感系统 描述该DS18B20的数字温度计提供9至12位(可编程设备温度读数。信息被发送到/从DS18B20 通过1线接口,所以中央微处理器与DS18B20只有一个一条口线连接。为读写以及温度转换可以从数据线本身获得能量,不需要外接电源。 因为每一个DS18B20的包含一个独特的序号,多个ds18b20s可以同时存在于一条总线。这使得温度传感器放置在许多不同的地方。它的用途很多,包括空调环境控制,感测建筑物内温设备或机器,并进行过程监测和控制。 8引脚封装 TO-92封装 用途 描述 5 1 接地 接地 4 2 数字 信号输入输出,一线输出:源极开路 3 3 电源 可选电源管脚。见"寄生功率"一节细节方面。电源必须接地,为行动中,寄生虫功率模式。 不在本表中所有管脚不须接线 。 概况框图图1显示的主要组成部分DS18B20的。DS18B20内部结构主要由四部分组成:64位光刻ROM、温度传感器、非挥发的温度报警触发器TH和TL、配置寄存器。该装置信号线高的时候,内部电容器 储存能量通由1线通信线路给片子供电,而且在低电平期间为片子供电直至下一个高电平的到来重新充电。 DS18B20的电源也可以从外部3V-5 5V的电压得到。 DS18B20采用一线通信接口。因为一线通信接口,必须在先完成ROM设定,否则记忆和控制功能将无法使用。主要首先提供以下功能命令之一: 1 )读ROM, 2 )ROM匹配, 3 )搜索ROM, 4 )跳过ROM, 5 )报警检查。这些指令 *** 作作用在没有一个器件的64位光刻ROM序列号,可以在挂在一线上多个器件选定某一个器件,同时,总线也可以知道总线上挂有有多少,什么样的设备。 若指令成功地使DS18B20完成温度测量,数据存储在DS18B20的存储器。一个控制功能指挥指示DS18B20的演出测温。测量结果将被放置在DS18B20内存中,并可以让阅读发出记忆功能的指挥,阅读内容的片上存储器。温度报警触发器TH和TL都有一字节EEPROM 的数据。如果DS18B20不使用报警检查指令,这些寄存器可作为一般的用户记忆用途。在片上还载有配置字节以理想的解决温度数字转换。写TH,TL指令以及配置字节利用一个记忆功能的指令完成。通过缓存器读寄存器。所有数据的读,写都是从最低位开始。 DS18B20有4个主要的数据部件: (1)光刻ROM中的64位序列号是出厂前被光刻好的,它可以看作是该DS18B20的地址序列码。64位光刻ROM的排列是:开始8位(28H)是产品类型标号,接着的48位是该DS18B20自身的序列号,最后8位是前面56位的循环冗余校验码(CRC=X8+X5+X4+1)。光刻ROM的作用是使每一个DS18B20都各不相同,这样就可以实现一根总线上挂接多个DS18B20的目的。 (2) DS18B20中的温度传感器可完成对温度的测量,以12位转化为例:用16位符号扩展的二进制补码读数形式提供,以00625℃/LSB形式表达,其中S为符号位。 表1 DS18B20温度值格式表 431 DS18B20的管脚排列如图44所示。 图44DS18B20的管脚排列如图 DS18B20内部结构主要由四部分组成:64位光刻ROM,温度传感器,温度报警触发器TH和TL,配置寄存器。DS18B20内部结构图如图45所示。 图45 DS18B20内部结构图 432存储器 DS18B20的存储器包括高速暂存器RAM和可电擦除RAM,可电擦除RAM又包括温度触发器TH和TL,以及一个配置寄存器。存储器能完整的确定一线端口的通讯,数字开始用写寄存器的命令写进寄存器,接着也可以用读寄存器的命令来确认这些数字。当确认以后就可以用复制寄存器的命令来将这些数字转移到可电擦除RAM中。当修改过寄存器中的数时,这个过程能确保数字的完整性。 高速暂存器RAM是由8个字节的存储器组成;第一和第二个字节是温度的显示位。第三和第四个字节是复制TH和TL,同时第三和第四个字节的数字可以更新;第五个字节是复制配置寄存器,同时第五个字节的数字可以更新;六、七、八三个字节是计算机自身使用。用读寄存器的命令能读出第九个字节,这个字节是对前面的八个字节进行校验。存储器的结构图如图46所示。 图46 存储器的结构图 433 64-位光刻ROM 64位光刻ROM的前8位是DS18B20的自身代码,接下来的48位为连续的数字代码,最后的8位是对前56位的CRC校验。64-位的光刻ROM又包括5个ROM的功能命令:读ROM,匹配ROM,跳跃ROM,查找ROM和报警查找。64-位光刻ROM的结构图如图47所示。 图47位64-位光刻ROM的结构图 434 DS18B20外部电源的连接方式 DS18B20可以使用外部电源VDD,也可以使用内部的寄生电源。当VDD端口接30V—55V的电压时是使用外部电源;当VDD端口接地时使用了内部的寄生电源。无论是内部寄生电源还是外部供电,I/O口线要接5KΩ左右的上拉电阻。 连接图如图48、图49所示。 图48 使用寄生电源的连接图 图49外接电源的连接图 434 DS18B20温度处理过程 4341配置寄存器 配置寄存器是配置不同的位数来确定温度和数字的转化。配置寄存器的结构图如图410所示。 图410 配置寄存器的结构图 由图49可以知道R1,R0是温度的决定位,由R1,R0的不同组合可以配置为9位,10位,11位,12位的温度显示。这样就可以知道不同的温度转化位所对应的转化时间,四种配置的分辨率分别为05℃,025℃,0125℃和00625℃,出厂时以配置为12位。温度的决定配置图如图8所示。 图411 温度的决定配置图 4342 温度的读取 DS18B20在出厂时以配置为12位,读取温度时共读取16位,所以把后11位的2进制转化为10进制后在乘以00625便为所测的温度,还需要判断正负。前5个数字为符号位,当前5位为1时,读取的温度为负数;当前5位为0时,读取的温度为正数。16位数字摆放是从低位到高位,温度的关系图如图412所示。 图412为温度的关系图 4343.DS18B20控制方法 DS18B20有六条控制命令,如表41所示: 表41 为DS18B20有六条控制命令 指 令 约定代码 *** 作 说 明 温度转换 44H 启动DS18B20进行温度转换 读暂存器 BEH 读暂存器9位二进制数字 写暂存器 4EH 将数据写入暂存器的TH、TL字节 复制暂存器 48H 把暂存器的TH、TL字节写到E2RAM中 重新调E2RAM B8H 把E2RAM中的TH、TL字节写到暂存器TH、TL字节 读电源供电方式 B4H 启动DS18B20发送电源供电方式的信号给主CPU 4344 DS18B20的初始化 (1) 先将数据线置高电平“1”。 (2) 延时(该时间要求的不是很严格,但是尽可能的短一点) (3) 数据线拉到低电平“0”。 (4) 延时750微秒(该时间的时间范围可以从480到960微秒)。 (5) 数据线拉到高电平“1”。 (6) 延时等待(如果初始化成功则在15到60毫秒时间之内产生一个由DS18B20所返回的低电平“0”。据该状态可以来确定它的存在,但是应注意不能无限的进行等待,不然会使程序进入死循环,所以要进行超时控制)。 (7) 若CPU读到了数据线上的低电平“0”后,还要做延时,其延时的时间从发出的高电平算起(第(5)步的时间算起)最少要480微秒。 (8) 将数据线再次拉高到高电平“1”后结束。 其时序如图413所示: 图413 初始化时序图 4345 DS18B20的写 *** 作 (1) 数据线先置低电平“0”。 (2) 延时确定的时间为15微秒。 (3) 按从低位到高位的顺序发送字节(一次只发送一位)。 (4) 延时时间为45微秒。 (5) 将数据线拉到高电平。 (6) 重复上(1)到(6)的 *** 作直到所有的字节全部发送完为止。 (7) 最后将数据线拉高。 DS18B20的写 *** 作时序图如图414所示。 图414 DS18B20的写 *** 作时序图 4346 DS18B20的读 *** 作 (1)将数据线拉高“1”。 (2)延时2微秒。 (3)将数据线拉低“0”。 (4)延时3微秒。 (5)将数据线拉高“1”。 (6)延时5微秒。 (7)读数据线的状态得到1个状态位,并进行数据处理。 (8)延时60微秒。 DS18B20的读 *** 作时序图如图415所示。 图115 DS18B20的读 *** 作图 数字温度传感器DS18B20介绍
1、DS18B20的主要特性 11、适应电压范围更宽,电压范围:30~55V,在寄生电源方式下可由数 据线供电 12、独特的单线接口方式,DS18B20在与微处理器连接时仅需要一条口线即可实现微处理器与DS18B20的双向通讯 13、 DS18B20支持多点组网功能,多个DS18B20可以并联在唯一的三线上,实现组网多点测温 14、DS18B20在使用中不需要任何外围元件,全部 传感元件及转换电路集成在形如一只三极管的集成电路内 15、温范围-55℃~+125℃,在-10~+85℃时精度为±05℃ 16、可编程 的分辨率为9~12位,对应的可分辨温度分别为05℃、025℃、0125℃和00625℃,可实现高精度测温 17、在9位分辨率时最多在 9375ms内把温度转换为数字,12位分辨率时最多在750ms内把温度值转换为数字,速度更快 18、测量结果直接输出数字温度信号,以"一 线总线"串行传送给CPU,同时可传送CRC校验码,具有极强的抗干扰纠错能力 19、负压特性:电源极性接反时,芯片不会因发热而烧毁, 但不能正常工作。 2、DS18B20的外形和内部结构DS18B20内部结构主要由四部分组成:64位光刻ROM 、温度传感器、非挥发的温度报警触发器TH和TL、配置寄存器。DS18B20的外形及管脚排列如下图1: DS18B20引脚定义: (1)DQ为数字信号输入/输出端; (2)GND为电源地; (3)VDD为外接供电电源输入端(在寄生电源接线方式时接地)。
图2: DS18B20内部结构图 3、DS18B20工作原理 DS18B20的读写时序和测温原理与DS1820相同,只是得到的温度值的位数因分辨率不同而不同,且温度转换时的延时时间由2s 减为750ms。 DS18B20测温原理如图3所示。图中低温度系数晶振的振荡频率受温度影响很小,用于产生固定频率的脉冲信号送给计数器1。高温度系数晶振 随温度变化其振荡率明显改变,所产生的信号作为计数器2的脉冲输入。计数器1和温度寄存器被预置在-55℃所对应的一个基数值。计数器1对 低温度系数晶振产生的脉冲信号进行减法计数,当计数器1的预置值减到0时,温度寄存器的值将加1,计数器1的预置将重新被装入,计数器1重 新开始对低温度系数晶振产生的脉冲信号进行计数,如此循环直到计数器2计数到0时,停止温度寄存器值的累加,此时温度寄存器中的数值即 为所测温度。图3中的斜率累加器用于补偿和修正测温过程中的非线性,其输出用于修正计数器1的预置值。 图3:DS18B20测温原理框图
DS18B20有4个主要的数据部件: (1)光刻ROM中的64位序列号是出厂前被光刻好的,它可以看作是该DS18B20的地址序列码。64位光刻ROM的排列是:开始8位 (28H)是产品类型标号,接着的48位是该DS18B20自身的序列号,最后8位是前面56位的循环冗余校验码(CRC=X8+X5+X4+1)。光刻ROM的作用 是使每一个DS18B20都各不相同,这样就可以实现一根总线上挂接多个DS18B20的目的。 (2)DS18B20中的温度传感器可完成对温度的测量,以12位转化为例:用16位符号扩展的二进制补码读数形式提供,以 00625℃/LSB形式表达,其中S为符号位。
表1: DS18B20温度值格式表 这是12位转化后得到的12位数据,存储在18B20的两个8比特的RAM中,二进制中的前面5位是符号位,如果测得的温度大于0, 这5位为0,只要将测到的数值乘于00625即可得到实际温度;如果温度小于0,这5位为1,测到的数值需要取反加1再乘于00625即可得到实际 温度。 例如+125℃的数字输出为07D0H,+250625℃的数字输出为0191H,-250625℃的数字输出为FE6FH,-55℃的数字输出为FC90H 。 表2: DS18B20温度数据表
(3)DS18B20温度传感器的存储器 DS18B20温度传感器的内部存储器包括一个高速暂存RAM和一个非易失性的可电擦除的EEPRAM,后者存放高温度和低温度触发器 TH、TL和结构寄存器。 (4)配置寄存器 该字节各位的意义如下: 表3:配置寄存器结构 TM R1 R0 1 1 1 1 1
低五位一直都是"1",TM是测试模式位,用于设置DS18B20在工作模式还是在测试模式。在DS18B20出厂时该位被设置为0,用 户不要去改动。R1和R0用来设置分辨率,如下表所示:(DS18B20出厂时被设置为12位) 表4:温度分辨率设置表 R1 R0 分辨率 温度最大转换时间
0 0 9位
9375ms
0 1 10位
1875ms
1 0 11位
375ms
1 1 12位
750ms
4、高速暂存存储器 高速暂存存储器由9个字节组成,其分配如表5所示。当温度转换命令发布后,经转换所得的温度值以二字节补码形式存放在 高速暂存存储器的第0和第1个字节。单片机可通过单线接口读到该数据,读取时低位在前,高位在后,数据格式如表1所示。对应的温度计算: 当符号位S=0时,直接将二进制位转换为十进制;当S=1时,先将补码变为原码,再计算十进制值。表 2是对应的一部分温度值。第九个字节是 冗余检验字节。 表5:DS18B20暂存寄存器分布
寄存器内容 字节地址
温度值低位 (LS Byte) 0
温度值高位 (MS Byte) 1
高温限值(TH) 2
低温限值(TL) 3
配置寄存器 4
保留 5
保留 6
保留 7
CRC校验值 8
根据DS18B20的通讯协议,主机(单片机)控制DS18B20完成温度转换必须经过三个步骤:每一次读写之前都要对DS18B20进行 复位 *** 作,复位成功后发送一条ROM指令,最后发送RAM指令,这样才能对DS18B20进行预定的 *** 作。复位要求主CPU将数据线下拉500微秒,然后 释放,当DS18B20收到信号后等待16~60微秒左右,后发出60~240微秒的存在低脉冲,主CPU收到此信号表示复位成功。 表6:ROM指令表 指 令 约定代码 功 能
读ROM 33H 读DS1820温度传感器ROM中的编码(即64位地址)
符合 ROM 55H 发出此命令之后,接着发出 64 位 ROM 编码,访问单总线上与该编码相对应的 DS1820 使之作出响应,为下一步对该 DS1820 的读写作准备。
搜索 ROM 0FOH 用于确定挂接在同一总线上 DS1820 的个数和识别 64 位 ROM 地址。为 *** 作各器件作好准备。
跳过 ROM 0CCH
忽略 64 位 ROM 地址,直接向 DS1820 发温度变换命令。适用于单片工作。
告警搜索命令 0ECH
执行后只有温度超过设定值上限或下限的片子才做出响应。
表6:RAM指令表 指 令 约定代码 功 能
温度变换 44H 启动DS1820进行温度转换,12位转换时最长为750ms(9位为9375ms)。结果存入内部9字节RAM中。
读暂存器
0BEH 读内部RAM中9字节的内容
写暂存器
4EH 发出向内部RAM的3、4字节写上、下限温度数据命令,紧跟该命令之后,是传送两字节的数据。
复制暂存器
48H
将RAM中第3 、4字节的内容复制到EEPROM中。
重调 EEPROM
0B8H
将EEPROM中内容恢复到RAM中的第3 、4字节。
读供电方式 0B4H
读DS1820的供电模式。寄生供电时DS1820发送“ 0 ”,外接电源供电 DS1820发送“ 1 ”。
5、DS18B20的应用电路DS18B20测温系统具有测温系统简单、测温精度高、连接方便、占用口线少等优点。下面就是DS18B20几个不同应用方式下的 测温电路图: 51、DS18B20寄生电源供电方式电路图如下面图4所示,在寄生电源供电方式下,DS18B20从单线信号线上汲取能量:在信号线DQ处于高电平期间把能量储存在内部 电容里,在信号线处于低电平期间消耗电容上的电能工作,直到高电平到来再给寄生电源(电容)充电。 独特的寄生电源方式有三个好处: 1)进行远距离测温时,无需本地电源 2)可以在没有常规电源的条件下读取ROM 3)电路更加简洁,仅用一根I/O口实现测温 要想使DS18B20进行精确的温度转换,I/O线必须保证在温度转换期间提供足够的能量,由 于每个DS18B20在温度转换期间工作电流达到1mA,当几个温度传感器挂在同一根I/O线上进行多点测温时,只靠47K上拉电阻就无法提供足够的 能量,会造成无法转换温度或温度误差极大。 因此,图4电路只适应于单一温度传感器测温情况下使用,不适宜采用电池供电系统中。并 且工作电源VCC必须保证在5V,当电源电压下降时,寄生电源能够汲取的能量也降低,会使温度误差变大。 图4
图4 52、DS18B20寄生电源强上拉供电方式电路图改进的寄生电源供电方式如下面图5所示,为了使DS18B20在动态转换周期中获得足够的电流供应,当进行温度转换或拷贝到 E2存储器 *** 作时,用MOSFET把I/O线直接拉到VCC就可提供足够的电流,在发出任何涉及到拷贝到E2存储器或启动温度转换的指令后,必须在最 多10μS内把I/O线转换到强上拉状态。在强上拉方式下可以解决电流供应不走的问题,因此也适合于多点测温应用,缺 点就是要多占用一根I/O口线进行强上拉切换。 图5
图5 注意:在图4和图5寄生电源供电方式中,DS18B20的VDD引脚必须接地 53、DS18B20的外部电源供电方式在外部电源供电方式下,DS18B20工作电源由VDD引脚接入,此时I/O线不需要强上拉,不存在电源电流不足的问题,可以保证 转换精度,同时在总线上理论可以挂接任意多个DS18B20传感器,组成多点测温系统。注意:在外部供电的方式下,DS18B20的GND引脚不能悬空 ,否则不能转换温度,读取的温度总是85℃。 图6:外部供电方式单点测温电路 图6
图7:外部供电方式的多点测温电路图 图7
外部电源供电方式是DS18B20最佳的工作方式,工作稳定可靠,抗干扰能力强,而且电路也比较简单,可以开发出稳定可靠的多点温度 监控系统。站长推荐大家在开发中使用外部电源供电方式,毕竟比寄生电源方式只多接一根VCC引线。在外接电源方式下, 可以充分发挥DS18B20宽电源电压范围的优点,即使电源电压VCC降到3V时,依然能够保证温度量精度。 6、DS1820使用中注意事项 DS1820虽然具有测温系统简单、测温精度高、连接方便、占用口线少等优点,但在实际应用中也应注意以下几方面的问题: 61、较小的硬件开销需要相对复杂的软件进行补偿,由于DS1820与微处理器间采用串行数据传送,因此 ,在对DS1820进行读写编程时,必须严格的保证读写时序,否则将无法读取测温结果。在使用PL/M、C等高级语言进行系统程序设计时,对 DS1820 *** 作部分最好采用汇编语言实现。 62、在DS1820的有关资料中均未提及单总线上所挂DS1820数量问题,容易使人误认为可以挂任意多个 DS1820,在实际应用中并非如此。当单总线上所挂DS1820超过8个时,就需要解决微处理器的总线驱动问题,这一点在进行多点测温系统设计时 要加以注意。 63、连接DS1820的总线电缆是有长度限制的。试验中,当采用普通信号电缆传输长度超过50m时,读取的 测温数据将发生错误。当将总线电缆改为双绞线带屏蔽电缆时,正常通讯距离可达150m,当采用每米绞合次数更多的双绞线带屏蔽电缆时,正 常通讯距离进一步加长。这种情况主要是由总线分布电容使信号波形产生畸变造成的。因此,在用DS1820进行长距离测温系统设计时要充分考 虑总线分布电容和阻抗匹配问题。 64、在DS1820测温程序设计中,向DS1820发出温度转换命令后,程序总要等待DS1820的返回信号,一旦 某个DS1820接触不好或断线,当程序读该DS1820时,将没有返回信号,程序进入死循环。这一点在进行DS1820硬件连接和软件设计时也要给予 一定的重视。 测温电缆线建议采用屏蔽4芯双绞线,其中一对线接地线与信号线,另一组接VCC和地线,屏蔽层在源端单点接地。

在DS18B20的技术手册里有说,在12位精度下,以00625℃递增,上电默认为12位精度。
温度为正时那样算是对,是负时就是错的。
规范写法为:
temp=temp2;
temp=temp<<8;
temp=temp|temp1;
if(temp>0xf000)//负温度
{
temp=0xffff-temp+1;
temp_f = -(temp 00625); //实际温度值
}
else//正温度
temp_f = temp 00625; //实际温度值

#include<reg51h>
#include<intrinsh>
#include <mathH> //要用到取绝对值函数abs()
//通过DS18B20测试当前环境温度, 并通过数码管显示当前温度值, 目前显示范围: -55~ +125度
sbit wela = P2^7; //数码管位选
sbit dula = P2^6; //数码管段选
sbit ds = P2^2;
int tempValue;
//数码管2-5位选
unsigned char code tablewe[]={0xfd,0xfb,0xf7,0xef,0xdf};
//0-F数码管的编码(共阴极)
unsigned char code table[]={
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71};
//0-9数码管的编码(共阴极), 带小数点
unsigned char code tableWidthDot[]={
0xbf,0x86,0xdb,0xcf,
0xe6,0xed,0xfd,0x87,
0xff,0xef};
//延时函数, 对于110592MHz时钟, 例i=10,则大概延时10ms
void delay(unsigned int i)
{
unsigned int j;
while(i--)
{
for(j = 0; j < 125; j++);
}
}

//初始化DS18B20
//让DS18B20一段相对长时间低电平, 然后一段相对非常短时间高电平, 即可启动
void dsInit()
{
//对于110592MHz时钟, unsigned int型的i, 作一个i++ *** 作的时间大于us
unsigned int i;
ds = 0;
i = 100; //拉低约800us, 符合协议要求的480us以上
while(i>0) i--;
ds = 1; //产生一个上升沿, 进入等待应答状态
i = 4;
while(i>0) i--;
}

void dsWait()
{
unsigned int i;
while(ds);
while(~ds); //检测到应答脉冲
i = 4;
while(i > 0) i--;
}
//向DS18B20读取一位数据
//读一位, 让DS18B20一小周期低电平, 然后两小周期高电平,
//之后DS18B20则会输出持续一段时间的一位数据
bit readBit()
{
unsigned int i;
bit b;
ds = 0;
i++; //延时约8us, 符合协议要求至少保持1us
ds = 1;
i++; i++; //延时约16us, 符合协议要求的至少延时15us以上
b = ds;
i = 8;
while(i>0) i--; //延时约64us, 符合读时隙不低于60us要求
return b;
}
//读取一字节数据, 通过调用readBit()来实现
unsigned char readByte()
{
unsigned int i;
unsigned char j, dat;
dat = 0;
for(i=0; i<8; i++)
{
j = readBit();
//最先读出的是最低位数据
dat = (j << 7) | (dat >> 1);
}
return dat;
}
//向DS18B20写入一字节数据
void writeByte(unsigned char dat)
{
unsigned int i;
unsigned char j;
bit b;
for(j = 0; j < 8; j++)
{
b = dat & 0x01;
dat >>= 1;
//写"1", 将DQ拉低15us后, 在15us~60us内将DQ拉高, 即完成写1
if(b)
{
ds = 0;
i++; i++; //拉低约16us, 符号要求15~60us内
ds = 1;
i = 8; while(i>0) i--; //延时约64us, 符合写时隙不低于60us要求
}
else //写"0", 将DQ拉低60us~120us
ds = 0;
i = 8; while(i>0) i--; //拉低约64us, 符号要求
ds = 1;
i++; i++; //整个写0时隙过程已经超过60us, 这里就不用像写1那样, 再延时64us了

}
}
//向DS18B20发送温度转换命令
void sendChangeCmd()
{
dsInit(); //初始化DS18B20, 无论什么命令, 首先都要发起初始化
dsWait(); //等待DS18B20应答
delay(1); //延时1ms, 因为DS18B20会拉低DQ 60~240us作为应答信号
writeByte(0xcc); //写入跳过序列号命令字 Skip Rom
writeByte(0x44); //写入温度转换命令字 Convert T
}
//向DS18B20发送读取数据命令
void sendReadCmd()
{
dsInit();
dsWait();
delay(1);
writeByte(0xcc); //写入跳过序列号命令字 Skip Rom
writeByte(0xbe); //写入读取数据令字 Read Scratchpad
}
//获取当前温度值
int getTmpValue()
{
unsigned int tmpvalue;
int value; //存放温度数值
float t;
unsigned char low, high;
sendReadCmd();
//连续读取两个字节数据
low = readByte();
high = readByte();
//将高低两个字节合成一个整形变量
//计算机中对于负数是利用补码来表示的
//若是负值, 读取出来的数值是用补码表示的, 可直接赋值给int型的
tmpvalue = high;
tmpvalue <<= 8;
tmpvalue |= low;
value = tmpvalue;

//使用DS18B20的默认分辨率12位, 精确度为00625度, 即读回数据的最低位代表00625度
t = value 00625;
//将它放大100倍, 使显示时可显示小数点后两位, 并对小数点后第三进行4舍5入
//如t=110625, 进行计数后, 得到value = 1106, 即1106 度
//如t=-110625, 进行计数后, 得到value = -1106, 即-1106 度
value = t 100 + (value > 0 05 : -05); //大于0加05, 小于0减05
return value;
}
unsigned char const timeCount = 3; //动态扫描的时间间隔
//显示当前温度值, 精确到小数点后一位
//若先位选再段选, 由于IO口默认输出高电平, 所以当先位选会使数码管出现乱码
void display(int v)
{
unsigned char count;
unsigned char datas[] = {0, 0, 0, 0, 0};
unsigned int tmp = abs(v);
datas[0] = tmp / 10000;
datas[1] = tmp % 10000 / 1000;
datas[2] = tmp % 1000 / 100;
datas[3] = tmp % 100 / 10;
datas[4] = tmp % 10;
if(v < 0)
{
//关位选, 去除对上一位的影响
wela = 1; //打开锁存, 给它一个下降沿量
P0 = 0;
wela = 0;
//段选
dula = 1; //打开锁存, 给它一个下降沿量
P0 = 0x40; //显示"-"号
dula = 0;
//位选
P0 = 0xfe;//选通第一个数码管
wela = 1; //打开锁存, 给它一个下降沿量
wela = 0;
delay(timeCount);
}
for(count = 0; count != 5; count++)
{
//关位选, 去除对上一位的影响
P0 = 0;
wela = 1; //打开锁存, 给它一个下降沿量
wela = 0;
//段选
if(count != 2)
{

P0 = table[datas[count]]; //显示数字
}
else
{
P0 = tableWidthDot[datas[count]]; //显示带小数点数字
}
dula = 1; //打开锁存, 给它一个下降沿量
dula = 0;
//位选
P0 =tablewe[count]; //选择第(count + 1) 个数码管
wela = 1; //打开锁存, 给它一个下降沿量
wela = 0;
delay(timeCount);
}
}
void main()
{
unsigned char i;

while(1)
{
//启动温度转换
sendChangeCmd();
//显示5次
for(i = 0; i < 40; i++)
{
display(tempValue);
}
tempValue = getTmpValue();
}
}

//#include <at89x51h>//用AT89C51时就用这个头文件

#include <reg52h>//用华邦W78E58B时必须用这个头文件

sbit DQ = P3^7; //定义DQ引脚为P37

/ds18b20延迟子函数(晶振12MHz )/

/DS18B20对时间要求很严,但只能长不能短

在110592M下也行,因为时间长些/

void delay_18B20(unsigned int i)

{

while(i--);

}

/ds18b20初始化函数/

void Init_DS18B20(void)

{

 unsigned char x=0;

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

 delay_18B20(80); //精确延时 大于 480us

 DQ = 1;          //拉高总线

 delay_18B20(14);

 x=DQ;            //稍做延时后 如果x=0则初始化成功 x=1则初始化失败

 delay_18B20(20);

}

/ds18b20读一个字节/

unsigned char ReadOneChar(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_18B20(4);

 }

return(dat);

}

/ds18b20写一个字节/

void WriteOneChar(unsigned char dat)

{

unsigned char i=0;

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

{

DQ = 0;

DQ = dat&0x01;

delay_18B20(5);

DQ = 1;

dat>>=1;

}

}

/设置DS18B20工作状态

TH和TL分别是上限报警和下限报警温度,RS是显示分辨率的设置

/

void setds18b20(unsigned char TH,unsigned char TL,unsigned char RS)

{

Init_DS18B20();

WriteOneChar(0xCC);     // 跳过读序号列号的 *** 作

WriteOneChar(0x4E);  // //写入"写暂存器"命令,修改TH和TL和分辩率配置寄存器

//先写TH,再写TL,最后写配置寄存器

WriteOneChar(TH); //写入想设定的温度报警上限

WriteOneChar(TL); //写入想设定的温度报警下限

WriteOneChar(RS); //写配置寄存器,格式为0 R1 R0 1,1 1 1 1

//R1R0=00分辨率娄9位,R1R0=11分辨率为12位

}

/读取ds18b20当前温度/

unsigned char ReadTemperature(void)

{ unsigned char tt[2];

Init_DS18B20();

WriteOneChar(0xCC);     // 跳过读序号列号的 *** 作

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

delay_18B20(70);       // 温度转化要一段时间

Init_DS18B20();

WriteOneChar(0xCC);  //跳过读序号列号的 *** 作

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

//delay_18B20(70);

tt[0]=ReadOneChar();     //读取温度值低位

tt[1]=ReadOneChar();    //读取温度值高位

return(tt);

}

//#include <at89x51h>//用AT89C51时就用这个头文件

#include <reg52h>//用华邦W78E58B时必须用这个头文件

#include <intrinsh>//此函数为库函数,里面有_nop_函数,相当于汇编中的NOP

//Port Definitions

sbit LcdRs = P2^0;

sbit LcdRw = P2^1;

sbit LcdEn   = P2^2;

sfr  DBPort  = 0x80; //P0=0x80,P1=0x90,P2=0xA0,P3=0xB0数据端口

//内部等待函数

void LCD_Wait(void)

{

LcdRs=0; //RS=0表示选择指令寄存器

LcdRw=1; _nop_();//RW=1表示进行读 *** 作

LcdEn=1; _nop_();//在EN为下降沿的时候锁存数据

while(DBPort&0x80)

{

LcdEn=0;

_nop_();

    _nop_();

LcdEn=1;

_nop_();

    _nop_();

}

LcdEn=0;

}

//向LCD写入命令或数据

#define LCD_COMMAND 0      // Command

#define LCD_DATA 1      // Data

#define LCD_CLEAR_SCREEN 0x01      // 清屏

#define LCD_HOMING   0x02      // 光标返回原点

void LCD_Write(bit style, unsigned char input)

{

LcdEn=0;

LcdRs=style;

LcdRw=0; _nop_();

DBPort=input; _nop_();//注意顺序

LcdEn=1; _nop_();//注意顺序

LcdEn=0; _nop_();

LCD_Wait();

}

//设置显示模式

#define LCD_SHOW 0x04    //显示开

#define LCD_HIDE 0x00    //显示关

#define LCD_CURSOR 0x02  //显示光标

#define LCD_NO_CURSOR 0x00    //无光标

#define LCD_FLASH 0x01    //光标闪动

#define LCD_NO_FLASH 0x00    //光标不闪动

void LCD_SetDisplay(unsigned char DisplayMode)

{

LCD_Write(LCD_COMMAND, 0x08|DisplayMode);

}

//设置输入模式

#define LCD_AC_UP 0x02

#define LCD_AC_DOWN 0x00      // default

#define LCD_MOVE 0x01      // 画面可平移

#define LCD_NO_MOVE 0x00      //default

void LCD_SetInput(unsigned char InputMode)

{

LCD_Write(LCD_COMMAND, 0x04|InputMode);

}

//初始化LCD

void LCD_Initial()

{

LcdEn=0;

LCD_Write(LCD_COMMAND,0x38);           //8位数据端口,2行显示,57点阵

LCD_Write(LCD_COMMAND,0x38);

LCD_SetDisplay(LCD_SHOW|LCD_NO_CURSOR);    //开启显示, 无光标

LCD_Write(LCD_COMMAND,LCD_CLEAR_SCREEN);   //清屏

LCD_SetInput(LCD_AC_UP|LCD_NO_MOVE);       //AC递增, 画面不动

}

//

void GotoXY(unsigned char x, unsigned char y)

{

if(y==0)

LCD_Write(LCD_COMMAND,0x80|x);

if(y==1)

LCD_Write(LCD_COMMAND,0x80|(x-0x40));

}

void Print(unsigned char str)

{

while(str!='\0')

{

LCD_Write(LCD_DATA,str);

str++;

}

}

void LCD_Print(unsigned char x, unsigned char y, unsigned char str)

{

GotoXY(x,y);

Print(str);

}

#include <reg52h>

//#include <at89x52h>

//unsigned char code BCD[]={0x3f,0x06,0x5b,0x4f, //此处是将0-F转换成相应的BCD码

//                          0x66,0x6d,0x7d,0x07,

//                          0x7f,0x6f,0x77,0x7c,

//                          0x39,0x5e,0x79,0x71};

//unsigned char code KEY[]={0x00,0x00,0x01,0x02,0x03,//此处是为使程序通用,当键值不是按

//       0x04,0x05,0x06,0x07,//这个排列时,把此表更改即可

//    0x08,0x09,0,0x0b,//最前面的那个0x00是为了查表方便,

//    0x0c,0x0d,0x0e,0x0f};//因为键值是从1开始的

sfr key_port=0x90;     //定义P1口为键盘扫描口

//P0=0x80,P1=0x90,P2=0xA0,P3=0xB0数据端口

bit key_ok=0;        //有键按下的标志

/延时子程序

调用一次用时18微秒,t每加1,用时增加6微秒/

void delay(unsigned char t)

{

while(t--);

}

unsigned char r_left(unsigned char x)//循环左移一位

{

x<<=1;

x++;

return(x);

}

/粗判有无键按下

有键按下则将key_ok置1/

void scan_full(void)

{

unsigned char temp;

key_port=0xf0;  //低半字节为行线,高半字节为列线

temp=P1;

if(temp!=0xf0)

key_ok=1;

else key_ok=0;

}

/键盘扫描程序

功能:返回键值,当无键按下时,返回0/

unsigned char key_scan(void)

{

unsigned char temp,count=0x01,key_value;//按键返回值

unsigned char x_scan=0xfe,y_scan=0xef;//行、列扫描码

unsigned char i,j,y; //行数和列数

while(1)

{

scan_full();   //粗判是否有键按下

if(key_ok==1)

{

key_ok=0;

delay(200); //延时去抖动

scan_full(); //再次粗判是否有键按下

if(key_ok==1)

{

for(i=0;i<4;i++) //扫描4行

{

  key_port=x_scan;

for(j=0;j<4;j++) //每行4列

{

temp=key_port;

   temp=temp&0xf0;

   y=y_scan&0xf0;

   if(temp==y)

   {

while(key_ok!=0)//等待按键松开

{

scan_full();

}

    key_value=count;

    return(key_value);//找到键值,马上返回

   }

   else

   {

    count++;

    y_scan=r_left(y_scan);

   }

  }

y_scan=0xef; //扫描完一列,重新对列扫描量赋初值

  x_scan=r_left(x_scan);//行扫描码左移一位,扫描下一行  

}

}

}

return(key_value);//没键按下,返回0

}

}

//unsigned char key(void)

//{

// unsigned char x;

// unsigned char y;

// x=key_scan();

// return(x);

//y=KEY[x];

//return y;

//}

//#include <at89x51h>//用AT89C51时就用这个头文件

#include <reg52h>//用华邦W78E58B时必须用这个头文件

//#include <absacch>

//#include <ctypeh>

//#include <mathh>

//#include <stdioh>

//#include <stringh>

#include <DS18B20h> //测温头文件

#include <LCD1602h> //液晶显示头文件

#include <keyscanh> //键盘扫描头文件

sbit alarm=P2^6; //报警信号

//sbit DQ = P3^7; //定义DQ引脚为P37

unsigned char key_value;            //存放键盘扫描值

bit up_one,down_one;  //加1和减1标志

bit alarm_up_flag,alarm_down_flag; //上限报警和下限报警设置标志

bit set_temper_flag; //设置控制标志温度标志

bit alarm_switch; //报警开关

unsigned char user_temper;  //用户标定温度

unsigned char TH=110,TL=-20,RS=0x3f; //上限温度110,下限-20,分辨率10位,也就是025C

unsigned char t[2],pt; //用来存放温度值,测温程序就是通过这个数组与主函数通信的

unsigned char  TempBuffer1[17]={0x2b,0x20,0x30,0x30,0x2e,0x30,0x30,0x20,

0x53,0x45,0x54,0x2b,0x20,0x30,0x30,0x43,'\0'};

//显示实时温度,上电时显示+ 0000 SET+ 00C

unsigned char  TempBuffer0[17]={0x54,0x48,0x3a,0x2b,0x20,0x30,0x30,0x20,

0x54,0x4c,0x3a,0x2b,0x20,0x30,0x30,0x43,'\0'};

//显示温度上下限,上电时显示TH:+ 00 TL:+ 00C

unsigned char code dotcode[4]={0,25,50,75};

/因显示分辨率为025,但小数运算比较麻烦,故采用查表的方法

再将表值分离出十位和个位后送到十分位和百分位/

/用户设定温度转换为LCD显示数据

功能:将用户设定温度user_temper,分离出符号位,百、十、个位

  并将它们转化为ACSII码,送到液晶显示缓冲区

/

void user_temper_LCD(unsigned char temper)

{

if(temper>0x7f) //判断正负,如果为负温,将其转化为其绝对值

{

TempBuffer1[11]=0x2d; //0x2d为"-"的ASCII码

temper=~temper; //将负数的补码转换成绝对值

temper++;

}

else TempBuffer1[11]=0x2b; ////0x2B为"+"的ASCII码

TempBuffer1[12]=temper/100+0x30;              //分离出temper的百十个位

if( TempBuffer1[12]==0x30) TempBuffer1[12]=0xfe;     //百位数消隐

TempBuffer1[13]=(temper%100)/10+0x30;      //分离出十位

TempBuffer1[14]=(temper%100)%10+0x30;        //分离出个位

}

/温度上下限转换为LCD显示数据

功能:将上下限报警温度,分离出符号位,百、十、个位

  并将它们转化为ACSII码,送到液晶显示缓冲区

/

void alarm_LCD( unsigned char TH, unsigned char TL)

{

if(TH>0x7F)                    //判断正负,如果为负温,将其转化为其绝对值

{

TempBuffer0[3]=0x2d;      //0x2d为"-"的ASCII码

TH=~TH;  //将负数的补码转换成绝对值

TH++;

}

else TempBuffer0[3]=0x2b; //0x2B为"+"的ASCII码

if(TL>0x7f)

{

TempBuffer0[11]=0x2d;      //0x2d为"-"的ASCII码

TL=~TL+1;

}

else TempBuffer0[11]=0x2b; //0x2B为"+"的ASCII码

TempBuffer0[4]=TH/100+0x30;              //分离出TH的百十个位

if( TempBuffer0[4]==0x30) TempBuffer0[4]=0xfe; //百位数消隐

TempBuffer0[5]=(TH%100)/10+0x30; //分离出十位

TempBuffer0[6]=(TH%100)%10+0x30;   //分离出个位

TempBuffer0[12]=TL/100+0x30;              //分离出TL的百十个位

if( TempBuffer0[12]==0x30) TempBuffer0[12]=0xfe; //百位数消隐

TempBuffer0[13]=(TL%100)/10+0x30; //分离出十位

TempBuffer0[14]=(TL%100)%10+0x30;   //分离出个位

}

/温度转换为LCD显示数据

功能:将两个字节的温度值,分离出符号位,整数及小数

  并将它们转化为ACSII码,送到液晶显示缓冲区

/

void temper_LCD(void)

{

unsigned char x=0x00,y=0x00;

t[0]=pt;

pt++;

t[1]=pt;

if(t[1]>0x07)                    //判断正负温度

{

TempBuffer1[0]=0x2d;      //0x2d为"-"的ASCII码

t[1]=~t[1];  /下面几句把负数的补码/

t[0]=~t[0];   / 换算成绝对值/

x=t[0]+1;  //

t[0]=x;  //

if(x>255)                //

t[1]++;  //

}

else TempBuffer1[0]=0x2b; //0xfe为变"+"的ASCII码

t[1]<<=4; //将高字节左移4位

t[1]=t[1]&0x70; //取出高字节的3个有效数字位

x=t[0]; //将t[0]暂存到X,因为取小数部分还要用到它

x>>=4; //右移4位

x=x&0x0f; //和前面两句就是取出t[0]的高四位

t[1]=t[1]|x; //将高低字节的有效值的整数部分拼成一个字节

TempBuffer1[1]=t[1]/100+0x30;              //+0x30 为变 0~9 ASCII码

if( TempBuffer1[1]==0x30) TempBuffer1[1]=0xfe; //百位数消隐

TempBuffer1[2]=(t[1]%100)/10+0x30; //分离出十位

TempBuffer1[3]=(t[1]%100)%10+0x30;   //分离出个位

t[0]=t[0]&0x0c; //取有效的两位小数

t[0]>>=2; //左移两位,以便查表

x=t[0];

y=dotcode[x]; //查表换算成实际的小数

TempBuffer1[5]=y/10+0x30; //分离出十分位

TempBuffer1[6]=y%10+0x30; //分离出百分位

}

/键盘命令处理函数

功能:把键盘值转化成相应的功能标志位

备注:为了提高程序的健壮性,在功能标志位无效时,

up_one和down_one都无效,并且各功能标志之间

采用互锁处理,虽然这样麻烦,特别是功能标志较多时

更是麻烦,但各功能标志之间是同级别的;

也可采用多重if else方法,虽然简单,

但各功能标志之间有了明显的优先级差别

/

void key_command(unsigned char x)     

{

switch(x)

{

case 1: up_one=1;break;

case 2: down_one=1;break;

case 5: alarm_up_flag=!alarm_up_flag;break;

case 6: alarm_down_flag=!alarm_down_flag;break;

case 7: set_temper_flag=!set_temper_flag;break;

case 8: alarm_switch=!alarm_switch;break;

default: break;

}

if(!(alarm_up_flag||alarm_down_flag||set_temper_flag))

{

up_one=0x00; //在没有相应功能标志有效时

down_one=0x00; //up_one和down_one都被锁定

}

if(alarm_up_flag&&(!alarm_down_flag)&&(!set_temper_flag))//设置上限报警

{

if(up_one)//上限报警加1

{

TH++;up_one=0;

if(TH>=100)//超过100度,回零到20度

TH=20;

}

if(down_one)//上限报警减1

{

TH--;down_one=0;

if(TH<=20)//小于20度,回零到20度

TH=20;

}

}

if((!alarm_up_flag)&&(alarm_down_flag)&&(!set_temper_flag))//设置下限报警

{

if(up_one)

{

TL++;up_one=0;

if(TL>=20)//高于20度,回零到0度

TL=0;

}

if(down_one)

{

TL--;down_one=0;

if(TL<=0)//低于0度,回零到0度

TL=0;

}

}

if((!alarm_up_flag)&&(!alarm_down_flag)&&(set_temper_flag))//设置用户标定温度

{

if(up_one)

{

user_temper++;up_one=0;

if(user_temper>=60)//高于60度,回零到0度

user_temper=0;

}

if(down_one)

{

user_temper--;down_one=0;

if(user_temper<=0)//低于0度,回零到0度

user_temper=0;

}

}

//if(alarm_switch)

}

main()

{

setds18b20(TH,TL,RS);     //设置上下限报警温度和分辨率

delay(100); 

while(1)

{

pt=ReadTemperature();    //测温函数返回这个数组的头地址

 //读取温度,温度值存放在一个两个字节的数组中,

temper_LCD();  //实测温度转化为ACSII码,并送液晶显示缓冲区

user_temper_LCD(user_temper);  //用户设定温度转化为ACSII码,并送液晶显示缓冲区

alarm_LCD(TH,TL);  //上下限报警温度转化为ASCII码,并送液晶显示缓冲区

LCD_Initial(); //第一个参数列号,第二个为行号,为0表示第一行

//为1表示第二行,第三个参数为显示数据的首地址

LCD_Print(0,0,TempBuffer0);

LCD_Print(0,1,TempBuffer1);

scan_full();                     //看有无键按下

if(key_ok) //如有键按下则看到底哪个键按下

{

key_value=key_scan();  //调用键盘扫描程序

key_command(key_value);  //键盘命令处理函数

}

}

}

觉得能运行,我试过了,自己看图


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/12697187.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-27
下一篇 2023-05-27

发表评论

登录后才能评论

评论列表(0条)

保存