关于蓝桥杯STC15单片机的18B20程序
2016-03-04 13:03
567 查看
DS18B20是一种单总线数字温度传感器,测试温度范围-55℃-125℃,具有体积小,硬件开销低,抗干扰能力强,精度高的特点。单总线,意味着没有时钟线,只有一根通信线。单总线读写数据是靠控制起始时间和采样时间来完成,所以时序要求很严格,这也是DS18B20驱动编程的难点。
1.引脚图
![](http://img.blog.csdn.net/20151210195355171)
2.DS18B20内部结构图
![](http://img.blog.csdn.net/20151210184712155)
主要由2部分组成:64位ROM、9字节暂存器,如图所示。
(1) 64 位ROM。它的内容是64 位序列号,它可以被看作是该DS18B20 的地址序列码,其作用是使每个DS18B20 都各不相同,这样就可以实现一根总线上挂接多个DS18B20 的目的。
(2) 9字节暂存器包含:温度传感器、上限触发TH高温报警器、下限触发TL低温报警器、高速暂存器、8位CRC产生器。
3.64位ROM结构图
![](http://img.blog.csdn.net/20151210184906425)
8位CRC:是单总线系列器件的编码,DS18B20定义为28H。
48位序列号:是一个唯一的序列号。
8位系列码:由CRC产生器生产,作为ROM中的前56位编码的校验码。
4.9字节暂存器结构图
![](http://img.blog.csdn.net/20151210184812602)
以上是内部9 个字节的暂存单元(包括EEPROM)。
字节0~1 是温度存储器,用来存储转换好的温度。
字节2~3 是用户用来设置最高报警和最低报警值。这个可以用软件来实现。
字节4 是配置寄存器,用来配置转换精度,让它工作在9~12 位。
字节5~7 保留位。
字节8 CRC校验位。是64位ROM中的前56位编码的校验码。由CRC发生器产生。
5.温度寄存器结构图
![](http://img.blog.csdn.net/20151210185119044)
温度寄存器由两个字节组成,分为低8位和高8位。一共16位。
其中,第0位到第3位,存储的是温度值的小数部分。
第4位到第10位存储的是温度值的整数部分。
第11位到第15位为符号位。全0表示是正温度,全1表示是负温度。
表格中的数值,如果相应的位为1,表示存在。如果相应的位为0,表示不存在。
6.配置寄存器
![](http://img.blog.csdn.net/20151210190232265)
精度值:
9-bit 0.5℃
10-bit 0.25℃
11-bit 0.125℃
12-bit 0.0625℃
7.温度/数据关系
![](http://img.blog.csdn.net/20151210190036250)
注意:如果温度是一个负温度,要将读到的数据减一再取反
1.单总线通信初始化
![](http://img.blog.csdn.net/20151210184432678)
初始化时序包括:主机发出的复位脉冲和从机发出的应答脉冲。主机通过拉低单总线480-960μs产生复位脉冲;然后由主机释放总线,并进入接收模式。主机释放总线时,会产生一由低电平跳变为高电平的上升沿,单总线器件检测到该上升沿后,延时15~60μs,接着单总线器件通过拉低总线60~240μsμ来产生应答脉冲。主机接收到从机的以应答脉冲后,说明有单总线器件在线,到此初始化完成。然后主机就可以开始对从机进行ROM命令和功能命令操作。
2.位写入时序
![](http://img.blog.csdn.net/20151210184503688)
写时隙:当主机把数据线从逻辑高电平拉到逻辑低电平的时候,写时间隙开始。有两种写时间隙:写1的时间隙和写0时间隙。所有写时间隙必须最少持续60us,包括两个写周期间至少1us的恢复时间。DQ引脚上的电平变低后,DS18B20在一个15us到60us的时间窗口内对DQ引脚采样。如果DQ引脚是高电平,就是写1,如果DQ引脚是低电平,就是写0。主机要生成一个写1时间隙,必须把数据线拉到低电平然后释放,在写时间隙开始后的15us内允许数据线拉到高电平。主机要生成一个写0时间隙,必须把数据线拉到低电平并保持60us。
3.位读取时序
![](http://img.blog.csdn.net/20151210184536996)
当主机把总线从高电平拉低,并保持至少1us后释放总线;并在15us内读取从DS18B20输出的数据。
4.DS18B20的ROM操作命令
用途:主要是用于选定在单总线上的DS18B20,分为5个命令
(1).读出ROM,代码为33H,用于读出DS18B20的序列号,即64位激光ROM代码。
(2).匹配ROM,代码为55H,用于识别(或选中)某一特定的DS18B20进行操作。
(3).搜索ROM,代码为F0H,用于确定总线上的节点数以及所有节点的序列号。
(4).跳过ROM,代码为CCH,当总线仅有一个DS18B20时,不需要匹配 。
(5).报警搜索,代码为ECH,主要用于鉴别和定位系统中超出程序设定的报警温度界限的节点。
单片机:STC15
竞赛给出的驱动
18B20.C文件
/*
????: ???????
????: Keil uVision 4.10
????: CT107?????????
? ?: 2011-8-9
*/
#include "onewire.h"
//???????
void Delay_OneWire(unsigned int t)
{
unsigned char i;
while(t--)
for(i=0;i<12;i++);//此处是驱动有问题,所以需要进行修改
}
//DS18B20?????
bit Init_DS18B20(void)
{
bit initflag = 0;
DQ = 1;
Delay_OneWire(12);
DQ = 0;
Delay_OneWire(80);
DQ = 1;
Delay_OneWire(10);
initflag = DQ;
Delay_OneWire(5);
return initflag;
}
//??????DS18B20?????
void Write_DS18B20(unsigned char dat)
{
unsigned char i;
for(i=0;i<8;i++)
{
DQ = 0;
DQ = dat&0x01;
Delay_OneWire(5);
DQ = 1;
dat >>= 1;
}
Delay_OneWire(5);
}
//?DS18B20??????
unsigned char Read_DS18B20(void)
{
unsigned char i;
unsigned char dat;
for(i=0;i<8;i++)
{
DQ = 0;
dat >>= 1;
DQ = 1;
if(DQ)
{
dat |= 0x80;
}
Delay_OneWire(5);
}
return dat;
}
Main.c文件
#include "onewire.h"
#include "absacc.h"
#define uchar unsigned char
#define uint unsigned int
code unsigned char duan[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
code unsigned char wei[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};
uchar dis[4];
uint value;
void delay(unsigned int x)
{
unsigned int y;
for(x;x>0;x--)
for(y=110;y>0;y--);
}
uint Get_Temp(void)//温度是由两个字节构成的返回值必须是uint型(PS:关于int型的范围,由具体的编译器决定,keil中51系列对应2字节16位,MDK对应的4字节32位)
{
uint temp=0;//与返回值定义的一样
uchar LS,MS;
Init_DS18B20();
Write_DS18B20(0xcc);//跳过ROM
Write_DS18B20(0x44);//启动转换
Init_DS18B20();
Write_DS18B20(0xcc);
Write_DS18B20(0xbe);//读取温度
LS=Read_DS18B20();
MS=Read_DS18B20();
temp=(MS<<8)|LS;
return temp;
}
uint Temp_Change(void)
{
uint t;
float tp;//此处非常重要,用浮点型来存放十进制的温度
t=Get_Temp();
if(t<0) //考虑温度为负,用减一取反
{
t=~(t-1);
tp=t*0.0625; //16??????10?????
t=tp*100+0.5; //
}
else
{
tp=t*0.0625; //转换公式 精度0.0625
t=tp*100+0.5; //例如温度为12.654*100+0.5 =1265.9 四省五入
}
return t;
}
void Display(void)
{
uchar i;
dis[0]=duan[value/1000];
dis[1]=duan[value%1000/100]|0x80;
dis[2]=duan[value%100/10];
dis[3]=duan[value%10];
for(i=0;i<4;i++)
{
XBYTE[0xE000]=~dis[i];
XBYTE[0xC000]=~wei[i];
delay(1);
XBYTE[0xC000]=~0xff;
}
}
void Cls_LED()
{
XBYTE[0x8000]=0xff;
}
void Cls_Buzz(void)
{
XBYTE[0xA000]=0x00;
}
void main(void)
{
Cls_Buzz();
Cls_LED();
while(1)
{
value=Temp_Change();
Display();
}
}
一.DS18B20温度传感器
1.引脚图2.DS18B20内部结构图
主要由2部分组成:64位ROM、9字节暂存器,如图所示。
(1) 64 位ROM。它的内容是64 位序列号,它可以被看作是该DS18B20 的地址序列码,其作用是使每个DS18B20 都各不相同,这样就可以实现一根总线上挂接多个DS18B20 的目的。
(2) 9字节暂存器包含:温度传感器、上限触发TH高温报警器、下限触发TL低温报警器、高速暂存器、8位CRC产生器。
3.64位ROM结构图
8位CRC:是单总线系列器件的编码,DS18B20定义为28H。
48位序列号:是一个唯一的序列号。
8位系列码:由CRC产生器生产,作为ROM中的前56位编码的校验码。
4.9字节暂存器结构图
以上是内部9 个字节的暂存单元(包括EEPROM)。
字节0~1 是温度存储器,用来存储转换好的温度。
字节2~3 是用户用来设置最高报警和最低报警值。这个可以用软件来实现。
字节4 是配置寄存器,用来配置转换精度,让它工作在9~12 位。
字节5~7 保留位。
字节8 CRC校验位。是64位ROM中的前56位编码的校验码。由CRC发生器产生。
5.温度寄存器结构图
温度寄存器由两个字节组成,分为低8位和高8位。一共16位。
其中,第0位到第3位,存储的是温度值的小数部分。
第4位到第10位存储的是温度值的整数部分。
第11位到第15位为符号位。全0表示是正温度,全1表示是负温度。
表格中的数值,如果相应的位为1,表示存在。如果相应的位为0,表示不存在。
6.配置寄存器
精度值:
9-bit 0.5℃
10-bit 0.25℃
11-bit 0.125℃
12-bit 0.0625℃
7.温度/数据关系
注意:如果温度是一个负温度,要将读到的数据减一再取反
二.单总线协议
1.单总线通信初始化初始化时序包括:主机发出的复位脉冲和从机发出的应答脉冲。主机通过拉低单总线480-960μs产生复位脉冲;然后由主机释放总线,并进入接收模式。主机释放总线时,会产生一由低电平跳变为高电平的上升沿,单总线器件检测到该上升沿后,延时15~60μs,接着单总线器件通过拉低总线60~240μsμ来产生应答脉冲。主机接收到从机的以应答脉冲后,说明有单总线器件在线,到此初始化完成。然后主机就可以开始对从机进行ROM命令和功能命令操作。
2.位写入时序
写时隙:当主机把数据线从逻辑高电平拉到逻辑低电平的时候,写时间隙开始。有两种写时间隙:写1的时间隙和写0时间隙。所有写时间隙必须最少持续60us,包括两个写周期间至少1us的恢复时间。DQ引脚上的电平变低后,DS18B20在一个15us到60us的时间窗口内对DQ引脚采样。如果DQ引脚是高电平,就是写1,如果DQ引脚是低电平,就是写0。主机要生成一个写1时间隙,必须把数据线拉到低电平然后释放,在写时间隙开始后的15us内允许数据线拉到高电平。主机要生成一个写0时间隙,必须把数据线拉到低电平并保持60us。
3.位读取时序
当主机把总线从高电平拉低,并保持至少1us后释放总线;并在15us内读取从DS18B20输出的数据。
4.DS18B20的ROM操作命令
用途:主要是用于选定在单总线上的DS18B20,分为5个命令
(1).读出ROM,代码为33H,用于读出DS18B20的序列号,即64位激光ROM代码。
(2).匹配ROM,代码为55H,用于识别(或选中)某一特定的DS18B20进行操作。
(3).搜索ROM,代码为F0H,用于确定总线上的节点数以及所有节点的序列号。
(4).跳过ROM,代码为CCH,当总线仅有一个DS18B20时,不需要匹配 。
(5).报警搜索,代码为ECH,主要用于鉴别和定位系统中超出程序设定的报警温度界限的节点。
三.驱动程序
单片机:STC15竞赛给出的驱动
18B20.C文件
/*
????: ???????
????: Keil uVision 4.10
????: CT107?????????
? ?: 2011-8-9
*/
#include "onewire.h"
//???????
void Delay_OneWire(unsigned int t)
{
unsigned char i;
while(t--)
for(i=0;i<12;i++);//此处是驱动有问题,所以需要进行修改
}
//DS18B20?????
bit Init_DS18B20(void)
{
bit initflag = 0;
DQ = 1;
Delay_OneWire(12);
DQ = 0;
Delay_OneWire(80);
DQ = 1;
Delay_OneWire(10);
initflag = DQ;
Delay_OneWire(5);
return initflag;
}
//??????DS18B20?????
void Write_DS18B20(unsigned char dat)
{
unsigned char i;
for(i=0;i<8;i++)
{
DQ = 0;
DQ = dat&0x01;
Delay_OneWire(5);
DQ = 1;
dat >>= 1;
}
Delay_OneWire(5);
}
//?DS18B20??????
unsigned char Read_DS18B20(void)
{
unsigned char i;
unsigned char dat;
for(i=0;i<8;i++)
{
DQ = 0;
dat >>= 1;
DQ = 1;
if(DQ)
{
dat |= 0x80;
}
Delay_OneWire(5);
}
return dat;
}
Main.c文件
#include "onewire.h"
#include "absacc.h"
#define uchar unsigned char
#define uint unsigned int
code unsigned char duan[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
code unsigned char wei[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};
uchar dis[4];
uint value;
void delay(unsigned int x)
{
unsigned int y;
for(x;x>0;x--)
for(y=110;y>0;y--);
}
uint Get_Temp(void)//温度是由两个字节构成的返回值必须是uint型(PS:关于int型的范围,由具体的编译器决定,keil中51系列对应2字节16位,MDK对应的4字节32位)
{
uint temp=0;//与返回值定义的一样
uchar LS,MS;
Init_DS18B20();
Write_DS18B20(0xcc);//跳过ROM
Write_DS18B20(0x44);//启动转换
Init_DS18B20();
Write_DS18B20(0xcc);
Write_DS18B20(0xbe);//读取温度
LS=Read_DS18B20();
MS=Read_DS18B20();
temp=(MS<<8)|LS;
return temp;
}
uint Temp_Change(void)
{
uint t;
float tp;//此处非常重要,用浮点型来存放十进制的温度
t=Get_Temp();
if(t<0) //考虑温度为负,用减一取反
{
t=~(t-1);
tp=t*0.0625; //16??????10?????
t=tp*100+0.5; //
}
else
{
tp=t*0.0625; //转换公式 精度0.0625
t=tp*100+0.5; //例如温度为12.654*100+0.5 =1265.9 四省五入
}
return t;
}
void Display(void)
{
uchar i;
dis[0]=duan[value/1000];
dis[1]=duan[value%1000/100]|0x80;
dis[2]=duan[value%100/10];
dis[3]=duan[value%10];
for(i=0;i<4;i++)
{
XBYTE[0xE000]=~dis[i];
XBYTE[0xC000]=~wei[i];
delay(1);
XBYTE[0xC000]=~0xff;
}
}
void Cls_LED()
{
XBYTE[0x8000]=0xff;
}
void Cls_Buzz(void)
{
XBYTE[0xA000]=0x00;
}
void main(void)
{
Cls_Buzz();
Cls_LED();
while(1)
{
value=Temp_Change();
Display();
}
}
相关文章推荐
- C语言实现非循环双链表节点的删除(带头结点尾结点)
- iOS缓存
- MySQL与JDBC连接
- UITableView或UIScrollView的content截屏
- 在SSIS包中使用 Checkpoint从失败处重新启动包[转]
- 谈谈程序员的职业方向
- Install sharelatex on virtual machine
- 解析几何:第三章 平面上的直线
- C++中的四种转型操作符
- ArrayList扩容问题
- eclipse找不到jdk来运行
- [.Net码农]C#操作Access的一些小结
- VS2010 C#创建和发布ActiveX控件
- iOS之手动内存管理
- 解析几何:第二章 解析几何中的基本计算公式
- 86. Partition List
- 插入排序(解析及代码实现 二分优化)
- CentOS环境下,gdb调试中出现:Missing separate debuginfos, use: debuginfo-install.....的问题
- 如何保留HTML中的空格
- 博客怎么写