基于AVR单片机DS18B20的温度测量实验

更新时间:2023-10-15 08:15:02 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

AVR学习笔记七、基于DS18B20的温度测量实验

7.1 基于DS18B20的基本测温实验

7.1.1、实例功能

传统的温度测量采用热敏电阻,但热敏电阻存在可靠性差,测温准确率低,并且必须经过专门的接口电路将采集到的模拟量转换为数字量后才能由单片机处理。

DS18B20是美国DALLAS公司推出的一款单线数字温度传感器。它具有:体积小,功耗低,精度高,可靠性好,易于单片机接口等优点,每片DS18B20都有唯一的一个可读出的序列号,同时DS18B20还采用了寄生电源技术,可以不用外接电源。综合以上特点,DS18B20特别适合于多点测温系统。

本节首先介绍DS18B20的一些基本知识:特点、结构、原理、控制时序、与单片机的接口方法等。最后通过一个实例实现最简单的温度测量。

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

● 单片机系统:利用ATmega16单片机与DS18B20温度传感器通信,控制温度的采集过程,并将采集到的温度值通过串口发送到计算机。

● 外围电路:外围电路分两部分:串口电路部分(实现将采集到的温度值发送到计算机的功能)、DS18B20温度采集电路(实现采集环境温度的功能)。

● 软件程序:编写软件,实现温度测量和串口发送数据功能。

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

● 理解DS18B20的特点、结构和原理和接口设计方法。 ● 掌握DS18B20的控制时序和控制方法流程。 ● 掌握最简单的采集温度指令。

7.1.2 器件和原理 1、DS18B20介绍

DS18B20主要有以下特点:

●单线接口:DS18B20与单片机连接时仅需一根I/O口线即可实现单片机与DS18B20之间的双向通信。

●实际使用中不需要任何外围元件。

●可用数据线供电,电压范围3.0-5.5V。测温范围-55-+125oC。 ●可编程实现9-12位的数字读数方式。

●用户可设定的非易失性(掉电不丢失)的温度上下线报警值。

●支持多点组网功能,多个DS18B20可并联在唯一的三总线上,实现多点温度测量。 ●负压特性:电源极性接反时不会烧坏DS18B20,但是也不能正常工作 DS18B20的外形级封装如图7.1.1,引脚说明: NC 空引脚,不连接外部信号。

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

GND 接地引脚。

DQ 数据引脚,传递数据的输入和输出。该引脚常态下为开漏输出,输出高电平。

图7.1.1 DS18B20的外形级封装

7.1.2DS18B20的内部结构

DS18B20的内部结构如图7.1.2。DS18B20的内部结构主要有64位ROM、温度灵敏元件、内部存储器和配置寄存器四部分组成。

图7.1.2 DS18B20的内部结构

● 64位ROM:64位ROM的内容是64位序列号,是出厂前用激光刻好的。它可以用作该DS18B20的地址序列码。每一个DS18B20的64位ROM都不同,这样就可以实现一根总线上挂多个DS18B20的目的。这64位 ROM的排列是:开始8位是产品类型号,接

着的48位是该DS18B20的自身的序列号,最后8位是前面56位的循环冗余(CRC,

CRC=X8+X5+X4+1)校验码。

● 温度灵敏元件:温度灵敏元件完成对温度的测量,测量后的结果存储在两个8位的寄存器中,这两个寄存器定义如图7.1.3。温度寄存器高字节的高5位是符号位,温度为负时这5位为1;温度为正时,这5位为0。高字节寄存器的低3位与低字节寄存器的高4位组成温度的整数部分,低字节寄存器的低4位是温度的小数部分。当温度大于0时,温度值以原码存放。而当温度小于0时,以二进制补码形式存放。

当转换位数为12位时,温度的精度为1/16(4位小数位,所以为16)=0.0625度。同理,当转换位数为11位时,精度为1/8=0.125度。

