如何利用DS18B20传感器通过PIC微控制器获得温度

描述

通常,LM35温度传感器与微控制器一起使用以测量温度,因为它便宜且易于获得。但是 LM35 给出了模拟值,我们需要使用 ADC(模数转换器)将它们转换为数字值。但今天我们使用DS18B20温度传感器,不需要ADC转换即可获得温度。在这里,我们将使用带有DS18B20的PIC微控制器来测量温度。

因此,在这里,我们使用微芯片的PIC16F877A微控制器单元构建具有以下规格的温度计。

它将显示从 -55 度到 +125 度的全温度范围。

仅当温度变化 + / - .2 度时,它才会显示温度。

所需组件:-

Pic16F877A – PDIP40 封装

面包板

皮基特-3

5V 适配器

液晶显示器 JHD162A

DS18b20 温度传感器

用于连接外围设备的电线。

4.7k 电阻器 – 2 个

10k锅

20mHz 晶体

2 个 33pF 陶瓷电容器

DS18B20温度传感器:

DS18B20是一款出色的传感器,可准确检测温度。该传感器提供 9 位至 12 位的温度检测分辨率。该传感器仅与一根导线通信,不需要任何ADC即可获取模拟温度并将其转换为数字温度。

传感器的规格是:-

测量温度范围为 -55°C 至 +125°C(-67°F 至 +257°F)

-10°C 至 +85°C 范围内精度为 ±0.5°C

可编程分辨率从 9 位到 12 位

无需外部组件

传感器采用1-Wire®接口

adc

如果我们查看数据表中的上述引脚排列图像,我们可以看到传感器看起来与 BC547 或 BC557 封装 TO-92 完全相同。第一个引脚是接地,第二个引脚是DQ或数据,第三个引脚是VCC。

以下是数据表中的电气规格,这是我们设计所需的。传感器的额定电源电压为+3.0V至+5.5V。它还需要上拉电源电压,该电压与上述电源电压相同。

adc

此外,对于 -10 摄氏度到 +10 摄氏度的范围,精度裕度为 +-0.5 摄氏度,全范围裕度的精度会发生变化,对于 -55 度到 +125 度范围,精度裕度为 +-2 度。

如果我们再次查看数据表,我们将看到传感器的连接规格。我们可以在需要两根电线(DATA 和 GND)的寄生电源模式下连接传感器,或者可以使用外部电源连接传感器,其中需要三根单独的电线。我们将使用第二种配置。

adc

由于我们现在熟悉传感器和连接相关区域的额定功率,我们现在可以专注于制作原理图。

电路图:-

adc

如果我们看到电路图,我们将看到:-

16x2字符LCD通过PIC16F877A微控制器连接,其中RB0,RB1,RB2连接到LCD引脚RS,R/W和E。RB4、RB5、RB6 和 RB7 通过 LCD 的 4 针 D4、D5、D6、D7 连接。液晶屏以4位模式或半字节模式连接。

一个 20MHz 晶体振荡器和两个 33pF 陶瓷电容器连接在 OSC1 和 OSC2 引脚上。它将为微控制器提供恒定的20Mhz时钟频率。

DS18B20也按照引脚配置连接,如前所述,采用4.7k上拉电阻连接。我已经在面包板上连接了所有这些。

如果您不熟悉 PIC 微控制器,请按照我们的 PIC 微控制器教程进行操作,说明 PIC 微控制器入门。

步骤或代码流:-

设置微控制器的配置,包括振荡器配置。

设置LCD的所需端口,包括TRIS寄存器。

使用ds18b20传感器的每个周期都以复位开始,因此我们将复位ds18b20并等待存在脉冲。

编写暂存器并将传感器的分辨率设置为 12 位。

跳过ROM读取,然后跳过复位脉冲。

提交转换温度命令。

从暂存器读取温度。

检查温度值是负值还是正值。

在 16x2 LCD 上打印温度。

等待温度变化 +/-.20 摄氏度。

adc

代码说明:

本教程末尾提供了此数字温度计的完整代码,并附有演示视频。您将需要一些头文件来运行该程序,可以从此处下载。

首先,我们需要在 pic 微控制器中设置配置位,然后从 void main 函数开始。

然后下面四行用于包括库头文件,lcd.h和ds18b20.h。 xc.h 用于微控制器头文件。

#include
#include
#include "supporting c files/ds18b20.h"
#include "supporting c files/lcd.h"
这些定义用于向温度传感器发送命令。这些命令列在传感器的数据表中。

#define skip_rom 0xCC
#define convert_temp 0x44
#define write_scratchpad 0x4E
#define resolution_12bit 0x7F
#define read_scratchpad 0xBE

adc

传感器数据表中的表 3 显示了使用宏发送相应命令的所有命令。

仅当温度变化 +/- .20 度时,温度才会显示在屏幕上。我们可以从这个temp_gap宏观上改变这个温差。通过更改此宏中的值,规范将更改。

另外两个浮点变量用于存储显示的温度数据,并用温差区分它们

#define temp_gap 20
float pre_val=0, aft_val=0;
.

