关于51ds18b20单片机程序与DS18b20温度转换的问题 书上说温度转换代码0X44发送后启动温度转换,电源使

后使用快捷导航没有帐号?
查看: 3358|回复: 6
DS18B20多路温度采集
在线时间53 小时
TA的帖子TA的资源
一粒金砂(中级), 积分 20, 距离下一级还需 180 积分
一粒金砂(中级), 积分 20, 距离下一级还需 180 积分
在用MSP430X15x采集多路DS18B20时是不是要先规定每一路18B20的地址?这个地址是根据什么规定的?看到的程序基本上都是采集一路的,在搜索ROM后还需要哪些改动
本帖子中包含更多资源
才可以下载或查看,没有帐号?
在线时间42 小时
TA的帖子TA的资源
一粒金砂(中级), 积分 50, 距离下一级还需 150 积分
一粒金砂(中级), 积分 50, 距离下一级还需 150 积分
首先要得到挂在同一总线的ds18b20的ROM序列号
读取序列号命令是0x33
在初始化18b20后向18b20写0x33(在测序列号的时候总线上只能挂一只18B20)
然后18b20会返回64个比特的序列号;
每一个18b20的序列号不一样;
得到所有的18B20的序列号后将这些序列号事先存入程序;
之后要识别的话向总线写ROM匹配命令即0x55
然后向总线写你要找的18B20序列号;
之后就只有这个18B20会响应单片机的指令;
另外:在启动温度转换的时候先向18B20写0xcc(跳过ROM匹配)这样所有在总线上的18B20都收的到命令
然后写启动温度转换命令0X44;
事实上18B20启动温度转换命令或者读取温度数据命令之前必须要有0xcc(跳过ROM匹配)或是0x55(ROM匹配);这其实就是在发送命令前先指定接收者,可以是全部的18B20或者是其中一个。
至于18B20序列号自动检测。。。相当难搞。。检测命令以及检测方法在DATASHEET上有,不过建议还是直接事先测好序列号然后存入程序来识别比较简单。
#define uchar unsigned char
#define uint unsigned int
#define DataDir
#define DataPort
#define Busy
#define CtrlDir
在线时间53 小时
TA的帖子TA的资源
一粒金砂(中级), 积分 20, 距离下一级还需 180 积分
一粒金砂(中级), 积分 20, 距离下一级还需 180 积分
回复 沙发 voodo 的帖子
#include&msp430x15x.h&
#include&intrins.h&
#define uchar unsigned char
#define uint unsigned int
#define DataDir& &&&P4DIR
#define DataPort& & P4OUT& & & & & & & & & & & & & & & &
#define Busy& & & && &&&0x80
#define CtrlDir& &&&P3DIR
#define CLR_RS P3OUT&=~BIT0;& & //RS = P3.0& & & &
#define SET_RS P3OUT|=BIT0;& & & &
#define CLR_RW P3OUT&=~BIT1;& & & & //RW = P3.1
#define SET_RW P3OUT|=BIT1;& & & &
#define CLR_EN P3OUT&=~BIT2;& & & & //EN = P3.2& & & &
#define SET_EN P3OUT|=BIT2;& & & &
#define DQ1 P2OUT |= BIT4
#define DQ0 P2OUT &= ~BIT4
#define DQ_in& &P2DIR &= ~BIT4
#define DQ_out&&P2DIR |= BIT4
#define DQ_val&&(P2IN & BIT4)
uchar tab1[16];
uchar code tab[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
void delay(int ms)
&&while(ms--)
& &&&for(i=0;i&250;i++)
& && & _nop_(); _nop_(); _nop_(); _nop_();
void DispStr(uchar x,uchar y,uchar *ptr)
& & uchar *
& & uchar i,n = 0;
& & temp =
& & while(*ptr++ != '\0')& &n++;& & //计算字符串有效字符的个数
& & for (i=0;i&n;i++)
& && &&&Disp1Char(x++,y,temp);
& && &&&if (x == 0x0f)
& && && &&&x&&= 0;
& && && &&&y ^= 1;
/*******************************************
函数名称:DispNchar
功& & 能:让液晶从某个位置起连续显示N个字符
参& & 数:x--位置的列坐标
& && && & y--位置的行坐标
& && && & n--字符个数
& && && & ptr--指向字符存放位置的指针
返回值&&:无
********************************************/
void DispNChar(uchar x,uchar y, uchar n,uchar *ptr)
& & for (i=0;i&n;i++)
& && &&&Disp1Char(x++,y,ptr);
& && &&&if (x == 0x0f)
& && && &&&x = 0;
& && &&&y ^= 1;
/*******************************************
函数名称:LocateXY
功& & 能:向液晶输入显示字符位置的坐标信息
参& & 数:x--位置的列坐标
& && && & y--位置的行坐标
返回值&&:无
********************************************/
void LocateXY(uchar x,uchar y)
& & temp = x&0x0f;
& & y &= 0x01;
& & if(y)& &temp |= 0x40;&&//如果在第2行
& & temp |= 0x80;
& & LcdWriteCommand(temp,1);
/*******************************************
函数名称:Disp1Char
功& & 能:在某个位置显示一个字符
参& & 数:x--位置的列坐标
& && && & y--位置的行坐标
& && && & data--显示的字符数据
返回值&&:无
********************************************/
void Disp1Char(uchar x,uchar y,uchar data)
& & LocateXY( x, y );& & & & & & & & & & & &
& & LcdWriteData( data );& & & & & & & &
/*******************************************
函数名称:LcdReset
功& & 能:对1602液晶模块进行复位操作
参& & 数:无
返回值&&:无
********************************************/
void LcdReset(void)
& & CtrlDir |= 0x07;& && && && && &&&//控制线端口设为输出状态
& & DataDir&&= 0xFF;& && && && && &&&//数据端口设为输出状态
& & LcdWriteCommand(0x38, 0);& & & && &&&//规定的复位操作
& & Delay5ms();
& & LcdWriteCommand(0x38, 0);& & & & & & & &
& & Delay5ms();
& & LcdWriteCommand(0x38, 0);
& & Delay5ms();
& & LcdWriteCommand(0x38, 1);& & & & & & & & //显示模式设置
& & LcdWriteCommand(0x08, 1);& & & & & & & & //显示关闭
& & LcdWriteCommand(0x01, 1);& & & && &&&//显示清屏
& & LcdWriteCommand(0x06, 1);& & & & & & & & //写字符时整体不移动
& & LcdWriteCommand(0x0c, 1);& & & & & & & & //显示开,不开游标,不闪烁
/*******************************************
函数名称:LcdWriteCommand
功& & 能:向液晶模块写入命令
参& & 数:cmd--命令,
& && && & chk--是否判忙的标志,1:判忙,0:不判
返回值&&:无
********************************************/
void LcdWriteCommand(uchar cmd,uchar chk)
& & if (chk) WaitForEnable();& &// 检测忙信号?
& & CLR_RS;& & & &
& & CLR_RW;
& & _NOP();
& & DataPort =& && && && & //将命令字写入数据端口
& & _NOP();& & & & & & & & & & & & & & & & & & & &
& & SET_EN;& && && && && && && &//产生使能脉冲信号
& & _NOP();
& & _NOP();
& & CLR_EN;& & & & & & & & & & & &
/*******************************************
函数名称:LcdWriteData
功& & 能:向液晶显示的当前地址写入显示数据
参& & 数:data--显示字符数据
返回值&&:无
********************************************/
void LcdWriteData( uchar data )
& & WaitForEnable();& && &&&//等待液晶不忙
& & SET_RS;
& & CLR_RW;
& & _NOP();
& & DataPort =& && &&&//将显示数据写入数据端口
& & _NOP();
& & SET_EN;& && && && && &&&//产生使能脉冲信号
& & _NOP();
& & _NOP();
& & CLR_EN;& & & & & & & &
/*******************************************
函数名称:WaitForEnable
功& & 能:等待1602液晶完成内部操作
参& & 数:无
返回值&&:无
********************************************/
void WaitForEnable(void)
& & P4DIR &= 0x00;&&//将P4口切换为输入状态
& & CLR_RS;
& & SET_RW;
& & _NOP();
& & SET_EN;
& & _NOP();
& & _NOP();
& & while((P4IN & Busy)!=0);&&//检测忙标志
& & CLR_EN;
& & P4DIR |= 0xFF;&&//将P4口切换为输出状态
& && && && && && && &&&
/*******************************************
函数名称:Delay5ms
功& & 能:延时约5ms
参& & 数:无
返回值&&:无
********************************************/
void Delay5ms(void)
& & uint i=40000;
& & while (i != 0)
& && &&&i--;
void DelayNus(uint n)
& & CCR0 =
& & TACTL |= MC_1;& && && &&&//增计数到CCR0
& & while(!(TACTL & BIT0));& &//等待
& & TACTL &= ~MC_1;& && && & //停止计数
& & TACTL &= ~BIT0;& && && & //清除中断标志
/*******************************************
函数名称:Init_18B20
功& & 能:对DS18B20进行复位操作
参& & 数:无
返回值&&:初始化状态标志:1--失败,0--成功
********************************************/
uchar Init_18B20(void)
& & uchar E
& & _DINT();
& & DelayNus(500);
& & DelayNus(55);
& & _NOP();
& & if(DQ_val)& && &
& && &&&Error = 1;& && && & //初始化失败
& && &&&Error = 0;& && && & //初始化成功
& & _EINT();
& & DelayNus(400);
& & return E
/*******************************************
函数名称:Write_18B20
功& & 能:向DS18B20写入一个字节的数据
参& & 数:wdata--写入的数据
返回值&&:无
********************************************/
void Write_18B20(uchar wdata)
& & _DINT();
& & for(i = 0; i & 8;i++)
& && &&&DQ0;
& && &&&DelayNus(6);& && && && &//延时6us
& && &&&if(wdata & 0X01)& & DQ1;
& && &&&else& && && && && & DQ0;
& && &&&wdata &&= 1;
& && &&&DelayNus(50);& && && &&&//延时50us
& && &&&DQ1;
& && &&&DelayNus(10);& && && &&&//延时10us
& & _EINT();
/*******************************************
函数名称:Read_18B20
功& & 能:从DS18B20读取一个字节的数据
参& & 数:无
返回值&&:读出的一个字节数据
********************************************/
uchar Read_18B20(void)
& & uchar temp = 0;
& & _DINT();
& & for(i = 0;i & 8;i++)
& && &&&temp &&= 1;
& && &&&DQ0;
& && &&&DelayNus(6);& && && && &//延时6us
& && &&&DQ1;
& && &&&DelayNus(8);& && && && &//延时9us
& && &&&DQ_
& && &&&_NOP();
& && &&&if(DQ_val)& &temp |= 0x80;
& && &&&DelayNus(45);& && && &&&//延时45us
& && &&&DQ_
& && &&&DQ1;
& && &&&DelayNus(10);& && && &&&//延时10us
& & _EINT();
& & return&&
void readrom()
&&uchar i,sn1,sn2,sn3,sn4,sn5,sn6,sn7,sn8;
&&uchar Init_18B20;
&&delay(1);
&&Write_18B20(0x33);
&&sn1=Read_18B20();
&&sn2=Read_18B20();
&&sn3=Read_18B20();
&&sn4=Read_18B20();
&&sn5=Read_18B20();
&&sn6=Read_18B20();
&&sn7=Read_18B20();
&&sn8=Read_18B20();
&&tab1[14]=sn1/16;tab1[15]=sn1%16;
&&tab1[12]=sn2/16;tab1[13]=sn2%16;
&&tab1[10]=sn3/16;tab1[11]=sn3%16;
&&tab1[8]=sn4/16;tab1[9]=sn4%16;
&&tab1[6]=sn5/16;tab1[7]=sn5%16;
&&tab1[4]=sn6/16;tab1[5]=sn6%16;
&&tab1[2]=sn7/16;tab1[2]=sn7%16;
&&tab1[0]=sn8/16;tab1[1]=sn8%16;
& &LocateXY(0,0);
&&while(tab!='\0')
& &LcdWriteData(tab[tab1]);
& &_nop_();_nop_();_nop_();_nop_();
void main()
&&delay(10);
&&LcdReset();
&&while(1)
& &readrom();
这是楼主自己整理的测DS18B20序列的程序&&测不到序列& & 请帮忙查看一下&&不胜感激
写0x33之前没有初始化18B20&
在线时间42 小时
TA的帖子TA的资源
一粒金砂(中级), 积分 50, 距离下一级还需 150 积分
一粒金砂(中级), 积分 50, 距离下一级还需 150 积分
回复 板凳 泡泡鱼会飞 的帖子
写0x33之前没有初始化18B20
初始化后也不行啊&
在线时间53 小时
TA的帖子TA的资源
一粒金砂(中级), 积分 20, 距离下一级还需 180 积分
一粒金砂(中级), 积分 20, 距离下一级还需 180 积分
回复 4楼 voodo 的帖子
初始化后也不行啊
顺序是这样:1初始化18B20;2写序列号检测指令;3读序列号;4显示
有问题的话就1个个查过,先看你液晶显示是否正常,这个最容易;然后看18B20各个驱动函数里面的时间对不对,比如初始化的时候拉低的时间,因为你可&
在线时间42 小时
TA的帖子TA的资源
一粒金砂(中级), 积分 50, 距离下一级还需 150 积分
一粒金砂(中级), 积分 50, 距离下一级还需 150 积分
回复 5楼 泡泡鱼会飞 的帖子
顺序是这样:1初始化18B20;2写序列号检测指令;3读序列号;4显示
有问题的话就1个个查过,先看你液晶显示是否正常,这个最容易;然后看18B20各个驱动函数里面的时间对不对,比如初始化的时候拉低的时间,因为你可能是用其他人的驱动,芯片时钟频率上不一致,导致时间不对,这个要算一下;然后再看各个驱动里面的动作对不对,这个可以对着DATASHEET看
在线时间1 小时
TA的帖子TA的资源
一粒金砂(中级), 积分 10, 距离下一级还需 190 积分
一粒金砂(中级), 积分 10, 距离下一级还需 190 积分
你好,你的那个多点的程序 现在 改好了吗?
我想请教几个问题
Powered by
逛了这许久,何不进去瞧瞧?最近都在学习和写单片机的程序, 今天有空又模仿写了一个与DS18B20基于单总线通信的程序.
DS18B20 数字温度传感器(参考:是DALLAS 公司生产的1-Wire,即单总线器件,具有线路简单,体积小的特点。因此用它来组成一个测温系统,具有线路简单,在一根通信线,可以挂很多这样的数字温度计。DS18B20 产品的特点:
(1)、只要求一个I/O 口即可实现通信。
(2)、在DS18B20 中的每个器件上都有独一无二的序列号。
(3)、实际应用中不需要外部任何元器件即可实现测温。
(4)、测量温度范围在-55 到+125℃之间; 在-10 ~ +85℃范围内误差为±5℃;
(5)、数字温度计的分辨率用户可以从9 位到12 位选择。将12位的温度值转换为数字量所需时间不超过750
(6)、内部有温度上、下限告警设置。
DS18B20引脚分布图
DS18B20 详细引脚功能描述:
1、GND 地信号;
2、DQ数据输入出引脚。开漏单总线接口引脚。当被用在寄生电源下,此引脚可以向器件提供电源;漏极开路, 常太下高电平. 通常要求外接一个约5kΩ的上拉电阻.
3、VDD可选择的VDD 引脚。电压范围:3~5.5V; 当工作于寄生电源时,此引脚必须接地。
DS18B20存储器结构图
暂存储器的头两个字节为测得温度信息的低位和高位字节;
第3, 4字节是TH和TL的易失性拷贝, 在每次电复位时都会被刷新;
第5字节是配置寄存器的易失性拷贝, 同样在电复位时被刷新;
第9字节是前面8个字节的CRC检验值.
配置寄存器的命令内容如下:
MSB&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& LSB
R0和R1是温度值分辨率位, 按下表进行配置.默认出厂设置是R1R0 = 11, 即12位.
温度值分辨率配置表
最大转换时间(ms)
93.75(tconv/8)
183.50(tconv/4)
375(tconv/2)
750 (tconv)
4种分辨率对应的温度分辨率为0.5℃, 0.25℃, 0.125℃, 0.0625℃(即最低一位代表的温度值)
12位分辨率时的两个温度字节的具体格式如下:
其中高字节前5位都是符号位S, 若分辨率低于12位时, 相应地使最低为0, 如: 当分辨率为10位时, 低字节为:
, 高字节不变....
一些温度与转换后输出的数字参照如下:
换成16进制
+25.0625℃
-25.0625℃
由上表可看出, 当输出是负温度时, 使用补码表示, 方便计算机运算(若是用C语言, 直接将结果赋值给一个int变量即可).
DS18B20 的使用方法:
由于DS18B20 采用的是方式,即在一根数据线实现数据的双向传输,而对单片机来说,我们必须采用软件的方法来模拟单总线的协议时序来完成对DS18B20芯片的访问。
由于DS18B20是在一根I/O线上读写数据,因此,对读写的数据位有着严格的时序要求。
DS18B20有严格的通信协议来保证各位数据传输的正确性和完整性。
该协议定义了几种信号的时序:初始化时序(dsInit()实现)、读时序(readByte())、写时序(writeByte())。
所有时序都是将主机作为主设备,单总线器件作为从设备。而每一次命令和数据的传输都是从主机主动启动写时序开始,如果要求单总线器件回送数据,在进行写命令后,主机需启动读时序完成数据接收。数据和命令的传输都是低位在先。
DS18B20与单片机连接电路图:
利用软件模拟DS18B20的单线协议和命令:主机操作DS18B20必须遵循下面的顺序
单线总线上的所有操作都是从初始化开始的. 过程如下:
1)请求: 主机通过拉低单线480us以上, 产生复位脉冲, 然后释放该线, 进入Rx接收模式. 主机释放总线时, 会产生一个上升沿脉冲.
DQ : 1 -& 0(480us+) -& 1&
2)响应: DS18B20检测到该上升沿后, 延时15~60us, 通过拉低总线60~240us来产生应答脉冲.
DQ: 1(15~60us) -& 0(60~240us)
3)接收响应: 主机接收到从机的应答脉冲后, 说明有单线器件在线. 至此, 初始化完成.
2. ROM操作命令
当主机检测到应答脉冲, 便可发起ROM操作命令. 共有5类ROM操作命令, 如下表
&命令类型&
Read Rom &&读ROM&&
读取激光ROM中的64位,只能用于总线上单个DS18B20器件情况, 多挂时会发生数据冲突
Match Rom匹配ROM
此命令后跟64位ROM序列号,寻址多挂总线上的对应DS18B20.只有序列号完全匹配的DS18B20才能响应后面的内存操作命令,其他不匹配的将等待复位脉冲.可用于单挂或多挂两种情况.
Skip Rom&& 跳过ROM
可无须提供64位ROM序列号即可运行内存操作命令, 只能用于单挂.
Search Rom搜索ROM
通过一个排除法过程, 识别出总线上所有器件的ROM序列号
Alarm Search告警搜索
命令流程与Search Rom相同, 但DS18B20只有最近的一次温度测量时满足了告警触发条件的, 才会响应此命令.
3. 内存操作命令
在成功执行ROM操作命令后, 才可使用内存操作命令. 共有6种内存操作命令:
Write Scratchpad
写暂存器中地址2~地址4的3个字节(TH,TL和配置寄存器)在发起复位脉冲之前,3个字节都必须要写.
Read Scratchpad
读取暂存器内容,从字节0~一直到字节8, 共9个字节,主机可随时发起复位脉冲,停止此操作,通常我们只需读前5个字节.
Copy Scratchpad
复制暂存器
将暂存器中的内容复制进EERAM, 以便将温度告警触发字节存入非易失内存. 如果此命令后主机产生读时隙, 那么只要器件还在进行复制都会输出0, 复制完成后输出1.
Convert T&
开始温度转换操作. 若在此命令后主机产生时隙, 那么只要器件还在进行温度转换就会输出0, 转换完成后输出1.
Recall E2&&&
重调E2暂存器
将存储在EERAM中的温度告警触发值和配置寄存器值重新拷贝到暂存器中,此操作在DS18B20加电时自动产生.
Read Power Supply
读供电方式
主机发起此命令后每个读数时隙内,DS18B20会发信号通知它的供电方式:0寄生电源, 1外部供电.
4. 数据处理
DS18B20要求有严格的时序来保证数据的完整性. 在单线DQ上, 有复位脉冲, 应答脉冲, 写0, 写1, 读0, 读1这6种信号类型. 除了应答脉冲外, 其它都由主机产生. 数据位的读和写是通过读、写时隙实现的.
1) 写时隙: 当主机将数据线从高电平拉至低电平时, 产生写时隙.所有写时隙都必须在60us以上, 各写时隙间必须保证1us的恢复时间.
写"1" : 主机将数据线DQ先拉低, 然后释放15us后, 将数据线DQ拉高;
写"0" : 主机将DQ拉低并至少保持60us以上.
2)读时隙: 当主机将数据线DQ从高电平拉至低电平时, 产生读时隙. 所有读时隙最短必须持续60us, 各读时隙间必须保证1us的恢复时间.
读: 主机将DQ拉低至少1us,. 此时主机马上将DQ拉高, 然后就可以延时15us后, 读取DQ即可.
源代码: (测量范围: 0 ~ 99度)
&&1#include&&reg51.H&
&&2//通过DS18B20测试当前环境温度,&并通过数码管显示当前温度值
&&3sbit&wela&=&P2^7;&&//数码管位选
&&4sbit&dula&=&P2^6;&&//数码管段选
&&5sbit&ds&=&P2^2;
&&6//0-F数码管的编码(共阴极)
&&7unsigned&char&code&table[]={0x3f,0x06,0x5b,0x4f,0x66,
&&8&&&&0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
&&9//0-9数码管的编码(共阴极),&带小数点
&10unsigned&char&code&tableWidthDot[]={0xbf,&0x86,&0xdb,&0xcf,&0xe6,&0xed,&0xfd,&
&11&&&&0x87,&0xff,&0xef};
&13//延时函数,&例i=10,则大概延时10ms.
&14void&delay(unsigned&char&i)
&16&&&&unsigned&char&j,&k;
&17&&&&for(j&=&i;&j&&&0;&j--)
&19&&&&&&&&for(k&=&125;&k&&&0;&k--);
&23//初始化DS18B20
&24//让DS18B20一段相对长时间低电平,&然后一段相对非常短时间高电平,&即可启动
&25void&dsInit()
&27&&&&//一定要使用unsigned&int型,&一个i++指令的时间,&作为与DS18B20通信的小时间间隔
&28&&&&//以下都是一样使用unsigned&int型
&29&&&&unsigned&int&i;&&
&30&&&&ds&=&0;
&31&&&&i&=&103;
&32&&&&while(i&0)&i--;
&33&&&&ds&=&1;
&34&&&&i&=&4;
&35&&&&while(i&0)&i--;
&38//向DS18B20读取一位数据
&39//读一位,&让DS18B20一小周期低电平,&然后两小周期高电平,&
&40//之后DS18B20则会输出持续一段时间的一位数据
&41bit&readBit()
&43&&&&unsigned&int&i;
&44&&&&bit&b;
&45&&&&ds&=&0;
&46&&&&i++;
&47&&&&ds&=&1;&
&48&&&&i++;&i++;
&49&&&&b&=&
&50&&&&i&=&8;&
&51&&&&while(i&0)&i--;
&52&&&&return&b;
&55//读取一字节数据,&通过调用readBit()来实现
&56unsigned&char&readByte()
&58&&&&unsigned&int&i;
&59&&&&unsigned&char&j,&
&60&&&&dat&=&0;
&61&&&&for(i=0;&i&8;&i++)
&63&&&&&&&&j&=&readBit();
&64&&&&&&&&//最先读出的是最低位数据
&65&&&&&&&&dat&=&(j&&&&7)&|&(dat&&&&1);
&67&&&&return&
&70//向DS18B20写入一字节数据
&71void&writeByte(unsigned&char&dat)
&73&&&&unsigned&int&i;
&74&&&&unsigned&char&j;
&75&&&&bit&b;
&76&&&&for(j&=&0;&j&&&8;&j++)
&78&&&&&&&&b&=&dat&&&0x01;
&79&&&&&&&&dat&&&=&1;
&80&&&&&&&&//写"1",&让低电平持续2个小延时,&高电平持续8个小延时
&81&&&&&&&&if(b)&&&
&82&&&&&&&&{
&83&&&&&&&&&&&&ds&=&0;
&84&&&&&&&&&&&&i++;&i++;
&85&&&&&&&&&&&&ds&=&1;
&86&&&&&&&&&&&&i&=&8;&while(i&0)&i--;
&87&&&&&&&&}
&88&&&&&&&&else&&//写"0",&让低电平持续8个小延时,&高电平持续2个小延时
&89&&&&&&&&{
&90&&&&&&&&&&&&ds&=&0;
&91&&&&&&&&&&&&i&=&8;&while(i&0)&i--;
&92&&&&&&&&&&&&ds&=&1;
&93&&&&&&&&&&&&i++;&i++;
&94&&&&&&&&}
&98//向DS18B20发送温度转换命令
&99void&sendChangeCmd()
101&&&&dsInit();&&&&//初始化DS18B20
102&&&&delay(1);&&&&//延时1ms
103&&&&writeByte(0xcc);&//写入跳过序列号命令字
104&&&&writeByte(0x44);&//写入温度转换命令字
107//向DS18B20发送读取数据命令
108void&sendReadCmd()
110&&&&dsInit();
111&&&&delay(1);
112&&&&writeByte(0xcc);&//写入跳过序列号命令字
113&&&&writeByte(0xbe);&//写入读取数据令字
116//获取当前温度值
117unsigned&int&getTmpValue()
119&&&&unsigned&int&&//存放温度数值
120&&&&float&t;
121&&&&unsigned&char&low,&
122&&&&sendReadCmd();
123&&&&//连续读取两个字节数据
124&&&&low&=&readByte();&
125&&&&high&=&readByte();
126&&&&//将高低两个字节合成一个整形变量
127&&&&value&=&
128&&&&value&&&=&8;
129&&&&value&|=&
130&&&&//DS18B20的精确度为0.0625度,&即读回数据的最低位代表0.0625度
131&&&&t&=&value&*&0.0625;
132&&&&//将它放大10倍,&使显示时可显示小数点后一位,&并对小数点后第二2进行4舍5入
133&&&&//如t=11.0625,&进行计数后,&得到value&=&111,&即11.1&度
134&&&&value&=&t&*&10&+&0.5;
135&&&&return&
138//显示当前温度值,&精确到小数点后一位
139void&display(unsigned&int&v)&
141&&&&unsigned&char&
142&&&&unsigned&char&datas[]&=&{0,&0,&0};
143&&&&datas[0]&=&v&/&100;
144&&&&datas[1]&=&v&%&100&/&10;
145&&&&datas[2]&=&v&%&10;
146&&&&for(count&=&0;&count&&&3;&count++)
148&&&&&&&&//片选
149&&&&&&&&wela&=&0;&
150&&&&&&&&P0&=&((0xfe&&&&count)&|&(0xfe&&&&(8&-&count)));&//选择第(count&+&1)&个数码管
151&&&&&&&&wela&=&1;&//打开锁存,&给它一个下降沿量
152&&&&&&&&wela&=&0;
153&&&&&&&&//段选
154&&&&&&&&dula&=&0;
155&&&&&&&&if(count&!=&1)
156&&&&&&&&{
157&&&&&&&&&&&&P0&=&table[datas[count]];&&//显示数字
158&&&&&&&&}
159&&&&&&&&else
160&&&&&&&&{
161&&&&&&&&&&&&P0&=&tableWidthDot[datas[count]];&//显示带小数点数字
162&&&&&&&&}
163&&&&&&&&dula&=&1;&&//打开锁存,&给它一个下降沿量
164&&&&&&&&dula&=&0;
165&&&&&&&&delay(5);&//延时5ms,&即亮5ms
167&&&&&&&&//清除段先,&让数码管灭,&去除对下一位的影响,&去掉高位对低位重影
168&&&&&&&&//若想知道影响效果如何,&可自行去掉此段代码
169&&&&&&&&//因为数码管是共阴极的,&所有灭的代码为:&00H
170&&&&&&&&dula&=&0;
171&&&&&&&&P0&=&0x00;&&//显示数字
172&&&&&&&&dula&=&1;&//打开锁存,&给它一个下降沿量
173&&&&&&&&dula&=&0;
177void&main()
179&&&&unsigned&char&i;
180&&&&unsigned&int&
181&&&&while(1)
183&&&&&&&&//启动温度转换
184&&&&&&&&sendChangeCmd();
185&&&&&&&&value&=&getTmpValue();
186&&&&&&&&//显示3次
187&&&&&&&&for(i&=&0;&i&&&3;&i++)
188&&&&&&&&{
189&&&&&&&&&&&&display(value);
190&&&&&&&&}
改进代码: 扩大测量范围, 使可测量范围为: -55度 ~ +125度, 严格按照上面的流程进行软件设计
3.15 1:34 修正display()函数中的下一位显示对上一位的影响
&&1#include&&reg51.H&
&&2#include&intrins.h&
&&3#include&&math.H&&&//要用到取绝对值函数abs()
&&4//通过DS18B20测试当前环境温度,&并通过数码管显示当前温度值,&目前显示范围:&-55~&+125度
&&5sbit&wela&=&P2^7;&&//数码管位选
&&6sbit&dula&=&P2^6;&&//数码管段选
&&7sbit&ds&=&P2^2;
&&8int&tempV
&10//0-F数码管的编码(共阴极)
&11unsigned&char&code&table[]={0x3f,0x06,0x5b,0x4f,0x66,
&12&&&&0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
&13//0-9数码管的编码(共阴极),&带小数点
&14unsigned&char&code&tableWidthDot[]={0xbf,&0x86,&0xdb,&0xcf,&0xe6,&0xed,&0xfd,&
&15&&&&0x87,&0xff,&0xef};
&17//延时函数,&对于11.0592MHz时钟,&例i=10,则大概延时10ms.
&18void&delay(unsigned&int&i)
&20&&&&unsigned&int&j;
&21&&&&while(i--)
&23&&&&&&&&for(j&=&0;&j&&&125;&j++);
&27//初始化DS18B20
&28//让DS18B20一段相对长时间低电平,&然后一段相对非常短时间高电平,&即可启动
&29void&dsInit()
&31&&&&//对于11.0592MHz时钟,&unsigned&int型的i,&作一个i++操作的时间大于为8us
&32&&&&unsigned&int&i;&&
&33&&&&ds&=&0;
&34&&&&i&=&100;&&&//拉低约800us,&符合协议要求的480us以上
&35&&&&while(i&0)&i--;
&36&&&&ds&=&1;&&&&//产生一个上升沿,&进入等待应答状态
&37&&&&i&=&4;
&38&&&&while(i&0)&i--;
&41void&dsWait()
&43&&&&&unsigned&int&i;
&44&&&&&while(ds);&&
&45&&&&&while(~ds);&&//检测到应答脉冲
&46&&&&&i&=&4;
&47&&&&&while(i&&&0)&i--;
&50//向DS18B20读取一位数据
&51//读一位,&让DS18B20一小周期低电平,&然后两小周期高电平,&
&52//之后DS18B20则会输出持续一段时间的一位数据
&53bit&readBit()
&55&&&&unsigned&int&i;
&56&&&&bit&b;
&57&&&&ds&=&0;
&58&&&&i++;&&&//延时约8us,&符合协议要求至少保持1us
&59&&&&ds&=&1;&
&60&&&&i++;&i++;&&//延时约16us,&符合协议要求的至少延时15us以上
&61&&&&b&=&
&62&&&&i&=&8;&
&63&&&&while(i&0)&i--;&&//延时约64us,&符合读时隙不低于60us要求
&64&&&&return&b;
&67//读取一字节数据,&通过调用readBit()来实现
&68unsigned&char&readByte()
&70&&&&unsigned&int&i;
&71&&&&unsigned&char&j,&
&72&&&&dat&=&0;
&73&&&&for(i=0;&i&8;&i++)
&75&&&&&&&&j&=&readBit();
&76&&&&&&&&//最先读出的是最低位数据
&77&&&&&&&&dat&=&(j&&&&7)&|&(dat&&&&1);
&79&&&&return&
&82//向DS18B20写入一字节数据
&83void&writeByte(unsigned&char&dat)
&85&&&&unsigned&int&i;
&86&&&&unsigned&char&j;
&87&&&&bit&b;
&88&&&&for(j&=&0;&j&&&8;&j++)
&90&&&&&&&&b&=&dat&&&0x01;
&91&&&&&&&&dat&&&=&1;
&92&&&&&&&&//写"1",&将DQ拉低15us后,&在15us~60us内将DQ拉高,&即完成写1
&93&&&&&&&&if(b)&&&
&94&&&&&&&&{
&95&&&&&&&&&&&&ds&=&0;
&96&&&&&&&&&&&&i++;&i++;&&//拉低约16us,&符号要求15~60us内
&97&&&&&&&&&&&&ds&=&1;&&&&
&98&&&&&&&&&&&&i&=&8;&while(i&0)&i--;&&//延时约64us,&符合写时隙不低于60us要求
&99&&&&&&&&}
100&&&&&&&&else&&//写"0",&将DQ拉低60us~120us
101&&&&&&&&{
102&&&&&&&&&&&&ds&=&0;
103&&&&&&&&&&&&i&=&8;&while(i&0)&i--;&&//拉低约64us,&符号要求
104&&&&&&&&&&&&ds&=&1;
105&&&&&&&&&&&&i++;&i++;&&//整个写0时隙过程已经超过60us,&这里就不用像写1那样,&再延时64us了
106&&&&&&&&}
110//向DS18B20发送温度转换命令
111void&sendChangeCmd()
113&&&&dsInit();&&&&//初始化DS18B20,&无论什么命令,&首先都要发起初始化
114&&&&dsWait();&&&//等待DS18B20应答
115&&&&delay(1);&&&&//延时1ms,&因为DS18B20会拉低DQ&60~240us作为应答信号
116&&&&writeByte(0xcc);&//写入跳过序列号命令字&Skip&Rom
117&&&&writeByte(0x44);&//写入温度转换命令字&Convert&T
120//向DS18B20发送读取数据命令
121void&sendReadCmd()
123&&&&dsInit();
124&&&&dsWait();
125&&&&delay(1);
126&&&&writeByte(0xcc);&//写入跳过序列号命令字&Skip&Rom
127&&&&writeByte(0xbe);&//写入读取数据令字&Read&Scratchpad
130//获取当前温度值
131int&getTmpValue()
133&&&&unsigned&int&
134&&&&int&&//存放温度数值
135&&&&float&t;
136&&&&unsigned&char&low,&
137&&&&sendReadCmd();
138&&&&//连续读取两个字节数据
139&&&&low&=&readByte();&
140&&&&high&=&readByte();
141&&&&//将高低两个字节合成一个整形变量
142&&&&//计算机中对于负数是利用补码来表示的
143&&&&//若是负值,&读取出来的数值是用补码表示的,&可直接赋值给int型的value
144&&&&tmpvalue&=&
145&&&&tmpvalue&&&=&8;
146&&&&tmpvalue&|=&
147&&&&value&=&
149&&&&//使用DS18B20的默认分辨率12位,&精确度为0.0625度,&即读回数据的最低位代表0.0625度
150&&&&t&=&value&*&0.0625;
151&&&&//将它放大100倍,&使显示时可显示小数点后两位,&并对小数点后第三进行4舍5入
152&&&&//如t=11.0625,&进行计数后,&得到value&=&1106,&即11.06&度
153&&&&//如t=-11.0625,&进行计数后,&得到value&=&-1106,&即-11.06&度
154&&&&value&=&t&*&100&+&(value&&&0&?&0.5&:&-0.5);&//大于0加0.5,&小于0减0.5
155&&&&return&
158unsigned&char&const&timeCount&=&3;&//动态扫描的时间间隔
159//显示当前温度值,&精确到小数点后一位
160//若先位选再段选,&由于IO口默认输出高电平,&所以当先位选会使数码管出现乱码
161void&display(int&v)&
163&&&&unsigned&char&
164&&&&unsigned&char&datas[]&=&{0,&0,&0,&0,&0};
165&&&&unsigned&int&tmp&=&abs(v);
166&&&&datas[0]&=&tmp&/&10000;
167&&&&datas[1]&=&tmp&%&10000&/&1000;
168&&&&datas[2]&=&tmp&%&1000&/&100;
169&&&&datas[3]&=&tmp&%&100&/&10;
170&&&&datas[4]&=&tmp&%&10;
171&&&&if(v&&&0)
173&&&&&&&&//关位选,&去除对上一位的影响
174&&&&&&&&P0&=&0xff;&
175&&&&&&&&wela&=&1;&//打开锁存,&给它一个下降沿量
176&&&&&&&&wela&=&0;
177&&&&&&&&//段选
178&&&&&&&&P0&=&0x40;&//显示"-"号
179&&&&&&&&dula&=&1;&&//打开锁存,&给它一个下降沿量
180&&&&&&&&dula&=&0;
182&&&&&&&&//位选
183&&&&&&&&P0&=&0xfe;&
184&&&&&&&&wela&=&1;&//打开锁存,&给它一个下降沿量
185&&&&&&&&wela&=&0;
186&&&&&&&&delay(timeCount);&
188&&&&for(count&=&0;&count&!=&5;&count++)
190&&&&&&&&//关位选,&去除对上一位的影响
191&&&&&&&&P0&=&0xff;&
192&&&&&&&&wela&=&1;&//打开锁存,&给它一个下降沿量
193&&&&&&&&wela&=&0;
194&&&&&&&&//段选
195&&&&&&&&if(count&!=&2)
196&&&&&&&&{
197&&&&&&&&/**//*&&&&if((count&==&0&&&&datas[count]&==&0)&
198&&&&&&&&&&&&&&&&||&((count&==&1&&&&datas[count]&==&0)&&&&(count&==&0&&&&datas[count&-&1]&==&0)))
199&&&&&&&&&&&&{
200&&&&&&&&&&&&&&&&P0&=&0x00;&//当最高位为0时,&不作显示
201&&&&&&&&&&&&}
202&&&&&&&&&&&&else*/
203&&&&&&&&&&&&&&&&P0&=&table[datas[count]];&&//显示数字
204&&&&&&&&}
205&&&&&&&&else
206&&&&&&&&{
207&&&&&&&&&&&&P0&=&tableWidthDot[datas[count]];&//显示带小数点数字
208&&&&&&&&}
209&&&&&&&&dula&=&1;&&//打开锁存,&给它一个下降沿量
210&&&&&&&&dula&=&0;
212&&&&&&&&//位选&
213&&&&&&&&P0&=&_crol_(0xfd,&count);&//选择第(count&+&1)&个数码管
214&&&&&&&&wela&=&1;&//打开锁存,&给它一个下降沿量
215&&&&&&&&wela&=&0;
216&&&&&&&&delay(timeCount);&
220void&main()
222&&&&unsigned&char&i;
224&&&&while(1)
226&&&&&&&&//启动温度转换
227&&&&&&&&sendChangeCmd();
228&&&&&&&&//显示5次
229&&&&&&&&for(i&=&0;&i&&&40;&i++)
230&&&&&&&&{
231&&&&&&&&&&&&display(tempValue);
232&&&&&&&&}
233&&&&&&&&tempValue&=&getTmpValue();
改进后的效果图:
只有一位小数
两位小数,& 并消除下一位对上一位的影响
(PS: 写这篇文章期间, 07年迟来的冬天过去了, 温度上升了5℃....温暖^_^)
其它参考资料:
1. 《51单片机C语言应用程序设计实例精讲》, 戴佳,戴卫恒编著,电子工业出版社。
阅读(...) 评论()}

我要回帖

更多关于 单片机18b20 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信