对于温度的计算,以12位转换位数为例:对于正的温度,只要将测到的数值的整数部分取出,转换为10进制,再将小数部分乘以0.0625就可以得到10进制的小数位的温度值了。而对于负的温度,则需要将采集到的数值取反加1,即可得到实际温度的16进制表示。再按照正温度的计算方法就可以得出10进制的负的温度了。

图7.1.3 DS18B20温度寄存器格式

图7.1.4所示是在12位转换位数情况下的温度转换值和温度对照表

图7.1.4 12位转换位数的温度转换值和温度对照表

7.1.3 DS18B20的内部存储器

DS18B20的内部存储器包括一个告诉暂存RAM和一个非易失性的可电擦除的EEPROM,后者存放温度的上下限报警值和配置寄存器。

高速暂存RAM以及EEPROM的构成如图7.1.5所示。高速暂存RAM由9个字节组成,当温度转换命令发出后,经转换获得的温度值以二进制补码形式存放在第0(LSB)和第一(MSB)个字节内。单片机通过单线接口DQ读出该数据,读取时低位在前,高位在后。

第二和第三个字节是温度的上(TH)下限(TL)报警值,他们没有小数位,第四个字节是配置寄存器,主要用以设置工作模式和转换位数。第五、第六和第七字节是保留位,没有实际意义,第八个字节是前面所有8个字节的CRC校验码。EEPROM由3个字节构成,用来存放温度的上下限报警值以及配置寄存器的内容。

图7.1.5 高速暂存RAM以及EEPROM的构成

配置寄存器的各位意义如图7.1.6所示。低五位的读出值总是为1,第7位是测试模式位,用于设置DS18B20是工作在测试模式还是工作模式,出厂时默认设置为0,用户不用改动。R1和R0用来设置温度转换位数。具体设置如图7.1.7所示。

图7.1.6 配置寄存器结构

图7.1.7 温度值转换位数设置表

7.1.4 DS18B20控制流程

再由DS18B20构成的单总线系统中,DS18B20只能作为从机,单片机或者其它部件作为主机。

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

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

二)、复位成功后发送一条ROM指令 三)、最后发送RAM指令,这样才能够对DS18B20进行正确的操作。

● 复位:复位要求主机将数据线拉低最少480us,然后释放,当DS18B20受到信号后,等待15-60us,然后把总线拉低60-240us,主机接收到此信号表示复位成功。 ● ROM指令:ROM指令表明了主机寻址一个或多个DS18B20中的某个或某几个,或者

是读取某个DS18B20的64位序列号。

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

温度等)。 1、ROM操作命令:DS18B20采用一线通信接口。因为一线通信接口,必须在先完成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序列号,可以在挂在一线上多个器件选定某一个器件,同时,总线也可以知道总线上挂有有多少,什么样的设备。 2、RAM指令

DS18B20有六条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”表示外部电源供电。

7.1.5 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)微秒。

7.1.3、电路和连接

串口电路前面已经介绍,本例中不再重复。本例中DS18B20与单片机的连接如图7.1.8所示,由于DS18B20的数据线要求空闲状态为高电平,所以我在DS18B20的数据线与电源线VCC之间加了一个4.7K的上拉电阻,如果不想接上拉电阻的话,可以使能PA2口的内部上拉功能。从图中可以看出,本例使用的是给DS18B20外接电源的方式。

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

图7.1.8 DS18B20电路

7.1.4、程序设计

1、程序功能

程序的功能是使用单片机的PA2口的实现对DS18B20的操作,然后将读出的温度值通过串口发送到计算机。

2函数说明

本程序多个功能函数,分别是:

● 端口初始化函数,设置各端口的初始工作状态。 ● 串口通信相关函数:

void Usart_Init(void); //USART寄存器设置

void Usart_PutChar(unsigned char cTXData); //字节发送函数 void Usart_PutString(unsigned char *pcString); //字符串发送函数 这些函数已经在前面的实例中做过介绍,在此不再重复。 ● DS18B20操作相关函数:

