DS18B20數字溫度傳感器接線友善,封裝成後可應用于多種場合,如管道式,螺紋式,磁鐵吸附式,不鏽鋼封裝式,型号多種多樣,有 LTM8877,LTM8874等等。主要根據應用場合的不同而改變其外觀。封裝後的DS18B20可用于電纜溝測溫,高爐水循環測溫,鍋爐測溫,機房測 溫,農業大棚測溫,潔淨室測溫,彈藥庫測溫等各種非極限溫度場合。耐磨耐碰,體積小,使用友善,封裝形式多樣,适用于各種狹小空間裝置數字測溫和控制領 域。
技術性能描述
1. 獨特的單線接口方式,DS18B20在與微處理器連接配接時僅需要一條口線即可實作微處理器與DS18B20的雙向通訊。
2. 測溫範圍 -55℃~+125℃,固有測溫分辨率0.5℃。
3. 支援多點組網功能,多個DS18B20可以并聯在唯一的三線上。
4. 工作電源: 3~5V/DC
5. 在使用中不需要任何外圍元件
6. 測量結果以9~12位數字量方式串行傳送
DS18B20 引腳功能: GND 電壓地 •DQ 單資料總線 •VDD 電源電壓 •NC 空引腳DS18B20 工作原理及應用
DS18B20 的溫度檢測與數字資料輸出全內建于一個晶片之上,進而抗幹擾力更強。其一個工作周期可分為兩個部分,即溫度檢測和資料處理。在講解其工作流程之前我們有必要了解 18B20的内部存儲器資源。18B20 共有三種形态的存儲器資源。它們分别是:
ROM 隻讀存儲器:
用于存放 DS18B20ID 編碼,其前 8 位是單線系列編碼(DS18B20 的編碼是19H) ,後面48 位是晶片唯一的序列号,最後 8位是以上 56的位的 CRC碼(備援校驗)。資料在出産時設定不由使用者更改。DS18B20 共 64 位 ROM。
RAM 資料暫存器:
用于内部計算和資料存取,資料在掉電後丢失,DS18B20 共9 個位元組 RAM,每個位元組為 8 位。第1、2 個位元組是溫度轉換後的資料值資訊,第 3、4 個位元組是使用者 EEPROM(常用于溫度報警值儲存)的鏡像。在上電複位時其值将被重新整理。第 5
個位元組則是使用者第 3 個 EEPROM的鏡像。第 6、7、8
個位元組為計數寄存器,是為了讓使用者得到更高的溫度分辨率而設計的,同樣也是内部溫度轉換、計算的暫存單元。第 9 個位元組為前 8個位元組的
CRC碼。EEPROM 非易失性記憶體,用于存放長期需要儲存的資料,上下限溫度報警值和校驗資料,
DS18B20共3位EEPROM,并在 RAM 都存在鏡像,以友善使用者操作。
控制器對 18B20 操作流程:
1、 複位:首先我們必須對 DS18B20 晶片進行複位,複位就是由控制器(單片機)給 DS18B20單總線至少 480uS 的低電平信号。當 18B20 接到此複位信号後則會在 15~60uS 後回發一個晶片的存在脈沖。
2、 存在脈沖:在複位電平結束之後,控制器應該将資料單總線拉高,以便于在 15~60uS 後接收存在脈沖,存在脈沖為一個 60~240uS 的低電平信号。至此,通信雙方已經達成了基本的協定,接下來将會是控制器與 18B20
間的資料通信。如果複位低電平的時間不足或是單總線的電路斷路都不會接到存在脈沖,在設計時要注意意外情況的處理。
3、 控制器發送 ROM 指令:雙方打完了招呼之後最要将進行交流了,ROM 指令共有 5條,每一個工作周期隻能發一條,ROM指令分别是讀 ROM 資料、指定比對晶片、跳躍 ROM、晶片搜尋、報警晶片搜尋。ROM 指令為 8 位長度,功能是對片内的 64位光刻
ROM進行操作。其主要目的是為了分辨一條總線上挂接的多個器件并作處理。誠然,單總線上可以同時挂接多個器件,并通過每個器件上所獨有的
ID号來差別,一般隻挂接單個 18B20晶片時可以跳過 ROM 指令(注意:此處指的跳過 ROM指令并非不發送 ROM
指令,而是用特有的一條“跳過指令” )
4、 控制器發送存儲器操作指令:在 ROM 指令發送給 18B20 之後,緊接着(不間斷)就是發送存儲器操作指令了。操作指令同樣為 8 位,共 6 條,存儲器操作指令分别是寫 RAM 資料、讀RAM 資料、将 RAM 資料複制到 EEPROM、溫度轉換、将
EEPROM中的報警值複制到 RAM、工作方式切換。存儲器操作指令的功能是指令 18B20 作什麼樣的工作,是晶片控制的關鍵。
5、 執行或資料讀寫:一個存儲器操作指令結束後則将進行指令執行或資料的讀寫,這個操作要視存儲器操作指令而定。如執行溫度轉換指令則控制器(單片機)必須等
待 18B20 執行其指令,一般轉換時間為 500uS。如執行資料讀寫指令則需要嚴格遵循 18B20 的讀寫時序來操作。
若要讀出目前的溫度資料我們需要執行兩次工作周期,第一個周期為複位、跳過 ROM 指令、執行溫度轉換存儲器操作指令、等待 500uS 溫度轉換時間。緊接着執行第二個周期為複位、跳過 ROM指令、執行讀 RAM 的存儲器操作指令、讀資料(最多為 9
個位元組,中途可停止,隻讀簡單溫度值則讀前 2 個位元組即可)。其它的操作流程也大同小異,在此不多介紹。
關于ds18b20的資料手冊網上資源較為豐富,這裡不再詳細介紹,下面是基于ARM-LINUX的驅動程式,在arm-gcc 編譯後測試通過。
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
#include <linux/errno.h>
#include <linux/cdev.h>
#include <linux/ioctl.h>
#include <linux/fcntl.h>
#include <linux/sched.h>
#include <linux/poll.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/mm.h>
#include <linux/spinlock.h>
#include <plat/map.h>
#include <asm/io.h>
#include <asm/delay.h>
#include <asm/memory.h>
#include <asm/uaccess.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <mach/regs-gpio.h>
#include <mach/map.h>
MODULE_LICENSE("GPL");
#define GPHCON (*(volatile unsigned int *)S3C2410_GPHCON)
#define GPHDAT (*(volatile unsigned int *)S3C2410_GPHDAT)
#define GPHUP (*(volatile unsigned int *)S3C2410_GPHUP)
static int ds18b20_major = 230; /*靜态申請裝置号*/
struct cdev cdev;
struct class *my_class;
spinlock_t lock;
dev_t dev = 0;
int number_of_devices = 1;
/*配置為輸入模式*/
void set_conIN(void)
{
GPHCON &= ~(1<<19);
GPHCON &= ~(1<<18);
}
/*配置為輸出模式*/
void set_conOUT(void)
{
GPHCON |= (1<<18);
GPHCON &= ~(1<<19);
}
/*引腳置位*/
void set_data(int i)
{
if( i == 0 ){
GPHDAT &= ~(1<<9);
}else if( i == 1 ){
GPHDAT |= (1<<9);
}
}
/*複位ds18b20*/
unsigned int reset_ds18b20(void)
{
unsigned int retValue;
set_conOUT();
set_data(1);
__udelay(1);
set_data(0);
__udelay(600);
set_data(1);
__udelay(20);
set_conIN();
__udelay(100);
/*稍做延時後 如果x=0則初始化成功
x=1則初始化失*/
retValue = (GPHDAT >> 9) & 0x01;
printk("init is %d\n",retValue);
return retValue;
}
/*讀取一位溫度*/
unsigned int read_bit(void)
{
spin_lock(&lock);
set_conOUT();
//set_data(1);
//__udelay(2);
set_data(0);
__udelay(2);
set_conIN();
__udelay(1);
spin_unlock(&lock);
return ((GPHDAT >> 9) & 0x01);
}
/*寫一位指令*/
void write_bit(char bitValue)
{
spin_lock(&lock);
set_conOUT();
set_data(0);
__udelay(15);
if( bitValue == 1 ){
set_data(1);
}else{
set_data(0);
}
spin_unlock(&lock);
__udelay(45);
set_conIN();
__udelay(2);
}
/*寫指令*/
void write_cmd(char cmd)
{
unsigned char i;
unsigned char temp;
for(i=0; i<8;i++){
temp = cmd>>i;
temp &= 0x01;
write_bit(temp);
}
//__udelay(10);
}
/*打開裝置*/
static int ds18b20_open(struct inode *inode,struct file *filp)
{
printk (KERN_INFO "HEY! device opened\n");
//GPHUP &= ~(1<<9);
GPHUP |= (1<<9);
spin_lock_init(&lock);
return 0;
}
/*讀取資料*/
static int ds18b20_read(struct file *filp, char *buffer, size_t count, loff_t *ppos)
{
char lowValue=0,highValue=0;
unsigned int i;
//float value;
if(reset_ds18b20()){
printk("init error\n");
}
__udelay(400);
set_conOUT();
set_data(1);
write_cmd(0xCC);
write_cmd(0x44);
__udelay(100000);
if(reset_ds18b20()){
printk("init error\n");
}
__udelay(400);
set_conOUT();
set_data(1);
write_cmd(0xcc);
write_cmd(0xBE);
/*讀取溫度轉化數值*/
for(i=0; i<8; i++){
if( read_bit() ){
lowValue |= (0x01<<i);
}
__udelay(62);
}
printk("lowValue is %d\n",lowValue);
for(i=0; i<8; i++){
if( read_bit() ){
highValue |= (0x01<<i);
}
__udelay(62);
}
printk("highValue is %d\n",highValue);
#if 0
i = highValue;
i <<= 8;
i = i|lowValue;
value = i*0.0625;
printk("kernel is %d\n",value);
#endif
highValue <<= 4;
highValue |= ((lowValue&0xf0)>>4) ;
/*拷貝核心資料到使用者空間*/
copy_to_user(buffer, &highValue, sizeof(highValue));
return 0;
}
/*寫指令,在此置空*/
static int ds18b20_write(struct file *file, const char *buffer, size_t count, loff_t * ppos)
{
return 0;
}
static int ds18b20_release(struct inode *inode,struct file *filp)
{
printk (KERN_INFO "device closed\n");
return 0;
}
static int ds18b20_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
return 0;
}
struct file_operations ds18b20_fops ={
.owner = THIS_MODULE,
.open = ds18b20_open,
.read = ds18b20_read,
.write = ds18b20_write,
.ioctl = ds18b20_ioctl,
.release = ds18b20_release,
};
static void ds18b20_setup_cdev(void)
{
int error,devno = MKDEV(ds18b20_major,0);
cdev_init(&cdev,&ds18b20_fops);
cdev.owner = THIS_MODULE;
cdev.ops = &ds18b20_fops;
error = cdev_add(&cdev,devno,1);
if( error )
printk(KERN_INFO"Error %d adding ds18b20 %d\n",error,0);
my_class = class_create(THIS_MODULE,"my_class");
if(IS_ERR(my_class))
{
printk("Err: failed in creating class.\n");
return;
}
device_create(my_class,NULL,devno,NULL,"ds18b20");
}
/*注冊裝置*/
static int ds18b20_init(void)
{
int result;
dev = MKDEV(ds18b20_major,0);
if(ds18b20_major)
result = register_chrdev_region(dev,1,"ds18b20");
else{
result = alloc_chrdev_region(&dev,0,1,"ds18b20");
ds18b20_major=MAJOR(dev);
}
if( result < 0 ){
printk(KERN_WARNING"ds18b20:unable to get major %d\n",ds18b20_major);
return result;
}
if(ds18b20_major == 0 )
ds18b20_major = result;
ds18b20_setup_cdev();
printk("ds18b20 initialized.\n");
return 0;
}
static void __exit ds18b20_exit(void)
{
dev_t devno = MKDEV (ds18b20_major, 0);
device_destroy(my_class,devno);
class_destroy(my_class);
cdev_del (&cdev);
unregister_chrdev_region (devno, number_of_devices);
printk("ds18b20_major=%d\n",ds18b20_major);
printk("ds18b20 device uninstalled\n");
}
module_init(ds18b20_init);
module_exit(ds18b20_exit);