DS18B20单总线协议
单片机课设
题目是DS18B20的通信,用CH452搭配数码管显示。DS18B20最主要的是单总线协议,这个我之前没有接触过。上来只好老老实实的看数据手册。
对于DS18B20来说,有下面的这些特点:
( 1 )采用单总线的接口方式 与微处理器连接时仅需要一条口线即可实现微处理器与 DS18B20 的双向通讯。单总线具有经济性好,抗干扰能力强,适合于恶劣环境的现场温度测量,使用方便等优点,使用户可轻松地组建传感器网络,为测量系统的构建引入全新概念。
( 2 )测量温度范围宽,测量精度高 DS18B20 的测量范围为 -55 ℃ ~+ 125 ℃ ; 在 -10~+ 85°C范围内,精度为 ± 0.5°C 。
( 3 )在使用中不需要任何外围元件。
( 4 )持多点组网功能 多个 DS18B20 可以并联在惟一的单线上,实现多点测温。
( 5 )供电方式灵活 DS18B20 可以通过内部寄生电路从数据线上获取电源。因此,当数据线上的时序满足一定的要求时,可以不接外部电源,从而使系统结构更趋简单,可靠性更高。
( 6 )测量参数可配置 DS18B20 的测量分辨率可通过程序设定 9~12 位。
( 7 ) 负压特性电源极性接反时,温度计不会因发热而烧毁,但不能正常工作。
( 8 )掉电保护功能 DS18B20 内部含有 EEPROM ,在系统掉电以后,它仍可保存分辨率及报警温度的设定值。
这里面需要注意的主要是内部的寄生电路,这个电路可以不接电源来实现工作。但是转换温度的时间会增加。在老师给我们的板子上接了电源。同时也给信号端口接了上拉电阻。所以也是在程序上简化了一些。
下面来一一介绍DS18B20的工作通信协议、DS18B20的配置以及CH452的显示部分。
DS18B20的工作通信协议:
DS18B20是单总线协议,结构上的简单一定会导致时序上的复杂。在时序上要求严格按照数据手册上面的要求来完成。对于每
一次的写命令来说都要按照下面的步骤来执行:
即 初始化命令——>Rom命令——>函数命令(主要是温度转换)之所以把这个写在前面,是因为这个非常的重要而且很容易被忽视。在自己写初步的程序的时候,一直没有正常的通讯。看了别人的程序才恍然大悟。主要是一开始这个步骤忽略了。介绍完了命令的步骤。下面开始说明初始化,写0 、写1和读0、读1这几步。
(初始化时序)
(读写1 0)
这里的话没有什么好说的,需要注意的主要是三点:(1)注意时序的要求,不同的单片机延时也不一样,我用的是STC15的和89的就不同。(2)注意释放总线 (3)可以利用初始化后面的应答信号确定是否响应,有时候会用到。
DS18B20的配置:
DS18B20内部有48位的唯一ID,这个ID在只有一个芯片的时候没有什么用。但是要是实现多个DS18B20挂载在一个总线的时候这个是不可缺少的。所以我们首先要读出来这个ID。ID可以通过CRC校验确定是否正确。
我读出的芯片ID是{0x28,0x79,0xA9,0xE6,0x05,0x00,0x00,0xA5}和{0x28,0xd8,0x60,0xc0,0x06,0x00,0x00,0x82}这样就通过不同的ID来确定不同新片了。
uchar CRC8()
{ uchar i,x; uchar crcbuff;crc=0;for(x = 0; x <8; x++){crcbuff=fCode[x];for(i = 0; i < 8; i++) { if(((crc ^ crcbuff)&0x01)==0) crc >>= 1; else { crc ^= 0x18; //CRC=X8+X5+X4+1crc >>= 1; crc |= 0x80; } crcbuff >>= 1; }}return crc;
}
(CRC校验程序)
CH452的显示部分:
CH452是键盘扫描和显示芯片。我参照的是官方的例程,(ˇˍˇ) 向里面写数据就可自动的实现显示和键盘读写。下面贴出原理图
最后给出源程序,希望有借鉴的价值。
#include<reg52.h>
#include "intrins.h"
#define uchar unsigned char
#define uint unsigned int
#define FOSC 11059200L //系统频率
#define BAUD 115200 //串口波特率
//命令定义
#define CH452_NOP 0x0000 // 空操作
#define CH452_RESET 0x0201 // 复位
#define CH452_LEVEL 0x0100 // 加载光柱值,需另加7位数据
#define CH452_CLR_BIT 0x0180 // 段位清0,需另加6位数据
#define CH452_SET_BIT 0x01C0 // 段位置1,需另加6位数据
#define CH452_SLEEP 0x0202 // 进入睡眠状态
#define CH452_LEFTMOV 0x0300 // 设置移动方式-左移
#define CH452_LEFTCYC 0x0301 // 设置移动方式-左循环
#define CH452_RIGHTMOV 0x0302 // 设置移动方式-右移
#define CH452_RIGHTCYC 0x0303 // 设置移动方式-右循环
#define CH452_SELF_BCD 0x0380 // 自定义BCD码,需另加7位数据
#define CH452_SYSOFF 0x0400 // 关闭显示、关闭键盘
#define CH452_SYSON1 0x0401 // 开启显示
#define CH452_SYSON2 0x0403 // 开启显示、键盘
#define CH452_SYSON2W 0x0423 // 开启显示、键盘, 真正2线接口
#define CH452_NO_BCD 0x0500 // 设置默认显示方式,可另加3位扫描极限
#define CH452_BCD 0x0580 // 设置BCD译码方式,可另加3位扫描极限
#define CH452_TWINKLE 0x0600 // 设置闪烁控制,需另加8位数据
#define CH452_GET_KEY 0x0700 // 获取按键,返回按键代码
#define CH452_DIG0 0x0800 // 数码管位0显示,需另加8位数据
#define CH452_DIG1 0x0900 // 数码管位1显示,需另加8位数据
#define CH452_DIG2 0x0a00 // 数码管位2显示,需另加8位数据
#define CH452_DIG3 0x0b00 // 数码管位3显示,需另加8位数据
#define CH452_DIG4 0x0c00 // 数码管位4显示,需另加8位数据
#define CH452_DIG5 0x0d00 // 数码管位5显示,需另加8位数据
#define CH452_DIG6 0x0e00 // 数码管位6显示,需另加8位数据
#define CH452_DIG7 0x0f00 // 数码管位7显示,需另加8位数据
#define RADIX 0x02 //小数点
// 显示部分引脚定义
sbit din = P2^6; // 串行数据输出,接CH451的数据输入
sbit load=P3^3; //串行命令加载,上升延激活
sbit dout=P2^7; //INT1,键盘中断和键值数据输入,接CH451的数据输出
sbit dclk = P2^5;
sbit DS=P1^3; //define interface
sbit beep = P1^7;
sfr AUXR = 0x8e; //辅助寄存器 //串行数据时钟上升延激活
unsigned char code number[]={0xbd,0x18,0xd5,0xd9,0x78,0xe9,0xed,0x98,0xfd,0xf9};
uchar i,j,cmd1,keycode;
uint temp; // variable of temperature
uint temped; // 源码
uchar flag1; // sign of the result positive or negative
uchar flag_key;
uchar ch451_key;
uchar flag_wendu;
uint cmd;
bit busy;
bit presence;
unsigned char crc;
uchar fCode[8]; //序列号数组
uchar DSrom1[8]={0x28,0x79,0xA9,0xE6,0x05,0x00,0x00,0xA5}; //板子上的 //2个器件每个64位序列号
uchar DSrom2[8]={0x28,0xd8,0x60,0xc0,0x06,0x00,0x00,0x82}; //ROM1 //2个器件每个64位序列号
uint f[2]; //温度数组
uint e[2]; //原温度数组
void CH452_Write(unsigned short cmd); // ch452写程序
void CH452_Read(void); // ch452读程序
void Delay500us(); //延时
void Delay30us(); //延时
void Delay240us(); //延时
void Delay5us(); //延时
void Delay60us(); //延时
void Delay2us(); //延时
void Delay1000us(); //延时
void Delay100ms(); //延时
void Delay80us();
void Delay20us();
void Delay1ms();
void delay_b20(uint n); //单片机定时1us 不准!!!!!!
void uartinit(void); //串口初始化
void SendData(uint dat); //发送数据
void SendString(char *s); //发送字符串
void dsreset(void); // Ds1820初始化
bit tmpreadbit(void); //read a bit
uchar tmpread(void); //read a byte date
void tmpwritebyte(uchar dat); //write a byte to ds18b20
void tmpchange(void); //DS18B20 begin change
void display(uint temp); //显示程序
void exti1init ();
void DispCode(); // 读序列号
void read_dealtemp0(); // 读多个温度
void read_dealtemp1(); //读取温度
uchar CRC8() ;
void delay_b20(uint n)//STC12C5A单片机定时1us
{ while(n--){_nop_();}
}
void exti1init (){INT0 = 1;IT0 = 1; //设置INT0的中断类型 (1:仅下降沿 0:上升沿和下降沿)EX0 = 1; //使能INT0中断EA = 1;
}
void display(uint temp) //显示程序
{uchar A1,A2,A3,A4;A1 = temp/1000;A2 = temp % 1000 / 100;A3 = temp % 100 / 10;A4 = temp % 10;CH452_Write(CH452_DIG4 | number[ A1 ]);CH452_Write(CH452_DIG5 | number[ A2]|RADIX);CH452_Write(CH452_DIG6 | number[A3]);CH452_Write(CH452_DIG7 | number[A4]);
}
void tmpchange(void) //DS18B20 begin change
{dsreset();Delay240us();tmpwritebyte(0xcc); // 跳过ROM tmpwritebyte(0x44); // initiates a single temperature conversion
}/*
响应多个温度 首先是复位 然后ROM 接着RAm最后计算
*/
void read_dealtemp0(){ //读多个温度uchar i,j; uchar a,b;float tt; j = 0;dsreset();Delay240us() ;tmpwritebyte(0x55); //输入序列号for(i=0;i<8;i++) { tmpwritebyte(DSrom1[i]);//发送64位序列号 } tmpwritebyte(0xbe);a=tmpread();b=tmpread();temp=b;temp<<=8; //two byte compose a int variabletemp=temp|a;temped=temp; // 源码tt=temp*0.0625; temp=tt*100+0.5;f[j]=temp;e[j]=temped;Delay100ms();}
void read_dealtemp1(){ //读多个温度uchar i,j; uchar a,b;float tt; j = 1;dsreset();Delay240us() ;tmpwritebyte(0x55); //输入序列号for(i=0;i<8;i++) { tmpwritebyte(DSrom2[i]);//发送64位序列号 } tmpwritebyte(0xbe);a=tmpread();b=tmpread();temp=b;temp<<=8; //two byte compose a int variabletemp=temp|a;temped=temp; // 源码tt=temp*0.0625; temp=tt*100+0.5;f[j]=temp;e[j]=temped;Delay100ms();}
uint tmp() //get the temperature
{float tt;uchar a,b;dsreset();Delay240us() ;tmpwritebyte(0xcc);tmpwritebyte(0xbe);a=tmpread();b=tmpread();temp=b;temp<<=8; //two byte compose a int variabletemp=temp|a;temped=temp; // 源码tt=temp*0.0625; temp=tt*100+0.5;return temp; // 转换的温度
}
void tmpwritebyte(uchar dat) //write a byte to ds18b20
{uchar j;bit testb;for(j=1;j<=8;j++){testb=dat&0x01;dat=dat>>1;if(testb) //write 1{DS=0;Delay5us();DS=1;Delay60us();}else{DS=0; //write 0Delay60us();DS=1;Delay5us();}}
}
void DispCode()//读取序列号
{ uchar i; dsreset(); tmpwritebyte(0x33); for (i=0;i<8;i++) {fCode[i]=tmpread(); }
}
uchar tmpread(void) //read a byte date
{uchar i,j,dat;dat=0;for(i=1;i<=8;i++){j=tmpreadbit();dat=(j<<7)|(dat>>1); //读出的数据最低位在最前面,这样刚好一个字节在DAT里}return(dat);
}
bit tmpreadbit(void) //read a bit
{bit dat;DS=0;//i++ for delayDelay2us();DS=1;Delay2us();dat=DS;Delay60us();return (dat);
}
void dsreset(void) //send reset and initialization command
{DS = 1; //DQ复位 Delay2us();//延时 DS = 0; //DQ拉低 Delay500us(); //精确延时大于480us DS = 1; //拉高 Delay30us(); presence = DS;Delay60us();DS = 1;
}void SendString(char *s)
{while (*s) //检测字符串结束标志{SendData(*s++); //发送当前字符}
}
void SendData(uint dat)
{while (busy); //等待前面的数据发送完成busy = 1;SBUF = dat; //写数据到UART数据寄存器
}
void uartinit(void){SCON = 0x50; //8位可变波特率AUXR = 0x40; //定时器1为1T模式TMOD = 0x20; //定时器1为模式2(8位自动重载)TL1 = (256 - (FOSC/32/BAUD)); //设置波特率重装值TH1 = (256 - (FOSC/32/BAUD));TR1 = 1; //定时器1开始工作ES = 1; //使能串口中断EA = 1;
}
void Delay1ms() //@11.0592MHz
{unsigned char i, j;_nop_();_nop_();_nop_();i = 11;j = 190;do{while (--j);} while (--i);
}void Delay100ms() //@11.0592MHz
{unsigned char i, j, k;_nop_();_nop_();i = 5;j = 52;k = 195;do{do{while (--k);} while (--j);} while (--i);
}
void Delay20us() //@11.0592MHz
{unsigned char i;_nop_();_nop_();_nop_();i = 52;while (--i);
}
void Delay80us() //@11.0592MHz
{unsigned char i, j;_nop_();i = 1;j = 217;do{while (--j);} while (--i);
}
void Delay1000us() //@11.0592MHz
{unsigned char i, j;_nop_();_nop_();_nop_();i = 11;j = 190;do{while (--j);} while (--i);
}
void Delay2us() //@11.0592MHz
{unsigned char i;i = 3;while (--i);
}
void Delay60us() //@11.0592MHz
{unsigned char i, j;i = 1;j = 162;do{while (--j);} while (--i);
}
void Delay5us() //@11.0592MHz
{unsigned char i;_nop_();i = 11;while (--i);
}
void Delay240us() //@11.0592MHz
{unsigned char i, j;_nop_();_nop_();i = 3;j = 145;do{while (--j);} while (--i);
}
void Delay500us() //@11.0592MHz
{unsigned char i, j;_nop_();_nop_();i = 6;j = 93;do{while (--j);} while (--i);
}
void Delay30us() //@11.0592MHz
{unsigned char i;_nop_();_nop_();i = 80;while (--i);
}
uchar CRC8()
{ uchar i,x; uchar crcbuff;crc=0;for(x = 0; x <8; x++){crcbuff=fCode[x];for(i = 0; i < 8; i++) { if(((crc ^ crcbuff)&0x01)==0) crc >>= 1; else { crc ^= 0x18; //CRC=X8+X5+X4+1crc >>= 1; crc |= 0x80; } crcbuff >>= 1; }}return crc;
}
void CH452_Write(unsigned short cmd){load=0; //命令开始,LOAD=0for(i=0;i!=12;i++) //送入12位数据,低位在前{dclk=0;din=cmd&1;dclk=1; //上升沿有效cmd=cmd>>1;}load=1; //加载数据,LOAD上升沿}
void CH452_Read(void){cmd1=0x07; //读按键的命令字load=0;for(i=0;i!=4;i++) // 只需要发出高4位,多发也可以,但应该确保最后留下的4位是该命令码{din=cmd1&1;dclk=0;cmd1>>=1; //往右移一位dclk=1; //产生时钟上升沿锁通知CH451输入位数据}load=1; //产生加载上升沿通知CH451处理命令数据for(j=0;j<100;j++){ }keycode=0; //清除keycodefor(i=0;i!=7;i++){keycode<<=1; //数据移入keycode,高位在前,低位在后if (dout){ keycode++;} //从高到低读入451的数据// keycode|=CH452_DOUT;dclk=0; //产生时钟下升沿通知CH451输出下一位dclk=1;}}
//中断服务程序
void exint0() interrupt 0 //INT0中断入口{}
/*----------------------------
UART 中断服务程序
-----------------------------*/
void Uart() interrupt 4 using 1{if (RI){RI = 0; //清除RI位}if (TI){TI = 0; //清除TI位busy = 0; //清忙标志}}
void main(void){uchar path1;path1 = 0; CH452_Write(CH452_RESET);CH452_Write(CH452_SYSON2); //CH452初始化 flag_wendu=1; // 显示温度标记// presence =0; // 响应信号 0是OK// DispCode(); //读序列号 读的时候只能是单线的操作// CRC8(); //校验crc, 0 是ok
while (1){CH452_Read();if (keycode==0x44){path1 =0 ;beep=0;Delay100ms();beep=1;}if (keycode==0x45){path1 =1; beep=0;Delay100ms();beep=1;}if (keycode==0x46){path1 =2; beep=0;Delay100ms();beep=1;}if (keycode==0x47){path1 =3; beep=0;Delay100ms();beep=1;}keycode=0;switch(path1) {case 0: display(f[0]); break;case 1: display(e[0]); break;case 2: display(f[1]); break;case 3: display(e[1]); break;}tmpchange();//初始化 read_dealtemp0();//读取温度tmpchange();//初始化 read_dealtemp1();//读取温度
}
}
DS18B20单总线协议相关推荐
- DS18B20数字温度传感器及单总线协议规定
1,DS18B20数字温度传感器的主要特点 通信采用1-Wire接口 每个DS18B20都有唯一的64位序列码储存在板载ROM中 无需外部元件 可从数据线供电,电源范围为3.0V ~ 5.5V. 可测 ...
- [stc89c52] DS18B20基于单总线协议的温度测量
一.单总线协议(1-wire) 1.定义:主机和从机用一根总线进行通信,是一种半双工的通信方式,单线=时钟线+数据线+控制线( +电源线).理想状况下一条总线上的从器件数量几乎不受数量限制. 2.特点 ...
- 解析单总线协议(1-wire)
一.单总线协议(1-wire) 1.定义:主机和从机通过1根线进行通信,在一条总线上可挂接的从器件数量几乎不受限制. 2.特点:这是由达拉斯半导体公司推出的一项通信技术.它采用单根信号线,既可传输时钟 ...
- 单总线协议(1—wire)
一.单总线协议(1-wire) 1.定义:主机和从机通过1根线进行通信,在一条总线上可挂接的从器件数量几乎不受限制. 2.特点:这是由达拉斯半导体公司推出的一项通信技术.它采用单根信号线,既可传输时钟 ...
- 一文看懂单总线协议(1-wire)
文章目录 一.什么是单总线协议? 1.单总线协议概念及特点 2.硬件结构 3.单总线协议应用 二.单总线协议时序(以DS18B20为例) 1.初始化(复位脉冲 + 存在脉冲) 2.读/写时序 (1)写 ...
- 《嵌入式 - 嵌入式大杂烩》深入理解单总线协议
1单总线简介 目前常用的微机与外设之间进行数据传输的串行总线主要有I2C总线.SPI总线和SCI总线.其中I2C总线以同步串行2线方式进行通信(一条时钟线,一条数据线),SPI总线则以同步串行3线方式 ...
- 通信协议--单总线协议
文章目录 一.单总线简介 二.单总线协议 单总线初始化 单总线写入 单总线读取 DS18B20用法 读取温度(仅仅包含整数部分) 读取温度(含小数部分) 一.单总线简介 1.定义:主机和从机通过1根线 ...
- 【51单片机快速入门指南】6.3:DS18B20 单总线数字温度计的多路读取
目录 硬知识 DS18B20介绍 时序 初始化时序 写时序 读时序 命令 ROM 操作命令 ROM 搜索举例 存贮器操作命令 示例程序 DS18B20.c DS18B20.h 测试程序 定时器中断服务 ...
- 蓝桥杯单片机DS18b20单总线测温模块常见问题解决
蓝桥杯单片机DS18b20单总线测温模块常见问题解决 有道是:"溪水声声留我住,梅花朵朵唤人回" DS18b20测温模块作为一个比较简单.稳定的蓝桥杯单片机外设模块, 使用时却经常 ...
- 单总线协议-以DS18B20举例
一.概述 1-wire 单总线是Maxim 全资子公司 Dallas 的一项专有技术.与目前多数标准串行数据通信方式,如SPI/I2C/MICROWIRE 不同,它采用单根信号线,既传输时钟,又传输数 ...
最新文章
- java中关键字volatile的作用(转载)
- Linux文件权限符号含义
- wukong引擎源码分析之索引——part 3 文档评分 无非就是将docid对应的fields信息存储起来,为搜索结果rank评分用...
- Python数据分析,抓取京东商品价格
- pc调试微信h5页面
- 退出循环:break 跳过当前的这次循环,直接开始下一次循环:continue
- 基于Unity的阿里云短信SDK接入流程
- 深度森林实现时间序列预测(Python)
- html 长度vm,css vm是什么单位?
- 基于MATLAB的疲劳检测系统研究解析
- 数据治理之IT系统存量信息梳理
- 【Python 爬虫实践】:《战狼2》豆瓣影评分析
- “千亿市值”巨无霸的膨胀 腾讯靠什么撬动下一个1000亿美金?
- 美国签证和加拿大签证申请及自驾游攻略合辑
- python excel单元格 剪切清除粘贴复制_Excel复制粘贴时弹出“不能清除剪贴板”的解决方法...
- 电路硬件设计——PCB布局和布线
- 《BREW进阶与精通——3G移动增值业务的运营、定制与开发》连载之11---什么是BREW
- 三自由度机器人运动学matlab仿真实验报告,3自由度机器人的正运动学建模研究...
- Uni-app 课程详情页 获取课程详情 + 收藏 + 加入购物车
- 计算机控制技术实验报告pid,东南大学计算机控制技术实验报告二.docx