void Port_DS18b20(void); //DS18B20端口配置,配置DS18B20端口的初始状态。

unsigned char DS18B20_Init(void); //DS18B20初始化,主机发送复位脉冲信号,DS18B20接收到复位信号后发出应答信号,单片机检测复位是否成功。

unsigned char Read_18b20(void); //读18b20,读取DS18B20发送过来的1字节数据。

void Write_18b20(unsigned char dat); //写18b20,向DS18B20写1字节函数。 ● 延时相关函数:

void Delayus(unsigned int lus); //us延时函数 void Delayms(unsigned int lms); //ms延时函数

由于WINAVR自带函数库中的延时函数使用起来很不方便,并且晶振频率不同,延时时间也有区别,而对DS18B20的操作时序要求比较严格,所以本实例中自己写了两个延时函数。

3、使用WINAVR开发环境,使用的是外部12M的晶振,所以需要将makefile文件中的时钟频率修改为12M。另外在程序烧录到单片机的时候,熔丝位也要选择为外部12M晶振(注意是晶振,不是外部振荡器,一定不要选择错了,否则会导致单片机不能再烧写程序)。 4、程序说明。在本实例中我们只是要首先了解DS18B20的原理和特点,至于例程在只要简单实现利用单片机实现对单个DS18B20的温度测量即可。所以在程序中我们对温度测量的处理是:

1)复位(假定复位成功,不检测复位是否成功),

2)发送跳过ROM指令(我们系统只连接了一个DS18B20,所以可以使用这条指令), 3)发送温度转换命令(我们采用DS18B20默认的12位温度转换,所以不用对DS18B20进行任何配置,直接指示DS18B20开始采集温度),

4)延时1S,等待DS18B20完成温度采集(默认12位温度转换时,采集一次温度的时间为750ms,所以至少要延时750ms以上), 5)复位(每次对DS18B20进行操作都要进行复位、ROM操作、RAM操作这三个步骤), 6)发送跳过ROM指令

7)发送读内部RAM命令(这个指令读取DS18B20中RAM的全部9个字节,而我们只需要得到温度值就可以了,温度值存储在RAM的前两个字节里面,所以我们读取完前两个字节的内容后可以不必理会后面的内容),

8)将采集到的温度值进行处理(判断温度的正负,分离温度的整数位和小数位),然后将处理后的数据发送到串口。

9)延时4S,然后跳到步骤1),重复步骤1)-8),完成下一次温度测量

5、程序代码

#include

#include

#include //中断函数头文件

//××××××××××××引脚宏定义××××××××××××× //18B20定义

#define SET_DQ (PORTA) |= (1 << (PA2)) // 18b20 高电平 #define CLR_DQ (PORTA) &=~(1 << (PA2)) // 18b20 低电平 #define DQ_IN (PINA) & (1<<(PA2)) // 18b20信号输入

#define SET_OUT (DDRA)|= (1<<(PA2)) //PA2定义成输出 #define SET_IN (DDRA)&=~(1<<(PA2)) //PA2定义成输入

//常量声明 #define BAUD 9600

//全局变量声明

unsigned char Temp_H,Temp_L,OK_Flag; //温度高位,低位,复位成功标志

//函数声明

void Delayus(unsigned int lus); //us延时函数 void Delayms(unsigned int lms); //ms延时函数 void Port_DS18b20(void); //DS18B20端口配置 void Port_Init(void); //端口初始化配置 void Usart_Init(void); //USART寄存器设置

void Usart_PutChar(unsigned char cTXData); //字节发送函数 void Usart_PutString(unsigned char *pcString); //字符串发送函数

unsigned char DS18B20_Init(void); //DS18B20初始化 unsigned char Read_18b20(void); //读18b20 void Write_18b20(unsigned char dat); //写18b20

