《嵌入式硬件(四):温度传感器DS1820》
一、DS1820的引脚
DS1820单总线数字温度计:异步串行半双工
特性:
1)独特的单线接口,只需 1 个接口引脚即可通信
2)多点(multidrop)能力使分布式温度检测应用得以简化
3)不需要外部元件
4)可用数据线供电
5)不需备份电源
6)测量范围从 - 55℃至 + 125℃,增量值为 0.5℃。等效的华氏温度范围是 - 67°F 至 257°F,增量值为 0.9°F
7)以 9 位数字值方式读出温度
8)在 1 秒(典型值)内把温度变换为数字
9)用户可定义的,非易失性的温度告警设置
10)告警搜索命令识别和寻址温度在编定的极限之外的器件(温度告警情况)
应用范围包括恒温控制,工业系统,消费类产品,温度计或任何热敏系统
51单片机和DS1820是线与关系,数据接受方需要释放总线->电平的高低由对方决定
上拉电阻通常在4.7k~10k,双方在释放总线时,保证线是高电平
二、ROM操作命令
Read ROM (读 ROM) [33h]:允许总线主机读 DS1820 的 8 位产品系列编码、唯一的 48 位序列号,以及 8 位的 CRC。仅能在总线上仅有一个 DS1820 时使用;若存在多个从属器件,所有从片同时发送会发生数据冲突(漏极开路产生 “线与” 结果)。
Match ROM (“符合” ROM) [55h]:命令后紧跟 64 位 ROM 数据序列,允许总线主机对多点总线上特定的 DS1820 寻址。只有与 64 位 ROM 序列严格相符的 DS1820,才会对后继存贮器操作命令响应;不符的从片会等待复位脉冲。总线上有单个或多个器件时都可使用。
Skip ROM (“跳过” ROM) [0Ch]:在单点总线系统中,允许总线主机不提供 64 位 ROM 编码就访问存储器操作,以此节省时间。若总线上有多个从属器件,且在该命令后发读命令,多个从片同时发数据会引发总线数据冲突(漏极开路下拉产生 “线与” 效果)。
Search ROM (搜索 ROM) [F0h]:系统刚工作时,总线主机可能不清楚单线总线上的器件个数或 64 位 ROM 编码。此命令允许主机用 “消去”(elimination) 处理,识别总线上所有从片的 64 位 ROM 编码。
Alarm Search (告警搜索) [ECh]:流程与 “搜索 ROM” 命令相同,但仅当 DS1820 最近一次温度测量出现告警(温度高于 TH 或低于 TL)时,才会对此命令响应。DS1820 上电后,告警条件会保持,直到温度测量显示非告警值,或修改 TH/TL 设置使测量值回到允许范围;EEPROM 内的触发器值用于告警。
三、DS1820的寄存器
- 读暂存存储器(Read Scratchpad)[BEh]:读取暂存存储器内容,从字节 0 开始,直到字节 8(CRC);若并非所有位置都可读,主机可随时发复位中止读操作。
- 复制暂存存储器(Copy Scratchpad)[48h]:将暂存存储器内容复制到 DS1820 的 E² 存储器,把温度触发器字节存入非易失性存储器;若总线主机发此命令后读时间片,DS1820 在复制时总线输出 “0”,完成后输出 “1”;若为寄生电源供电,主机发命令后需立即强制上拉至少 10ms。
- 温度变换(Convert T)[44h]:启动温度变换,无需额外数据;若总线主机发此命令后读时间片,DS1820 变换时总线输出 “0”,完成后输出 “1”;若为寄生电源供电,主机发命令后需立即强制上拉至少 2 秒。
- 重新调出 E2(Recall E2)[B8h]:把 E² 中温度触发器的值调回暂存存储器(器件上电时也会自动执行该操作,所以上电后暂存存储器就有有效数据);发此命令后,第一个读数据时间片,器件输出 “0” 表示 “忙”,“1” 表示 “准备就绪”。
- 读电源(Read Power Supply)[B4h]:发此命令后,第一个读出数据的时间片,器件会给出电源方式信号:“0” 表示寄生电源供电,“1” 表示外部电源供电。
四、DS1820的时序图
1.初始化(检测芯片是否能用)
方法:先给51单片机低电平,如果可以检测到一个低电平,一个高电平,芯片就是好的
#include <reg52.h>
#include <intrins.h>#define DS18B20_SET (P3 |= (1 << 7)) //拉高
#define DS18B20_CLEAR (P3 &= ~(1 << 7)) //拉低
#define DS18B20_TST ((P3 & (1 << 7)) != 0) //判断 高电平void Delay10us(unsigned int n) //@12.000MHz
{unsigned char data i;_nop_();_nop_();_nop_();i = 2 * n;while (--i){_nop_();}
}int reset_ds18b20(void)
{int t = 0;DS18B20_CLEAR;Delay10us(50);DS18B20_SET;Delay10us(2);while(DS18B20_TST && t < 25){Delay10us(1);++t;}if(t >= 25){return 0;}t = 0;while(!DS18B20_TST && t < 20){Delay10us(1);++t;}if(t >= 20){return 0;}return 1;
}int main(void)
{int t = reset_ds18b20();if(1 == t){P2 = 0;}else{P2 = 0xFF;}while(1){}return 0;
}
温度读取
main.c
#include <reg52.h>
#include <intrins.h>
#include <stdio.h>
#include <string.h>
#include "uart.h"
#include "delay.h"
#include "ds18b20.h"int main(void)
{ xdata char s[24];init_uart();while(1){float f;f = get_temperatuer();sprintf(s, "%f", f);send_buffer(s, strlen(s));}return 0;
}
delay.c
#include "delay.h"
#include <intrins.h>
void delay(unsigned int n)//0~65526
{while(n--);
}void Delay10us(unsigned int n) //@12.000MHz
{unsigned char data i;_nop_();_nop_();_nop_();i = 2 * n;while (--i){_nop_();}
}void delay_1ms(unsigned int n)
{while(n--){Delay10us(100);}
}
ds18b20.c
#include <reg52.h>
#include <intrins.h>
#include "delay.h"
#include "ds18b20.h"static int reset_ds18b20(void)
{int t;DS18B20_CLEAR;Delay10us(70);DS18B20_SET;Delay10us(4);t = 0;while(DS18B20_TST && t < 30){Delay10us(1);++t;}if(t >= 30){return 0;}t = 0;while(!DS18B20_TST && t < 30){Delay10us(1);++t;}if(t >= 30){return 0;}return 1;
}void ds18b20_write(unsigned char n) //0x01010 110 & 0000 0001
{int i;for(i = 0;i < 8;++i){if(n & 0x01) // 1{DS18B20_CLEAR;_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();DS18B20_SET;Delay10us(5); }else{DS18B20_CLEAR;Delay10us(6);DS18B20_SET;}n >>= 1; }
}unsigned char ds18b20_read(void)
{unsigned char ret = 0;int i;for(i = 0;i < 8;++i){DS18B20_CLEAR;_nop_();_nop_();DS18B20_SET;_nop_();_nop_();_nop_();_nop_();if(DS18B20_TST){ret |= 1 << i; }Delay10us(5); }return ret;
}float get_temperatuer(void)
{unsigned char tl, th;short t;reset_ds18b20();ds18b20_write(0xCC);ds18b20_write(0x44);delay_1ms(750);reset_ds18b20();ds18b20_write(0xCC);ds18b20_write(0xBE);tl = ds18b20_read();th = ds18b20_read();t = tl;t |= th << 8;return t * 0.0625;
}
uart.c
#include "uart.h"
#include <reg52.h>xdata char rcv_buffer[64] = {0};
int pos = 0;void init_uart(void)
{unsigned char t;t = SCON;t &= ~(3 << 6);t |= (1 << 6) | (1 << 4);SCON = t;PCON |= (1 << 7);IE |= (1 << 7) | (1 << 4);t = TMOD;t &= ~(3 << 4);t |= (2 << 4);t &= ~(3 << 6);TMOD = t;TH1 = 204; //12MHzTL1 = 204;TCON |= (1 << 6);
}void uart_handler(void) interrupt 4
{if((SCON & (1 << 0)) != 0){rcv_buffer[pos++] = SBUF;SCON &= ~(1 << 0);}
}void send_char(char ch)
{SBUF = ch;while((SCON & (1 << 1)) == 0);SCON &= ~(1 << 1);
}void send_buffer(const char *p, int len)
{while(len--){send_char(*p++);}
}