在void main()函数中,lcd_init();是一个初始化LCD的函数。此 lcd_init() 函数是从 lcd.h 库中调用的。

TRIS 寄存器用于选择 I/O 引脚作为输入或输出。两个无符号短变量 TempL 和 TempH 用于存储来自温度传感器的 12 位分辨率数据。

void main(void) {
TRISD = 0xFF;
TRISA = 0x00;
TRISB = 0x00; 
//TRISDbits_t.TRISD6 = 1;
unsigned short TempL, TempH;
unsigned int t, t2;
float difference1=0, difference2=0; 
lcd_init();
让我们看看 while 循环,这里我们将 while(1) 循环分解成小块。

这些线用于检测温度传感器是否连接。

while(ow_reset()){
lcd_com(0x80);
lcd_puts ("Please Connect ");
lcd_com (0xC0);
lcd_puts("Temp-Sense Probe");
}
通过使用这段代码,我们初始化传感器并发送命令来转换温度。

lcd_puts (" ");
ow_reset(); 
write_byte(write_scratchpad);
write_byte(0);
write_byte(0);
write_byte(resolution_12bit); // 12bit resolution
ow_reset();
write_byte(skip_rom);
write_byte(convert_temp);
此代码用于将 12 位温度数据存储在两个无符号短变量中。

while (read_byte()==0xff);
__delay_ms(500);
ow_reset();
write_byte(skip_rom);
write_byte(read_scratchpad);
TempL = read_byte();
TempH = read_byte();
然后,如果您检查下面的完整代码,我们将创建if-else条件来找出温度符号是正数还是负数。

通过使用 If 语句代码,我们操作数据并查看温度是否为负,并确定温度变化是否在 +/- .20 度范围内。在其他地方,我们检查温度是否为正和温度变化检测。

从DS18B20温度传感器获取数据:

让我们看看1-Wire®接口的时差。我们正在使用20Mhz晶体。如果我们查看 ds18b20.c 文件,我们会看到

#define _XTAL_FREQ 20000000

此定义用于 XC8 编译器延迟例程。20Mhz设置为晶体频率。

我们制作了五个功能

ow_reset

read_bit

read_byte

write_bit

write_byte

1-Wire协议需要严格的时序相关插槽进行通信。在数据表中,我们将获得完美的时隙相关信息。®

adc

在下面的函数中,我们创建了确切的时间段。为保持和释放创建确切的延迟并控制相应传感器端口的TRIS位非常重要。

unsigned char ow_reset(void)
{
DQ_TRIS = 0; // Tris = 0 (output)
DQ = 0; // set pin# to low (0)
__delay_us(480); // 1 wire require time delay
DQ_TRIS = 1; // Tris = 1 (input)
__delay_us(60); // 1 wire require time delay

if (DQ == 0) // if there is a presence pluse
{
__delay_us(480);
return 0; // return 0 ( 1-wire is presence)
}
else
{
__delay_us(480);
return 1; // return 1 ( 1-wire is NOT presence)
}
} // 0=presence, 1 = no part

现在,根据以下读取和写入中使用的时隙描述,我们分别创建了读取和写入函数。

adc

unsigned char read_bit(void)
{
unsigned char i;
DQ_TRIS = 1;
DQ = 0; // pull DQ low to start timeslot
DQ_TRIS = 1;
DQ = 1; // then return high
for (i=0; i<3; i++); // delay 15us from start of timeslot
return(DQ); // return value of DQ line
}

void write_bit(char bitval)
{
DQ_TRIS = 0;
DQ = 0; // pull DQ low to start timeslot
if(bitval==1) DQ =1; // return DQ high if write 1
__delay_us(5); // hold value for remainder of timeslot
DQ_TRIS = 1;
DQ = 1;
}// Delay provides 16us per loop, plus 24us. Therefore delay(5) = 104us

这就是我们如何利用DS18B20传感器通过PIC微控制器获得温度。

/* 

* File:   main.c 

* Author: Sourav Gupta 



* Created on 11 April 2018, 17:57 

*/ 

 

/* 

* Configuration Related settings. Specific for microcontroller unit. 

*/ 

#pragma config FOSC = HS        // Oscillator Selection bits (HS oscillator) 

#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled) 

#pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled) 

#pragma config BOREN = ON       // Brown-out Reset Enable bit (BOR enabled) 

#pragma config LVP = OFF         // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3/PGM pin has PGM function; low-voltage programming enabled) 

#pragma config CPD = OFF        // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off) 

#pragma config WRT = OFF        // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control) 

#pragma config CP = OFF         // Flash Program Memory Code Protection bit (Code protection off) 

#define _XTAL_FREQ 20000000 

/* 

* System Header files inclusions 

*/ 

 

#include  

#include  

#include "supporting c files/ds18b20.h" 

#include "supporting c files/lcd.h" 

 

/* 

* Ds18b20 related definition 

*/ 

 

#define skip_rom 0xCC 

#define convert_temp 0x44  

#define write_scratchpad 0x4E 

#define resolution_12bit 0x7F 

#define read_scratchpad 0xBE 

 

/* 

* User interface related definitions 

*/ 

 

#define temp_gap  20 

 

float pre_val=0, aft_val=0; 

 

/* 

* Program flow related functions 

*/ 

 

void sw_delayms(unsigned int d); 

 

/* Main function / single Thread*/ 

void main(void) { 

   TRISD = 0xFF; 

   TRISA = 0x00; 

   TRISB = 0x00;            

   //TRISDbits_t.TRISD6 = 1; 

   unsigned short TempL, TempH; 

unsigned int t, t2; 

float difference1=0, difference2=0;         

   lcd_init();     

   while(1){ 

       float i=0; 

/* This is for presence detection of temp-sensing probe*/ 

while(ow_reset()){ 

lcd_com(0x80); 

lcd_puts ("Please Connect   "); 

lcd_com (0xC0); 

lcd_puts("Temp-Sense Probe"); 



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

 

       lcd_puts ("                "); 

ow_reset(); 

write_byte(write_scratchpad); 

   write_byte(0); 

write_byte(0); 

write_byte(resolution_12bit); // 12bit resolution 

ow_reset(); 

write_byte(skip_rom);  

write_byte(convert_temp);  

 

while (read_byte()==0xff); 

__delay_ms(500); 

ow_reset(); 

 

write_byte(skip_rom); 

write_byte(read_scratchpad); 

 

TempL = read_byte(); 

TempH = read_byte(); 

            

/*This is for Negative temperature*/ 

            

/*If result  (TempH [Bitwise and] 1000 0000) = not 0 

    *then this condition get true. 

case1. -0.5 degree value = 1111 1111. [1111 1111 & 1000 0000 = 1000 0000 which is not 0.] 

case2. -55 degree value = 1111 1100. [1111 1100 & 1000 0000 = 1000 0000 which is not 0] 

0x80 = 1000 0000 

Test Case -10.125  output 1111 1111 0101 1110*/    

                        

if((TempH & 0x80)!=0){    // If condition will execute as TempH = 1111 1111 & 1000 0000 = 1000 0000.  

t=TempH;// Store tempH value in t = 1111 1111  . 

       t<<=8;//after bitwise left shift 8 times value in t will be 1111 1111 0000 0000.   

       t=t|TempL;// t = 1111 1111 0000 0000 | 0101 1110 [ result t = 1111 1111 0101 1110]  

       t=t-1;//t = t-1 in this case t = 1111 1111 0101 1101. 

       t=~t;// t = 0000 0000 1010 0010. 

       t>>=4;// t = 0000 0000 0000 1010. 

t=t*100;// t = 10 * 100 = 1000. 

t2=TempL; //Store tempL value = 0101 1110. 

t2=t2-1;// t2= 0101 1101 

       t2=~t2;//t2 = 1010 0010 

       t2=t2&0x0f;// t2 = 1010 0010 | 0000 1111 = 0000 0010 

t2=t2 * 6.25; // 0000 00010 = 2 x 6.25 = 12.50 

i=((unsigned int)t ) + (unsigned int)t2; //put both value in one variable 1000 + 12.5 = 1012.5 

 

/*This if-else condition done because LCD would not refresh till temperature change -.20 or +.20 degree*/ 

 

pre_val=aft_val;   

            

difference1 = pre_val - i;  

difference2 = i - pre_val; 

 

if(difference1 > temp_gap || difference2 > temp_gap){ 

aft_val = i; 

lcd_com (0x80); 

lcd_puts ("Circuit Digest"); 

lcd_com (0xc0); 

lcd_puts("-"); 

lcd_bcd (5,aft_val); 

lcd_data(223); 

lcd_puts("C    "); 



else{ 

lcd_com (0x80); 

lcd_puts ("Circuit Digest"); 

lcd_com (0xc0); 

lcd_puts("-"); 

lcd_bcd (5,pre_val); 

lcd_data(223); 

lcd_puts("C    "); 

 

 





/*This is for positive Temperature*/ 

else { 

i=((unsigned int)TempH << 8 ) + (unsigned int)TempL; //put both value in one variable 

i = i * 6.25;   //calculations used from the table provided in the data sheet of ds18b20 

 

/*This if-else condition done because LCD would not refresh till temperature change -.20 or +.20 degree*/ 

pre_val=aft_val;   

 

difference1 = pre_val - i;  

difference2 = i - pre_val; 

 

if(difference1 > temp_gap || difference2 > temp_gap){ 

aft_val = i; 

lcd_com (0x80); 

lcd_puts ("Circuit Digest"); 

lcd_com (0xc0); 

lcd_bcd (5,aft_val); 

lcd_data(223); 

lcd_puts("C    "); 

 



else{ 

lcd_com (0x80); 

lcd_puts ("Circuit Digest"); 

lcd_com (0xc0); 

lcd_bcd (5,pre_val); 

lcd_data(223); 

lcd_puts("C    "); 

}        

       }             

   }          

   return; 



 

void sw_delayms(unsigned int d){ 

int x, y; 

for(x=0;x

for(y=0;y<=1275;y++); 

}

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分