int main(void) {

unsigned char i;

unsigned int tempint,tempint1,tempint2,tempint3,tempint4;

//分别存储温度整数值,整数值的千,百,十,个位 unsigned int temppoint,temppoint1,temppoint2,temppoint3,temppoint4;

//分别存储温度小数值,小数值的千,百,十,个位

Port_Init(); //端口初始化 Usart_Init(); //串口初始化

Port_DS18b20(); //DS18B20端口初始化

tempint = 0; //变量初始化 temppoint=0; Temp_H = 0; Temp_L = 0; OK_Flag = 0;

Usart_PutString(\温度测量实验\Usart_PutChar(0x0D);

Usart_PutChar(0x0A); //结尾发送回车换行

sei(); //使能全局中断

while(1) {

/*

if(DS18B20_Init()) //判断DS18B20复位是否成功 { } else {

PORTB = 0x02; } */

cli(); //关中断

DS18B20_Init(); //初始化DS18B20

Write_18b20(0Xcc); //发送ROM指令,跳过ROM匹配

Write_18b20(0X44); // 发送温度转换命令

PORTB = 0x01;

for(i=0;i<50;i++) //延时1S,等转换完成 {

Delayms(20);

}

DS18B20_Init(); //初始化DS18B20

Write_18b20(0Xcc); //发送ROM指令,跳过ROM匹配

Write_18b20(0Xbe); //发送读取暂存器指令

Temp_L = Read_18b20(); //获得温度的低位

Temp_H = Read_18b20(); //获得温度的高位

if(Temp_H & 0x08) //判断温度的正负 {

}

tempint = ((Temp_H << 4) & 0x70) | (Temp_L >> 4); //获得温度的整数位

tempint1 = tempint / 1000; //千位 tempint2 = tempint % 1000 / 100; //百位 tempint3 = tempint % 100 / 10; //十位 tempint4 = tempint % 10; //个位

temppoint = Temp_L & 0x0f; //取出温度的小数位

temppoint = (temppoint * 625); //小数位乘以0.625得出温度的小数位值,在此扩大 //10000倍,得出温度的4位小数位,显示的时候加小数点

temppoint1 = temppoint / 1000; //千位 temppoint2 = temppoint % 1000 / 100; //百位 temppoint3 = temppoint % 100 / 10; //十位

temppoint4 = temppoint % 10; //个位

Usart_PutString(\当前环境温度为:\ //发送温度值到上位机

if(!(tempint1)) //高位为零,则不显示 {

Usart_PutChar(' ');

Temp_H = ~Temp_H; //负温度。取反加1 Temp_L = ~Temp_L; //

SREG |= ~(1 << SREG_C); //清零进位位标志 Temp_L++; //温度低字节加1 if(SREG & (1 << SREG_C)) //有进位吗? { }

Temp_H++; //有进位,则温度高字节加1

} else { }

if(!(tempint2)) { Usart_PutChar(' '); } else {

Usart_PutChar(tempint2 + 0x30); }

if(!(tempint3)) { }

Usart_PutChar(' ');

else { }

Usart_PutChar(tempint3 + 0x30);

//Usart_PutChar(tempint4 + 0x30);

Usart_PutChar(tempint1 + 0x30); Usart_PutChar(tempint2 + 0x30); Usart_PutChar(tempint3 + 0x30);

Usart_PutChar(tempint4 + 0x30);

Usart_PutChar('.'); //显示小数点

Usart_PutChar(temppoint1 + 0x30); //显示小数位 Usart_PutChar(temppoint2 + 0x30); Usart_PutChar(temppoint3 + 0x30); Usart_PutChar(temppoint4 + 0x30);

Usart_PutChar(' '); //不显示,空一格

Usart_PutChar('o'); //显示温度的符号。由于实在找不到温度那个再上面的小o, Usart_PutChar('C'); //只好用普通的小写o来代替了。

Usart_PutChar(0x0D); Usart_PutChar(0x0A); //结尾发送回车换行 sei(); //开中断

for(i=0;i<200;i++) //延时4S,再进行温度转换 {

Delayms(20);

}

} }

//端口状态初始化设置函数 void Port_Init() { }

