返回信息流将温度信息转化为电信号的器件,称为温度传感器(废话)。
最廉价最经典的温度传感器,要数DS18B20了。其手册参见附件。
附件(219KB) ds18B20.pdf
18b20之所以广受欢迎,是因为其管脚简洁,使用方便。
1: 技术性能描述
1.1 独特的单线接口方式,DS18B20在与微处理器连接时仅需要一条口线即可实现微处理器与DS18B20的双向通讯。
1.2 测温范围 -55℃~+125℃,固有测温分辨率0.5℃。
1.3 支持多点组网功能,多个DS18B20可以并联在唯一的三线上,实现多点测温
1.4 工作电源: 3~5V/DC
1.5 在使用中不需要任何外围元件
1.6 测量结果以9~12位数字量方式串行传送
2:特点
2.1 独特的一线接口,只需要一条口线通信,无需外部元件,简化了分布式温度传感应用;
2.2 可用数据总线供电,电压范围为3.0 V至5.5 V,无需备用电源;
2.3 测量温度范围为-55`C至+125℃ 。华氏相当于是-67`F到257华氏度 -10`C至+85`C范围内精度为±0.5`C
2.4 温度传感器可编程的分辨率为9~12位 温度转换为12位数字格式最大值为750毫秒 用户可定义的非易失性温度报警设置 应用范围包括恒温控制,工业系统,消费电子产品温度计,或任何热敏感系统
2.5 描述该DS18B20的数字温度计提供9至12位(可编程设备温度读数。信息被发送到/从DS18B20 通过1线接口,所以中央微处理器(例如单片机)与DS18B20只有一个一条口线连接。为读写以及温度转换可以从数据线本身获得能量,不需要外接电源。 因为每一个DS18B20的包含一个独特的序号,多个ds18b20s可以同时存在于一条总线。这使得温度传感器放置在许多不同的地方。它的用途很多,包括空调环境控制,感测建筑物内温设备或机器,并进行过程监测和控制。
3:时序控制
参考1楼。
4:使用技巧
附件(107.8KB)
5:参考代码
本楼代码来自互联网,没有亲自检验,请酌情参考。
为了完成18b20的时序控制,程序中往往会有专门的延迟函数。时序控制是靠执行延迟函数的次数来实现的。
5.1 该程序演示单总线数字测温芯片DS18B20的单片应用。
所用头文件没有找,看名称也差不多知道是干什么的了。核心算法都在程序文件中
[quote]
//例Y15.1
//该程序演示单总线数字测温芯片DS18B20的单片应用。
//在实验板上单总线网络由P1.0构成,标配时该网络中只有1片DS18B20,所以不需要识别器件的ID。
//DS18B20给出的测温数据为16位补码,包括符号位在内的有效数据一共12位,其余4位为符号扩展位,
//在12位有效数据中,最高位为符号,此外,高端7位为整数,低端4位为小数。
//程序每秒测一次温度,测试时先将数据转移到DS18B20中的高速缓冲器(9字节),然后连续读取。
//高速缓冲器中9字节读取顺序依次是:测温数据L/测温数据H/报警阈值H/报警阈值L/测温精度配置/保留/保留/保留//CRC娇艳数据。
//程序在数码管上显示1位符号(正号时不显示)和5位温度数据(含两位小数),并消隐它的前导0,
//在L16~L1上显示从DS18B20中读出的16位二进制补码原始测温数据,LED点亮时表示数据为1。
//Program Size: data=26.0 xdata=0 code=553
#include <reg51.h>
#include <absacc.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define ON 0
#define OFF 1
#define skiprom_cmd1820(); wr_byte1820(0xcc); //跳过ROM操作(芯片识别)
#define convert_cmd1820(); wr_byte1820(0x44); //启动测温转换
#define wrscrat_cmd1820(); wr_byte1820(0x4e); //拟写高速暂存
#define rdscrat_cmd1820(); wr_byte1820(0xbe); //拟读高速暂存
#define copyscrat_cmd1820(); wr_byte1820(0x48); //将高速暂存复制到EERAM保存
sbit DQ_1820=P1^0; //18B20的DQ端
sbit DAT_164=P3^4; //74HC164的串入端
sbit CLK_164=P3^5; //74HC164的时钟端
uchar code seg[]={ //七段码表
0x3f,0x06,0x5b,0x4f,0x66, //0~4
0x6d,0x7d,0x07,0x7f,0x6f, //5~9
0x77,0x7c,0x39,0x5e,0x79, //A~E
0x71,0x40,0x46,0x00,0x76, //F,-,-1,全灭,H
0xbf,0x86,0xdb,0xcf,0xe6, //0.~4.
0xed,0xfd,0x87,0xff,0xef //5.~9.
};
uchar disbuf[6]; //显示缓冲区
union //利用该结构来分离测温数据中的高/低8位
{ int i;
uchar c[2];
}temp; //拟存温度数据
void delay_10us(uchar n) //10微秒级延时
{ do
{ _nop_();
_nop_();
_nop_();
_nop_();
_nop_();
}while(--n);
}
void delay_ms(uint n) //毫秒级延时
{ do delay_10us(131);
while(--n);
}
void sendchar(uchar ch) //向数码管送1位显示数码
{ uchar i;
for(i=0;i<8;i++)
{ DAT_164=ch&0x01;
CLK_164=0;
CLK_164=1;
ch>>=1;
}
}
void display() //将缓冲区数据送数码管显示
{ uchar i;
for(i=0;i<6;i++) sendchar(seg[disbuf[i]]);
}
void res1820_to_disbuf() //处理转换结果并送显示缓冲区
{ uchar i;
uchar tint; //用它处理温度数据的整数部分
uint tdec; //用它处理温度数据的小数部分
disbuf[0]=18; //正数时显示空格
if(temp.i<0)
{ disbuf[0]=16; //显示"-"
temp.i=-temp.i; //负数取绝对值
}
tint=temp.i>>4; //右移4位后得8位整数(3位十进制)
disbuf[1]=tint/100; //取百位上数据
disbuf[2]=tint/10%10; //取十位上数据
disbuf[3]=tint%10+20; //取个位上数据并加小数点
i=1; //消隐数码显示前导0
while(disbuf[i]==0) disbuf[i++]=18;
tdec=temp.c[1]&0x0f; //得4位小数,最低位权重=0.0625
tdec=tdec*625+50; //小数作整数处理避免浮点运算(保留2位小数)
disbuf[4]=tdec/1000; //取十分之一位数据
disbuf[5]=tdec/100%10; //取百分之一位数据
}
void reset_1820() //复位18B20
{ DQ_1820=0;
delay_10us(60); //延时约500uS(要求>480us)
DQ_1820=1; //主机上拉DQ_1820
delay_10us(7); //延时约60uS
while(!DQ_1820); //等18B20送出0
}
void wr_byte1820(uchar dat) //写18B20
{ uchar i;
for(i=0;i<8;i++) //依次发送8位数据
{ DQ_1820=0;
delay_10us(2); //延时约20uS
DQ_1820=dat&0x01;
dat>>=1;
delay_10us(7); //延时约60uS
DQ_1820=1; //主机上拉DQ_1820
}
}
uchar rd_byte1820()
{ uchar i,dat=0;
for(i=0;i<8;i++) //依次接收8位数据
{ dat>>=1;
DQ_1820=0; //主机下拉DQ_1820
DQ_1820=1; //主机上拉DQ_1820
if(DQ_1820) dat|=0x80;
delay_10us(7); //满足延时要求58us
}
return dat;
}
void main()
{ uchar i;
uchar scratbuf[9]; //存从18B20高速缓存中读取的9字节数据
delay_ms(500); //等待系统充分复位
reset_1820(); //复位18B20
skiprom_cmd1820(); //跳过ROM操作(不识别芯片)
wrscrat_cmd1820(); //拟写高速暂存,下跟3个数据字节
wr_byte1820(0xfe); //写数据1:上限报警门槛TH=0xfe
wr_byte1820(0x05); //写数据2:下限报警门槛TL=0x05
wr_byte1820(0x7f); //写数据3:分辨率=12位
reset_1820(); //复位18b20
skiprom_cmd1820(); //跳过ROM操作
copyscrat_cmd1820(); //高速暂存送EERAM保存
delay_ms(11); //等操作完成,要求延时>10ms
while(1)
{ reset_1820(); //复位18b20
skiprom_cmd1820(); //跳过ROM操作
convert_cmd1820(); //启动测温
delay_ms(750); //延时等转换结束,12位精度约需750ms
reset_1820(); //复位18B20
skiprom_cmd1820(); //跳过ROM操作
rdscrat_cmd1820(); //拟读高速暂存
for(i=0;i<9;i++) scratbuf[i]=rd_byte1820(); //连读高速暂存器9字节暂存到scratbuf
/* 也可只读2字节的测温数据,并强迫读过程中止
for(i=0;i<2;i++) scratbuf[0]=rd_byte1820(); //读18B20测温2字节
reset_1820(); //复位18B20,强迫读过程中止
*/
XBYTE[0x2000]=temp.c[1]=scratbuf[0]; //在L1~L8上显示原始二进制数据低字节
XBYTE[0x4000]=temp.c[0]=scratbuf[1]; //在L9~L16上显示原始二进制数据高字节
res1820_to_disbuf(); //数据送显示缓冲区数据格式:(-)xxx.xx
display(); //数据显示
delay_ms(1000); //延时1S再测
}
}
[/quote]
5.2 ATmega16L学习板18B20测试程序
[quote]
/********************************************************************
ATmega16L学习板18B20测试程序
晶振频率: 8MHz
编译: ICCAVR 6.31
编写: hanzhaowei@2911.net
********************************************************************/
#include <iom16v.h>
#include <macros.h>
#include "../include/board.h"
/*===================================================================
// 函数功能: DS18B20数据校验函数
// 形参: void
// 返回: unsigned char 校验结果
// 编写: 2004/8/25
// 备注: CRC公式为:CRC = X^8 + X^5 + X^4 + 1
===================================================================*/
unsigned char crccheck(unsigned char *p,unsigned char len)
{
unsigned char bit0,cbit,r,temp,i,j,byte;
temp = 0;
for(j = 0; j < len; j++)
{
byte = p[j];
for(i = 0; i < 8; i++)
{
cbit = temp & 0x01;
bit0 = byte&0x01;
temp >>= 1;
r = cbit ^ bit0;
if(r == 1)
temp ^= 0x8c;
byte >>= 1;
}
}
return temp;
}
/*===================================================================
// 函数功能: us延时函数
// 形参: void
// 返回: void
// 编写: 2004/8/25
===================================================================*/
void delay_us(unsigned int time)
{
do
{
time--;
}
while (time>1);
}
/*===================================================================
// 函数功能: 判断总线应答
// 形参: void
// 返回: unsigned char true为应答
// 编写: 2004/8/25
===================================================================*/
unsigned char ds1820_ack(void)
{
unsigned char ack;
DDRC |= DQ;
PORTC &= ~DQ;
delay_us(500); // reset
PORTC |= DQ;
DDRC &= ~DQ;
delay_us(45);
ack = DQ & PINC;
delay_us(500); // host receive
if(ack)
return true;
else
return false;
}
/*===================================================================
// 函数功能: 从 1-wire 总线上读取一个字节
// 形参: void
// 返回: unsigned char 读到的值
// 编写: 2004/8/25
===================================================================*/
unsigned char read_byte(void)
{
unsigned char i;
unsigned char value = 0;
for(i = 8; i > 0; i--)
{
value >>= 1; // low bit first
DDRC |= DQ;
PORTC &= ~DQ; // pull DQ low to start timeslot
delay_us(3);
PORTC |= DQ;
DDRC &= ~DQ; // release bus
delay_us(10);
if(DQ & PINC)
value|=0x80;
delay_us(100);
DDRC |= DQ;
delay_us(5); // time interval
}
return(value);
}
/*===================================================================
// 函数功能: 向 1-WIRE 总线上写一个字节
// 形参: value 写到总线上的值
// 返回: void
// 编写: 2004/8/25
===================================================================*/
void write_byte(unsigned char value)
{
unsigned char i;
DDRC |= DQ;
for(i = 8; i > 0; i--)
{
if(value & 0x01)
{
PORTC &= ~DQ; // pull DQ low to start timeslot
delay_us(10);
PORTC |= DQ;
delay_us(100);
}
else
{
PORTC &= ~DQ; // pull DQ low to start timeslot
delay_us(100);
PORTC |= DQ;
delay_us(10);
}
value >>= 1;
}
}
/*===================================================================
// 函数功能: 读取温度
// 形参: *temperature 温度存储空间
// 返回: unsigned char true为有效
// 编写: 2004/8/25
===================================================================*/
unsigned char Read_Temperature(unsigned int *temperature)
{
unsigned char i;
union{
unsigned char c[2];
unsigned int x;
}temp;
unsigned char temporary[9];
ds1820_ack();
write_byte(0xCC); // Skip ROM
write_byte(0x44); // Start Conversion
for(i = 0; i < 16; i++)
delay_us(50000);
ds1820_ack();
write_byte(0xCC); // Skip ROM
write_byte(0xBE); // Read Scratch Pad
for(i = 0; i < 9; i++)
temporary[i] = read_byte();
temp.c[0] = temporary[0];
temp.c[1] = temporary[1];
if(crccheck(temporary,9))
return false;
else
{
*temperature = temp.x;
return true;
}
}
/*===================================================================
// 函数功能: 读取Rom Code
// 形参: *temp DS18B20的Rom Code存储空间
// 返回: unsigned char true为有效
// 编写: 2004/8/25
===================================================================*/
unsigned char Read_RomCode(unsigned char *temp)
{
ds1820_ack();
write_byte(0x33);
temp[0] = read_byte();
temp[1] = read_byte();
temp[2] = read_byte();
temp[3] = read_byte();
temp[4] = read_byte();
temp[5] = read_byte();
temp[6] = read_byte();
temp[7] = read_byte();
if(crccheck(temp,8))
return false;
else
return true;
}
/*===================================================================
// 函数功能: 匹配DS18B20
// 形参: *p DS18B20的Rom Code
// 返回: void
// 编写: 2004/8/25
===================================================================*/
void ds1820_match(unsigned char *p)
{
unsigned char i;
ds1820_ack();
write_byte(0x55);
for(i=0;i<8;i++)
write_byte(p[i]);
}
[/quote]
5.3 61下的ds18b20测温程序
[quote]
//========================================================
// 文件名称: DS18B20.c
// 功能描述: DS18B20的相关操作,通过用户接口函数取得函数值
// 维护记录: 2005-11-22 v1.0
//========================================================
#include "DS18B20.h"
#include "SPCE061A.h"
//========================================================
// 语法格式: void Delay(unsigned int uiTime)
// 实现功能: 延时,在调用Delay(1)时,延时时间小于1us
// 参数: uiTime
// 返回值: 无
//========================================================
void Delay(unsigned int uiTime)
{
while(uiTime > 0)
{
uiTime -= 1;
}
}
//========================================================
// 语法格式: void Set_DQ(int Dir)
// 实现功能: 改变IOB15口的状态
// 参数: Dir,1:IOB15输出1;0:IOB15悬浮输入
// 返回值: 无
//========================================================
void Set_DQ(int Dir)
{
if(Dir > 0)
*P_IOB_Dir |= 0x8000;
else
*P_IOB_Dir &= 0x7fff;
*P_IOB_Buffer |= 0x8000;
}
//========================================================
// 语法格式: void Clr_DQ(int Dir)
// 实现功能: 改变IOA15口的状态
// 参数: Dir,1:IOB15输出0;0:IOB15悬浮输入
// 返回值: 无
//========================================================
void Clr_DQ(int Dir)
{
if(Dir > 0)
*P_IOB_Dir |= 0x8000;
else
*P_IOB_Dir &= 0x7fff;
*P_IOB_Buffer &= 0x7fff;
}
//========================================================
// 语法格式: unsigned int Read_DQ(void)
// 实现功能: 读取DQ的值
// 参数: 无
// 返回值: DQ的值
//========================================================
unsigned int Read_DQ(void)
{
unsigned int uiTemp;
uiTemp = 0;
if((*P_IOB_Data & 0x8000) > 0)
uiTemp = 1;
return(uiTemp);
}
//========================================================
// 语法格式: unsigned int Read_18B20_Byte(void)
// 实现功能: 读取18B20的值
// 参数: 无
// 返回值: 18B20的值
//========================================================
unsigned int Read_18B20_Byte(void)
{
int i;
unsigned int Data;
Data = 0;
for(i=0;i<8;i++)
{
Set_DQ(1);
Delay(1);
Clr_DQ(1);
Delay(2);
Set_DQ(0); //切为输入
Data = Data >> 1;
if(Read_DQ()>0)
Data |= 0x0080;
Delay(31);
}
return(Data);
}
//========================================================
// 语法格式: void Write_18B20_Byte(unsigned int Data)
// 实现功能: 写18B20
// 参数: 要写的字节
// 返回值: 无
//========================================================
void Write_18B20_Byte(unsigned int Data)
{
int i;
Set_DQ(1);
Delay(1);
for(i=0;i<8;i++)
{
Clr_DQ(1);
Delay(1);
if((Data&0x0001)>0)
Set_DQ(1);
Data = Data >> 1;
Delay(31);
Set_DQ(1);
Delay(1);
}
}
//========================================================
// 语法格式: int Init_18B20(void)
// 实现功能: 初始化18B20
// 参数: 要写的字节
// 返回值: 无
//========================================================
int Init_18B20(void)
{
int flag;
Set_DQ(1);
Delay(1);
Clr_DQ(1);
Delay(250);
Set_DQ(0);
Delay(31);
if(Read_DQ()>0)
flag = 1;
else
{
flag = 0;
Delay(220);
}
Set_DQ(1);
return(flag);
}
//========================================================
// 语法格式: unsigned int Read_Temp(void)
// 实现功能: 读取温度
// 参数: 无
// 返回值: 温度值
//========================================================
unsigned int Read_Temp(void)
{
int i;
unsigned int uiT;
unsigned int Data[10];
Set_DQ(1);
while(Init_18B20()>0)
*P_Watchdog_Clear = 0x0001;
Delay(40);
Write_18B20_Byte(0xcc);
Write_18B20_Byte(0x44);
for(i=0;i<26;i++)
Delay(15000); //长时间延时
while(Init_18B20()>0)
*P_Watchdog_Clear = 0x0001;;
Write_18B20_Byte(0xcc);
Write_18B20_Byte(0xbe);
for(i=0;i<8;i++) //数据读取
Data[i] = Read_18B20_Byte();
i = Data[1]; //温度的高字节
i = i << 8;
uiT = Data[0]; //温度的低字节
uiT |= i; //高低字节组和,有效位数11位
Init_18B20();
return uiT;
}
// .h文件
#ifndef __DS18B20_h__
#define __DS18B20_h__
// write your header here
void Delay(unsigned int);
void Set_DQ(int);
void Clr_DQ(int);
unsigned int Read_DQ(void);
unsigned int Read_18B20_Byte(void);
void Write_18B20_Byte(unsigned int);
int Init_18B20(void);
unsigned int Read_Temp(void);
#endif
[/quote]
5.4 汇编语言实现18B10温度测量+LCD1602显示温度
好多人呼唤汇编,那就来一个吧。
[quote]
;18B10温度测量+LCD1602显示温度
;实战目的
;1、学习18B20单总线温度传感器的使用。
;2、学习LCD的使用。
;3、学习10进制转10进制的方法。
;所有资源:
;1、TMRO定时器。产生温度转换所需要的延时时间。
;2、PORTA口。即做LCD显示时可控制端口,RA2同时做18B20的数据接口
;3、PORTC口。做LCD显示时的数据口。
;功能说明
;1、通过18B20采集当前环境
;最高温度可显示127.9375,最低温度可显示0.0625(无负温度处理部分)
;2、将温度在LCD上显示(3位整数,4位小数)
;硬件连接
;1,在18B20按DEMO板上的标识插在插座U8上
;2,拨码开关S13第4位置ON
;3,其他所有拨码开关都置OFF
;深圳市乾龙盛电子科技有限公司(PIC单片机学习网)
;网站 http://www.pic16.com 讨论论坛:http://pic16.com/bbs/
;实例编制:技术部 钟闺田(工程师) 论坛网名:zhongruntian
;版权所有,转载请注明出处,并不能去掉或改变文件中的说明文字。
;程序文件名“LCDAND18B20.ASM“
;源程序如下:
LIST P=PIC16F877
TITLE="LCD DISPLAY"
ERRORLEVEl -302 ;去掉编译时的302号提示信息
;__CONFIG B'000010010101' ;代码保护开启;WRT_ENABLE;CPD_ENABLE;LVP_DISABLE;BODEN_ENABLE
;PWRTE_ENABLE;WDT_ENABLE;OSC_XT
;*****************以下是暂存器的定义*****************************
#INCLUDE<P16F877A.INC>
#DEFINE RS PORTA,1 ;LCD控制信号
#DEFINE RW PORTA,2 ;LCD控制信号
#DEFINE E PORTA,3 ;LCD控制信号
#DEFINE DAT PORTC ;LCD数据线
#DEFINE DQ PORTA,2 ;18B20数据口
CBLOCK 20H
DQ_DELAY1
DQ_DELAY2
TEMP
TEMP1
TEMP2 ;存放采样到的温度值
COUNT
COUNT1
ENDC
TMR0_VALUE EQU 0AH ;寄存器初值为6,预分频比1:4,中断一次时间为4*(256-6)=1000us
DQ_DELAY_VALUE1 EQU 0FAH
DQ_DELAY_VALUE2 EQU 4H
;***********************以下是宏定义****************************
READ_STATE MACRO ;读18B20的状态
BCF RS
BSF RW
BSF E
ENDM
WRITE_COMMAND MACRO ;写命令
BCF RS
BCF RW
BCF E
ENDM
WRITE_DATA MACRO ;写数据
BSF RS
BCF RW
BCF E
ENDM
;**********************以下是程序的开始************************
ORG 00H
NOP
GOTO MAIN ;入口地址
ORG 04H
RETFIE ;在中断入口出放置一条中断返回指令,防止干扰产生中断
;***************************主程序*******************************
MAIN
CLRF PORTC
CLRF PORTA
BANKSEL TRISA
CLRF TRISA ;A口所有先设置为输出
CLRF TRISC
MOVLW 01H
MOVWF OPTION_REG ;分频比1:4,定时器,内部时钟源
MOVLW 06H
MOVWF ADCON1 ;关闭所有A/D口
BCF STATUS,RP0
MOVLW 00H
MOVWF INTCON ;关闭所有中断,且同时清零T0IF
CLRF TEMP
CLRF TEMP1
CLRF TEMP2 ;清零临时寄存器
;****************************循环处理部分************************
;先启动18B20温度转换程序,在判断温度转换是否完成(需750us)
;未完成则调用显示子程序,直到完成温度转换
;完成后读取温度值
;送LCD显示
LOOP
CALL RESET_18B20 ;调用复位18B20子程序
MOVLW 0CCH
MOVWF TEMP
CALL WRITE_18B20 ;SKIP ROM命令
MOVLW 44H
MOVWF TEMP
CALL WRITE_18B20 ;温度转换命令
CLRF STATUS
BCF INTCON,T0IF
CALL DELAY_750MS ;调用温度转换所需要的750MS延时
NOP
CALL RESET_18B20
MOVLW 0CCH
MOVWF TEMP
CALL WRITE_18B20 ;SKIP ROM命令
MOVLW 0BEH
MOVWF TEMP
CALL WRITE_18B20 ;读温度命令
CALL READ_18B20 ;调用读温度低字节
MOVFW TEMP
MOVWF TEMP1 ;保存到TEMP1
CALL READ_18B20 ;调用读温度高字节
MOVFW TEMP
MOVWF TEMP2 ;保存到TMEP2
CALL RESET_18B20
CALL TEMP_CHANGE ;调用温度转换程序
CALL DISPLAY ;调用LCD显示程序
GOTO LOOP ;循环工作
;***************************LCD显示子程序************************
DISPLAY
;LCD模块初始化,由厂家提供的资料显示,其初始化过程为:
;6----写指令38H,此条指令是将LCD显示模块设置为8位数据线,双行,5X7点阵显示
;7----检测Busy信号;
;8----写指令08H,关闭显示
;9----检测Busy信号;
;10---写指令01H,显示清屏
;以后写入光标等的控制指令.
BANKSEL TRISA
CLRF TRISA ;A口为LCD控制信号,全输出
BANKSEL PORTA
NOP
MOVLW 38H
CALL COMMAND_WRITE ;显示模式设置:16*2显示,5*7点阵,8位数码接口
MOVLW 08H
CALL COMMAND_WRITE ;显示关闭,不显示光标
MOVLW 01H
CALL COMMAND_WRITE ;显示清屏
MOVLW 06H
CALL COMMAND_WRITE ;显示光标移动设置(右移),整屏显示不移动
MOVLW 0CH
CALL COMMAND_WRITE ;显示开及光标设置,不显示光标
DISPLAY0
MOVLW 84H
CALL COMMAND_WRITE ;设置显示起始位置
CALL BUSY ;判忙
MOVLW 8H ;共8个数据需要显示
MOVWF COUNT
MOVLW 37H ;取数地址
MOVWF FSR
DISPLAY1
INCF FSR,1 ;取数地址加1
MOVFW INDF
CALL DATA_WRITE ;调用写数据子程序
DECFSZ COUNT,1
GOTO DISPLAY1
RETURN
;*****************************写命令子程序***********************
COMMAND_WRITE
WRITE_COMMAND ;设置写命令所需要的控制信号
MOVWF DAT ;把命令字送数据口
BSF E
NOP
BCF E
CALL BUSY ;判忙
RETURN
;**************************判总线忙子程序************************
BUSY
BSF STATUS,RP0
MOVLW 80H
MOVWF TRISC ;数据口最高位置为输入口
BCF STATUS,RP0
READ_STATE
NOP
BCF E
BTFSC DAT,7 ;是否忙
GOTO BUSY ;是,继续判断
BANKSEL TRISC
CLRF TRISC ;否,数据最高位恢复为输出状态
BCF STATUS,RP0
RETURN
;*************************写数据子程序***************************
DATA_WRITE
WRITE_DATA
MOVWF DAT
BSF E
NOP
BCF E
CALL BUSY
RETURN
;*********************复位DS18B20子程序**************************
RESET_18B20
;根据DATASHEET介绍,写数据时应遵照如下规定:
;主控制器把总线拉低至少480us,
;18B20等待15-60us后,把总线拉低做为返回给控制器的应答信号
BANKSEL TRISA
BCF TRISA,2
BCF STATUS,RP0
BCF DQ
MOVLW 0A0H
MOVWF COUNT ;160US
DECFSZ COUNT,1
GOTO $-1 ;拉低480us
BSF DQ ;释放总线
MOVLW 14H
MOVWF COUNT
DECFSZ COUNT,1
GOTO $-1 ;等待60us
BANKSEL TRISA
BSF TRISA,2 ;DQ设置为输入
BCF STATUS,RP0
BTFSC DQ ;数据线是否为低
GOTO RESET_18B20 ;否则继续复位
MOVLW 4H
MOVWF COUNT
DECFSZ COUNT,1 ;延时一段时间后再次判断
GOTO $-1
BTFSC DQ
GOTO RESET_18B20
MOVLW 4BH
MOVWF COUNT
DECFSZ COUNT,1
GOTO $-1
BANKSEL TRISA
BCF TRISA,2 ;DQ设置为输出
BCF STATUS,RP0
RETURN
;*********************写DS18B20子程序****************************
WRITE_18B20
;根据DATASHEET介绍,写数据时应遵照如下规定:
;写数据0时,主控制器把总线拉低至少60us
;写数据1时,主控制器把总线拉低,但必须在15us内释放
MOVLW 8H
MOVWF COUNT ;8位数据
BANKSEL TRISA
BCF TRISA,2
BCF STATUS,RP0
BCF STATUS,C
WRITE_18B20_1
BSF DQ ;先保持DQ为高
MOVLW 5H
MOVWF COUNT1
BCF DQ ;拉低DQ15us
DECFSZ COUNT1,1
GOTO $-1
RRF TEMP,1
BTFSS STATUS,C ;判断写的数据为0还是1
GOTO WRITE_0
BSF DQ ;为1,立即拉高数据线
GOTO WRITE_END
WRITE_0
BCF DQ ;继续保持数据线为低
WRITE_END
MOVLW 0FH
MOVWF COUNT1 ;保持45ms
DECFSZ COUNT1,1
GOTO $-1
BSF DQ ;释放总线
DECFSZ COUNT,1 ;是否写完8位数据
GOTO WRITE_18B20_1
RETURN
;**********************读DS18B20子程序****************************
READ_18B20
;根据DATASHEET介绍,读数据时应遵照如下规定:
;读数据0时,主控制器把总线拉低后,18B20再把总线拉低60us
;读数据1时,主控制器把总线拉低后,保持总线状态不变
;主控制器在数据线拉低后15us内读区数据线上的状态。
MOVLW 8H ;一次读8位数据
MOVWF COUNT
READ_18B20_1
BANKSEL TRISA
BCF TRISA,2 ;数据线先设为输出
BCF STATUS,RP0
BCF DQ ;先拉低数据线
MOVLW 1H
MOVWF COUNT1
DECFSZ COUNT1,1 ;拉低总线3us
GOTO $-1
BSF DQ ;释放总线
BANKSEL TRISA
BSF TRISA,2 ;数据线设为输入
BCF STATUS,RP0
MOVLW 2H
MOVWF COUNT1
DECFSZ COUNT1,1 ;延时6ms
GOTO $-1
BSF STATUS,C
BTFSS DQ ;判断数据线状态
BCF STATUS,C
RRF TEMP,1 ;移位到TEMP中
MOVLW 12H
MOVWF COUNT1
DECFSZ COUNT1,1
GOTO $-1 ;读一位数据至少需要60us
DECFSZ COUNT,1 ;是否读完8位
GOTO READ_18B20_1
RETURN
;*******************温度表示形式转换程序**************************
;因为从18B20中读出的温度值是二进制形式,必须把它转换成对象ASCII才能在LCD上显示
;18B20中温度的表示为:S S S S S 2的6次方 2的5次方 2的4次方 2的3次方 2的2次方 。。。。2的负4次方
;结果整数放在38H开始的存储器里,小数部分放在3B开始的单元里
;38H(百位) 39H(十位) 3AH(个位) 3BH(小数点)3CH(十分位) 3DH(百分位) 3EH(千分位) 3FH(万分位)
TEMP_CHANGE
;整数部分
;因为转换后温度值位于两个单元内,所以必须先把它们组合到一个单元内。
;因为最大值为127.9375,所以只需判断结果是否大于100来决定百位上的结果
;用循环减0AH的方法得到十位的值,最后剩下的被减数即为个位的结果
MOVLW 7H
ANDWF TEMP2,1 ;只保留低3位
SWAPF TEMP2,0
MOVWF 3AH ;转存3AH
MOVFW TEMP1
MOVWF TEMP2 ;转存TEMP2
MOVLW 0F0H
ANDWF TEMP2,1 ;清除低4位
SWAPF TEMP2,0 ;高低半字节交换
IORWF 3AH,1 ;组合得到结果的7位整数部分
MOVLW 64H ;计算整数部分百位的结果
SUBWF 3AH,W ; -100
BTFSS STATUS,C
GOTO NEXT0 ;温度小于100
MOVWF 3AH ;减后的结果覆盖原来的数据
MOVLW 1H
MOVWF 38H ;整数部分最高位为1(不可能大于1)
GOTO $+2
NEXT0
CLRF 38H ;温度小于100,最高位为0
CLRF 39H ;计算整数部分十位的结果
MOVLW 0AH ; -10
SUBWF 3AH,1
BTFSS STATUS,C
GOTO NEXT1
INCF 39H,1 ;够减 十位上加1
GOTO $-5
NEXT1
MOVLW 0AH
ADDWF 3AH,1 ;多减一次再加回来,剩下的值即为个位上的值
MOVLW '.'
MOVWF 3BH ;小数点
;小数部分
;取四位精度
;计算方法为从最低位开始依次判断是否为1 ,若为1则分别加上:
;0.0625、0.125、0.25、0.5,而且只有百分位相加时有可能结果大于0AH
CLRF 3CH
CLRF 3DH
CLRF 3EH
CLRF 3FH
BTFSS TEMP1,0
GOTO NEXT2
MOVLW 5H
MOVWF 3FH
MOVLW 2H
MOVWF 3EH
MOVLW 6H
MOVWF 3DH ;万分位
NEXT2
BTFSS TEMP1,1
GOTO NEXT3
MOVLW 5H
ADDWF 3EH,1
MOVLW 2H
ADDWF 3DH,1
MOVLW 1H
MOVWF 3CH ;千分位
NEXT3
BTFSS TEMP1,2
GOTO NEXT5
MOVLW 5H
ADDWF 3DH,1
MOVLW 0AH
SUBWF 3DH,1
BTFSS STATUS,C
GOTO NEXT4
INCF 3CH,1
GOTO $+3
NEXT4
MOVLW 0AH
ADDWF 3DH,1
MOVLW 2H
ADDWF 3CH,1 ;百分位
NEXT5
BTFSS TEMP1,3
GOTO NEXT6
MOVLW 5H
ADDWF 3CH,1 ;十分位
NEXT6
MOVLW 30H ;各位加上30H,转换成对应的ASCII码,以便能在LCD上显示
ADDWF 38H,1
ADDWF 39H,1
ADDWF 3AH,1
ADDWF 3CH,1
ADDWF 3DH,1
ADDWF 3EH,1
ADDWF 3FH,1
RETURN
;**************************延时750ms******************************
DELAY_750MS
MOVLW DQ_DELAY_VALUE2
MOVWF DQ_DELAY2
DELAY_750MS_2
MOVLW DQ_DELAY_VALUE1
MOVWF DQ_DELAY1
DELAY_750MS_1
MOVLW TMR0_VALUE
MOVWF TMR0 ;开启定时器
BTFSS INTCON,T0IF
GOTO $-1
BCF INTCON,T0IF
DECFSZ DQ_DELAY1,1
GOTO DELAY_750MS_1
DECFSZ DQ_DELAY2,1
GOTO DELAY_750MS_2
RETURN
;**************************程序结束******************************
END
; 进入该实战演练的工序流程如下:
; 1.创建源文件和编辑源文件;在此介绍一种不同于前面讲的创建源文件的方法,用Windows附件中的”记事本”
; 这个为大家所熟知和好用的文件编辑器,并且可以方便的加入中文注释.不过有两点需要注意,一是注释前面的
; 分号”;”必须用西文半角输入;二是必须用”.asm”扩展名存储到事先建立的一个专用子目录下.
; 2.打开MPLAB集成开发环境:首先在WINDOWS环境下,选用开始>程序>Microchip MPLAB>MPLAB命令,启动MPLAB
; 并进入MPLAB的桌面.
; 3.创建项目:选用菜单File>New或Project>New Project,在事先建立的一个专用子目录下创建一个新项目,将
; 用记事本创建的源文件加入到该项目中.
; 4.建立项目中的目标文件:选择菜单Project >Build All(项目>建立所有文件),MPLAB将自动调用MPASM将项目
; 文件管理下的源文件(.asm)汇编成十六进制的目标文件(.hex).
[/quote]
5.5 18b20在MCS-51和6502上的实现
[quote]
;==============================================
;====Power Disassembler for MCS-51 and 6502====
;==============================================
; Writen by: 覃远高
; Copyright: 覃远高
; E-mail: qinyg@163.net
; Tel: 0755-2282553
; Last Update: 20.Aug,1999
;==============================================
;===========Disassemble information============
;==============================================
; File Name: C:\TDDOWNLOAD\51\boarddoc\18b20.bin
; Type: MCS-51反编译器
; Date: 2007-7-22
;==============================================
;==============================================
Q0000: ACALL INIT_AD
MOV ACC,#CCH
ACALL WRITE_68
MOV ACC,#44H
ACALL WRITE_68
ACALL INIT_AD
MOV ACC,#CCH
ACALL WRITE_68
Q0013: MOV ACC,#BEH
ACALL WRITE_68
MOV R1,#30H
MOV R6,#02H
LOOP_1C: ACALL READ_83
MOV @R1,A
INC R1
DJNZ R6,LOOP_1C
MOV R1,#30H
MOV A,@R1
RR A
RR A
RR A
RR A
ANL A,#0FH
MOV R3,A
INC R1
MOV A,@R1
RL A
RL A
RL A
RL A
ANL A,#70H
ORL A,R3
MOV 32H,A
LOOP_37: CLR P2.5
CLR P2.6
CLR P2.7
MOV A,32H
MOV B,#0AH
DIV AB
ACALL loadFont_9a
MOV P0,A
MOV R7,#0BH
ACALL delayR7_7f
SETB P2.7
MOV A,B
ACALL loadFont_9a
MOV P0,A
MOV R7,#0BH
ACALL delayR7_7f
SETB P2.6
CLR P2.7
MOV ACC,#0CH
ACALL loadFont_9a
MOV P0,A
MOV R7,#0BH
ACALL delayR7_7f
AJMP LOOP_37
WRITE_68: MOV R5,#08H
LOOP_6A: SETB P1.7
NOP
CLR P1.7
NOP
NOP
NOP
NOP
RRC A
MOV C,P1.7
MOV R7,#15H
ACALL delayR7_7f
SETB P1.7
DJNZ R5,LOOP_6A
RET
;===========================================
delayR7_7f: NOP
DJNZ R7,delayR7_7f
RET
;===========================================
READ_83: MOV ACC,#00H
MOV R2,#08H
LOOP_88: SETB P1.7
NOP
CLR P1.7
NOP
SETB P1.7
MOV P1.7,C
RRC A
MOV R7,#15H
ACALL delayR7_7f
DJNZ R2,LOOP_88
RET
;===========================================
loadFont_9a: INC A
MOVC A,@A+PC
RET
;===========================================
Q009D: DB C0H,F9H,A4H,B0H,99H,92H,82H,F8H ;........
DB 80H,90H,88H,83H,A7H,A1H,86H,8EH ;........
;===========================================
INIT_AD: SETB P1.7
NOP
CLR P1.7
MOV R7,#A7H
ACALL delayR7_7f
SETB P1.7
MOV R7,#22H
ACALL delayR7_7f
MOV P1.7,C
MOV R7,#A7H
ACALL delayR7_7f
SETB P1.7
RET
;===========================================
[/quote]
这是一条镜像帖。来源:北邮人论坛 / circuit / #10801同步于 2009/6/28
该镜像源已超过 30 天没有更新,可能在源站已被删除。
Circuit机器人发帖
[专题] 温度传感器介绍
teamo
2009/6/28镜像同步6 回复
订阅后,新回复会通过你的通知中心匿名送达。
6 条回复
【 在 teamo 的大作中提到: 】
: 将温度信息转化为电信号的器件,称为温度传感器(废话)。
: 最廉价最经典的温度传感器,要数DS18B20了。其手册参见附件。
:
: ...................
汇编里面有一句
RRF temp,1
BTFSS STATUS,C
那个什么意思。。。。。不明白