void Port_DS18b20() { DDRA &= ~(1 << PA2); // 输入模式(上电时为高电平) PORTA &= ~(1 << PA2); // 输出锁存器写0,以后不再更改 }

//USART寄存器配置函数

void Usart_Init() { UCSRA = 0X00; UCSRC |= (1<

//写 UCSRC 时, URSEL 应设置为 1。

UBRRL = (F_CPU / BAUD / 16 - 1) % 256; //波特率设置

UBRRH = (F_CPU / BAUD / 16 - 1) / 256;

UCSRB |= (1 << RXCIE) | (1 << RXEN) | (1 << TXEN); //发送使能

PORTB = 0x00; DDRB = 0xff;

PORTD = 0X00; //USART的发送接收端口分别为PD0和PD1

DDRD |= (1 << PD1); //PD0为接收端口,置为输入口;PD1为发送端口,置为输出口

}

//字节发送函数

void Usart_PutChar(unsigned char cTXData) {

while( !(UCSRA & (1 << UDRE)) ); //只有数据寄存器为空时才能发送数据 UDR = cTXData; //发送数据送USART I/O数据寄存器-UDR

}

//接收中断函数 ISR(USART_RXC_vect ) {

unsigned char Rev;

Rev = UDR; //从USART I/O数据寄存器-UDR中读出数据

Usart_PutChar(Rev); //将接收到的数据发送

}

void Usart_PutString(unsigned char *pcString) {

while (*pcString) { }

Usart_PutChar(*pcString++);

}

//DS18B20初始化

unsigned char DS18B20_Init() {

SET_OUT; //PA2设置为输出口(相当于拉低数据线上的电平)

Delayus(490); //延时大于480us

SET_IN; //输入 释放数据线(相当于拉高数据线上的电平)

Delayus(68); //延时大于60US,

//while(DQ_IN);//可以用两个while()死循环来判断复位是否成功,当数据线被拉低,说 //while(!(DQ_IN)); //明18b20开始复位应答,当数据线变高,说明应答完毕

if(DQ_IN) //判断DS18B20是否拉低数据线 { }

else { OK_Flag = 1; // 数据线是低?复位成功 }

Delayus(422); //有复位应答信号后,应当再延时一段时间(480-68),以等待应答完毕

return OK_Flag; //返回复位标志

OK_Flag = 0;

//

数据线是高?复位失败

}

//从DS18B20读取一个字节数据 unsigned char Read_18b20() {

unsigned char i;

unsigned char dat = 0; // dat用于存储读到的数据,先清零

}

for(i = 0;i < 8;i++) //共读8位数据,构成一个字节 {

SET_OUT; //定义为输出(拉低数据线)

Delayus(2); //拉低2微秒

SET_IN; //定义成输入,读入数据(同时也相当于拉高数据线)

Delayus(4); //延时

dat = dat >> 1; //数据右移,读顺序:先低后高 if(DQ_IN) //读数据, {

dat |= 0x80; //如果是高,置1,右移数据

//延时大于60us

}

Delayus(62);

}

return dat; //返回读到的1字节数据

//向DS18B20写1字节数据

void Write_18b20(unsigned char dat) { unsigned char i; for(i = 0;i < 8;i++) //写8次,一次写1位,先写低字节

{

SET_OUT; //拉低数据线2us,开始写数据 Delayus(2); //

if(dat & 0x01) //写数据 { }

SET_IN; //写1

else { SET_OUT; //写0

}

dat >>= 1; //数据右移1位,先写低位 Delayus(62); //延时大于60us

SET_IN; //拉高数据线

Delayus(2); //写两位数据的时间间隔

}

}

//us级别的延时函数 void Delayus(unsigned int lus) {

while(lus--) {

_delay_loop_2(3); //_delay_loop_2(1)是延时4个时钟周期,参数为3则延时12 //个时钟周期,本实验用12M晶体,则12个时钟周期为12/12=1us

}

}

//ms级别的延时函数 void Delayms(unsigned int lms) { }

while(lms--) { Delayus(1000); //延时1ms

}

7.2 基于寄生电源的DS18B20的温度测量

7.2.1、实例功能

完成了利用DS18B20实现最简单的温度测量后,我们再接再厉,继续深入研究DS18B20.。在上一实例中我们提到,DS18B20可以采用内部寄生电源供电,在本实例中我们就试着使用这一方法来实现不用给DS18B20加外接电源,利用寄生电源实现温度采集,同时我们也试着实现对DS18B20的RAM实现更多的操作,实现将温度上下限报警值写到RAM中,并复制到EEPROM中。

本实例包括三个功能模块,分别介绍如下:

● 单片机系统:利用ATmega16单片机与DS18B20温度传感器通信,控制温度的采集过程,并将采集到的温度值通过串口发送到计算机。

● 外围电路:外围电路分两部分:串口电路部分(实现将采集到的温度值发送到计算机的功能)、DS18B20温度采集电路(实现采集环境温度的功能),在DS18B20的电路部分,我们断开VCC与DS18B20的连接。

● 软件程序:编写软件,实现温度测量和串口发送数据功能。

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

● 理解DS18B20的特点、结构和原理和接口设计方法。 ● 掌握DS18B20的控制时序和控制方法流程。

● 掌握DS1820的RAM指令操作,以及操作EEPROM。

7.2.2 器件和原理

上一示例中我们已经对DS18B20的特点、原理进行了了解,并且通过控制时序实现了对DS18B20的读写,本实例中我们略过这些介绍,重点研究DS18B20的寄生电源供电方式。

1、DS18B20寄生电源供电方式的两种电路连接

DS18B20最基本电路连接如图7.2.1所示,图中DS18B20工作在寄生电源供电方式,它从数据线上获得能量,在信号线DQ处于高电平期间把能量储存在内部电容里,在信号线处于低电平期间消耗电容上储存的电能来使DS18B20工作,直到数据线变为高电平再给电容充电。

使用寄生电源供电有两个好处:

● 进行远距离测温时,无需本地电源;

● 电路更加简单,仅用一根I/O口线实现温度测量。

图7.2.1 DS18B20基本电路连接

上面的电路在总线上只连接1个DS18B20的情况下能满足测温要求,但是要想使DS18B20测温精确,或者总线上挂有多个DS18B20,上面的电路就很难满足要求了。因为每个DS18B20在温度转换期间的工作电流最大可达1.5mA,当多个DS18B20都挂在同一根I/O口线上进行多点测温时,只靠4.7K的上拉电阻无法提供足够的能量,会造成温度误差加大或者无法进行温度转换的后果。

为了使DS18B20在温度转换期间能够获得足够的电源供应,可以采用以下两种方法: 1)在每个DS18B20节点都单独为其供电,如图7.2.2,但是这种方法需要每个节点都有单独电源,这样寄生电源的优点就无从体现。在实际使用中只作单点测温时可以采用这种电路,多点测温基本不采用这种方法。

图7.2.2 节点单独供电的电路连接

2)使用强上拉电路:当进行温度转换或执行复制到EEPROM操作时,用低导通电阻三极管或者MOSFET把数据线直接拉到VCC就可以获得足够的电源,

7.2.3 使用强上拉的电路连接

注意使用寄生电源供电方式的时候,DS18B20的VCC和GND都要连接到地。

7.2.3、电路连接

限于学习板的实际情况,在本实例中我们使用节点单独供电的方法。具体实现方法是:将学习板上的DS18B20焊掉(上一实例中焊接的上拉电阻保留)。用3根导线分别连接DS18B20的3个引脚,把其中连接DS18B20的VCC和GND都连接到学习板的地线上,把连接DS18B20的DQ引脚的那根导线连接到单片机的PA2口。

至于电路的串口部分就不再说了。

7.3 利用DS18B20实现多点温度测量

1、程序功能

程序的功能是使用单片机的PA2口的实现对DS18B20的操作,然后将读出的温度值通过串口发送到计算机。

2函数说明

本程序多个功能函数,分别是:

● 端口初始化函数,设置各端口的初始工作状态。 ● 串口通信相关函数:

void Usart_Init(void); //USART寄存器设置

void Usart_PutChar(unsigned char cTXData); //字节发送函数

void Usart_PutString(unsigned char *pcString); //字符串发送函数 这些函数已经在前面的实例中做过介绍,在此不再重复。 ● DS18B20操作相关函数:

void Port_DS18b20(void); //DS18B20端口配置,配置DS18B20端口的初始状态。

unsigned char DS18B20_Init(void); //DS18B20初始化,主机发送复位脉冲信号,DS18B20接收到复位信号后发出应答信号,单片机检测复位是否成功。

unsigned char Read_18b20(void); //读18b20,读取DS18B20发送过来的1字节数据。

void Write_18b20(unsigned char dat); //写18b20,向DS18B20写1字节函数。 void DS18B20_StartConvert(void); //启动温度转换 void DS18B20_GetConvert(void); //获得温度转换结果 void DS18B20_ReadRAM(void); // 读取RAM内容

void DS18B20_WriteRAM(void); //写温度上下限和配置寄存器到RAM

void DS18B20_CopyEEPROM(void); //复制RAM中的温度上下线和配置寄存器到EEPROM

void DS18B20_RecallRAM(void); //把EEPROM中的温度上下线和配置寄存器恢复到RAM

● 延时相关函数:

void Delayus(unsigned int lus); //us延时函数

void Delayms(unsigned int lms); //ms延时函数

由于WINAVR自带函数库中的延时函数使用起来很不方便,并且晶振频率不同,延时时间也有区别,而对DS18B20的操作时序要求比较严格,所以本实例中自己写了两个延时函数。

3、使用WINAVR开发环境,使用的是外部12M的晶振,所以需要将makefile文件中的时钟频率修改为12M。另外在程序烧录到单片机的时候,熔丝位也要选择为外部12M晶振(注意是晶振,不是外部振荡器,一定不要选择错了,否则会导致单片机不能再烧写程序)。 4、程序说明。在本实例中我们不但实现了利用DS18B20测量温度,同时还实现了对DS18B20的RAM的读写,包括读RAM区的全部9个字节、写温度上下限报警值和配置寄存器、将数据复制到EEPROM、从EEPROM中恢复数据等,

在主程序的开始部分有一段对RAM操作的程序,我们如果想要观察对RAM的读写效果的话,只需将这段程序的屏蔽去掉,就可以在串口助手上利用十六进制显示的功能观察数据。

在程序中我们对温度测量的处理是:

1)复位(假定复位成功,不检测复位是否成功),

2)发送跳过ROM指令(我们系统只连接了一个DS18B20,所以可以使用这条指令), 3)发送温度转换命令(我们采用DS18B20默认的12位温度转换,所以不用对DS18B20进行任何配置,直接指示DS18B20开始采集温度),

4)延时1S,等待DS18B20完成温度采集(默认12位温度转换时,采集一次温度的时间为750ms,所以至少要延时750ms以上),

51)复位(每次对DS18B20进行操作都要进行复位、ROM操作、RAM操作这三个步骤), 6)发送跳过ROM指令

7)发送读内部RAM命令(这个指令读取DS18B20中RAM的全部9个字节,而我们只需要得到温度值就可以了,温度值存储在RAM的前两个字节里面,所以我们读取完前两个字节的内容后可以不必理会后面的内容), 8)将采集到的温度值进行处理(判断温度的正负,分离温度的整数位和小数位),然后将处理后的数据发送到串口。

9)延时4S,然后跳到步骤1),重复步骤1)-8),完成下一次温度测量

5、程序代码

由于本实例的程序量比较大,这里就不再列出了,直接放在附件里面。

7.3 基于DS18B20的多点温度测量

7.2.1、实例功能

完成了利用DS18B20实现最简单的温度测量后以及对DS18B20的RAM区进行读写之后,我们再接再厉,继续深入研究DS18B20.。在前面实例中我们提到,利用DS18B20可以很方便的实现多点测温,那么在本实例中我们就试着实现多点测温。 本实例包括三个功能模块,分别介绍如下:

● 单片机系统:利用ATmega16单片机与DS18B20温度传感器通信,通过对指定的DS18B20进行读取温度的操作,并将采集到的温度值通过串口发送到计算机。

● 外围电路:外围电路分两部分:串口电路部分(实现将采集到的温度值发送到计算机的功能)、DS18B20温度采集电路(实现采集环境温度的功能),在DS18B20的电路部分,我们并接两个DS18B20(如果没有条件一个DS18B20也可以)。

● 软件程序:编写软件,实现对指定DS18B20进行温度测量和串口发送数据功能。 通过本实例的学习,掌握以下内容:

● 理解DS18B20的特点、结构和原理和接口设计方法。 ● 掌握DS18B20的多点测温的基本原理和方法。 ● 掌握DS1820的ROM指令操作,以及操作ROM。

7.2.2 器件和原理

前面的实例中我们已经实现了利用DS18B20的进行温度测量,并且完成了对DS18B20的RAM区的读写操作,还实现了利用寄生电源对DS18B20的供电方式。

本实例中我们实现对并接在同一总线上的两个DS18B20的其中一个进行温度读取。 1、DS18B20的ROM操作指令

在前面利用DS18B20实现简单测温的例子中我们已经了解了DS18B20的相关ROM操作指令。

其中的“搜索ROM”指令可以让我们在不知道总线上连接了多少数目的DS18B20的情况下搜索出来总线上共连接了几个DS18B20,以及每个DS18B20的ROM序列号。 “匹配ROM”指令可以让我们对指定的某一个DS18B20进行操作。

“报警搜索ROM”指令可以实现对超过温度报警值的一个或数个DS18B20进行操作。 2、“搜索ROM”指令比较复杂,在此我们就不用了,等以后再研究,“报警搜索ROM”指令在实际应用中有不同的意义,我们也掠过不学。在这里我们重点“匹配ROM”指令。

如图7.3.1所示是利用“匹配ROM”指令实现对指定DS18B20的操作。其中的存在脉冲是DS18B20对复位信号发出的应答脉冲。在我们的程序中,在DS18B20初始化函数里面已经包含了复位脉冲和存在脉冲。

从图中可以看出,当需要对指定的DS18B20进行操作的时候,需要先对DS18B20进行复位初始化操作,然后发送“匹配ROM”指令,后面紧跟着就要发送指定DS18B20的ROM序列号,DS18B20对收到的ROM序列号进行比较,如果与自己的相同,则执行下面的指令,如果不同,则不再执行后面指令。

图7.3.1 对指定DS18B20进行操作的控制流程 7.2.3、电路连接

限于学习板的实际情况,在本实例中我们使用外接电源供电的方法。具体实现方法是:将学习板上的DS18B20焊掉(上一实例中焊接的上拉电阻保留)。用3根导线分别连接两个(1个也可以)DS18B20的3个引脚,把其中连接DS18B20的VCC和GND连接到学习板的电源和地线上,把连接DS18B20的DQ引脚的那根导线连接到单片机的PA2口。

至于电路的串口部分就不再说了。

1、程序功能

程序的功能是使用单片机的PA2口的实现对两个DS18B20的操作,然后将读出的指定的DS18B20的温度值通过串口发送到计算机。

2函数说明

本程序多个功能函数,分别是:

● 端口初始化函数,设置各端口的初始工作状态。 ● 串口通信相关函数:

void Usart_Init(void); //USART寄存器设置

void Usart_PutChar(unsigned char cTXData); //字节发送函数 void Usart_PutString(unsigned char *pcString); //字符串发送函数

本文来源:https://www.bwwdw.com/article/ktif.html

Top