DS18B20程序及初始化.
- 格式:pdf
- 大小:319.05 KB
- 文档页数:16
ds18b20c语言程序DS18B20驱动程序(C语言)//#include"reg51.h"sbit DQ =P1^4; //定义通信端口//延时函数/*void delay(unsigned inti){while(i--);}*///初始化函数Init_DS18B20(void){unsigned char x=0;DQ = 1; //DQ 复位delay(8); //稍做延时DQ = 0; //单片机将DQ拉低delay(80); //精确延时大于 480usDQ = 1; //拉高总线delay(14);x=DQ; //稍做延时后如果x=0则初始化成功x=1则初始化失败delay(20);}//读一个字节ReadOneChar(void){unsigned chari=0;unsigned char dat = 0;for (i=8;i>;0;i--){DQ = 0; // 给脉冲信号dat>;>;=1;DQ = 1; // 给脉冲信号if(DQ)dat|=0x80;delay(4);}return(dat);}//写一个字节WriteOneChar(unsigned chardat){unsigned char i=0;for (i=8; i>;0; i--){DQ = 0;DQ = dat&0x01;delay(5);DQ =1;dat>;>;=1;}//delay(4);}//DS18B20程序读取温度ReadTemperature(void){unsigned char a=0;unsignedchar b=0;unsigned int t=0;floattt=0;Init_DS18B20();WriteOneChar(0xCC); // 跳过读序号列号的操作WriteOneChar(0x44); // 启动温度转换Init_DS18B20();WriteOneChar(0xCC); //跳过读序号列号的操作WriteOneChar(0xBE); //读取温度寄存器等(共可读9个寄存器)前两个就是温度a=ReadOneChar();b=ReadOneChar();t=b;t<<=8;t=t|a;t t=t*0.0625;//t= tt*10+0.5; //放大10倍输出并四舍五入---此行没用return(t);}//DS18B20主程序main(){unsigned chari=0;while(1){i=ReadTemperature();//读温度}}ds18b20c语言程序完毕。
#include <reg52.h>#define uchar unsigned char#define uint unsigned int/********************************************************************/ sbit DQ = P2^2; //温度传感器信号线sbit rs = P3^5; //LCD数据/命令选择端(H/L)位声明sbit lcden = P3^4; //LCD使能信号端位声明/********************************************************************/ //uint temp; //定义整型的温度数据//float f_temp; //定义浮点型的温度数据//uint warn_11 = 270; //定义温度设定值,是温度值乘以10后的结果//uint warn_12 = 250; //定义温度下限值//uint warn_h1 = 300; //定义温度上限值/********************************************************************/ void delay(uint z); //延时函数void DS18B20_Reset(void); //DQ18B20复位,初始化函数bit DS18B20_Readbit(void); //读1位数据函数uchar DS18B20_ReadByte(void); //读1个字节数据函数void DS18B20_WriteByte(uchar dat); //向DQ18B20写一个字节数据函数void LCD_WriteCom(uchar com); //1602液晶命令写入函数void LCD_WriteData(uchar dat); //1602液晶数据写入函数void LCD_Init(); //LCD初始化函数void Display18B20Rom(char Rom); //显示18B20序列号函数/**********************************************//* 主函数 *//**********************************************/void main(){ uchar a,b,c,d,e,f,g,h;LCD_Init();DS18B20_Reset();delay(1);DS18B20_WriteByte(0x33);delay(1);a = DS18B20_ReadByte();b = DS18B20_ReadByte();c = DS18B20_ReadByte();d = DS18B20_ReadByte();e = DS18B20_ReadByte();f = DS18B20_ReadByte();g = DS18B20_ReadByte();h = DS18B20_ReadByte();LCD_WriteCom(0x80+0x40);Display18B20Rom(h);Display18B20Rom(g);Display18B20Rom(f);Display18B20Rom(e);Display18B20Rom(d);Display18B20Rom(c);Display18B20Rom(b);Display18B20Rom(a);while(1);}/***************************************************//* 延时函数:void delay() *//* 功能:延时函数 *//***************************************************/void delay(uint z)//延时函数{uint x,y;for( x = z; x > 0; x-- )for( y = 110; y > 0; y-- );}/***************************************************//* DS18B20函数:void DS18B20_Reset() *//* 功能:复位18B20 */ /***************************************************/void DS18B20_Reset(void)//DQ18B20复位,初始化函数{uint i;DQ = 0;i = 103;while( i > 0 ) i--;DQ = 1;i = 4;while( i > 0 ) i--;}/***************************************************//* DS18B20函数:void DS18B20_Readbit() *//* 功能:读1个字节数据函数 *//***************************************************/bit DS18B20_Readbit(void) //读1位数据函数{uint i;bit dat;DQ = 0;i++; //i++起延时作用DQ = 1;i++;i++;dat = DQ;i = 8;while( i > 0 )i--;return( dat );}/***************************************************//* DS18B20函数:void DS18B20_ReadByte() *//* 功能:读1个字节数据函数 */ /***************************************************/uchar DS18B20_ReadByte(void) //读1个字节数据函数{uchar i,j,dat;dat = 0;for( i = 1; i <= 8; i++ ){j = DS18B20_Readbit();dat = ( j << 7 ) | ( dat >> 1 );}return(dat);}/***************************************************//* DS18B20函数:void DS18B20_WriteByte() *//* 功能:向DQ18B20写一个字节数据函数 *//***************************************************/void DS18B20_WriteByte(uchar dat) //向DQ18B20写一个字节数据函数{uint i;uchar j;bit testb;for( j=1; j<=8; j++){testb = dat&0x01;dat= dat>>1;if(testb) //写1{DQ = 0;i++;i++;DQ = 1;i = 8;while(i>0)i--;}else{DQ = 0; //写0i = 8;while(i>0)i--;DQ = 1;i++;i++;}}}/***********************************************//* LCD函数:void LCD_WriteCom() *//* 功能:向LCD写入命令 *//***********************************************/void LCD_WriteCom(uchar com){rs = 0;P0 = com;delay(5);lcden = 0;delay(5);lcden = 1;delay(5);lcden = 0;}/***********************************************//* LCD函数:void LCD_WriteData(uchar dat) *//* 功能:向LCD写入数据 *//***********************************************/void LCD_WriteData(uchar dat){rs = 1; //选择LCD为写入数据状态lcden = 0;P0 = dat; //将待写入数据放到总线上delay(5);lcden = 1; //给LCD使能端一个脉冲delay(5); //信号将之前放到总线上lcden = 0; //的数据写入LCDdelay(5);}/***********************************************//* LCD函数:void LCD_Init() */ /* 功能:初始化LCD,设定LCD的初始状态 *//***********************************************/void LCD_Init(){LCD_WriteCom(0x38); //LCD显示模式设定delay(15);LCD_WriteCom(0x08); //关闭LCD显示delay(3);LCD_WriteCom(0x01); //LCD显示清屏delay(3);LCD_WriteCom(0x06); //设定光标地址指针为自动加1delay(3);LCD_WriteCom(0x0c); //打开LCD显示,但不显示光标}/**********************************************//* */ /* 显示18B20序列号 *//* *//**********************************************/void Display18B20Rom(char Rom){uchar h,l;l = Rom & 0x0f; //取低4位h = Rom & 0xf0; //取高4位h >>= 4;if( ( h >= 0x00 )&&( h <= 0x09 ) )LCD_WriteData(h+0x30); //取ASCII码elseLCD_WriteData(h+0x37); //取ASCII码if( ( l >= 0x00 )&&( l <= 0x09 ) )LCD_WriteData(l+0x30); //取ASCII码elseLCD_WriteData(l+0x37); //取ASCII码}。
两路的ds18b20程序说明文档硬件原理《一》整个电路的实物焊接图:LCD的D0-D7跟单片机的P2口连。
LCD用得是1602,LCD的第4脚与单片机的P3.5脚,LCD的第6脚与单片机的P3.4连。
LCD的第5脚接地。
DS18B20的数据线(中间的引脚)接单片机的P1.3。
单片机用的是A T89S52.《二》硬件原理图:1、最小系统:2、LCD1602与DS18B20的原理图:软件原理1、DS18B20程序说明《一》DS18B20的初始化时序图:DS18B20的初始化程序:DS18B20的初始化说明:1》数据线控制到低电平2》延时600us3》数据线拉到高电平4》延时等待60us5》若单片机读到了数据线上的低电平“0”后,还要做延时,其延时的时间从发出的高电平算起最少要480us《二》DS18B20写入一个字节的时序图:DS18B20写入一个字节的程序:DS18B20写入一个字节的说明:1》数据线先置低电平“0”2》延时5us3》按从低位到高位的顺序发送数据(一次只发出一位)4》延时60us5》重复1~5步骤,直到发送完整的字节6》最后将数据线拉高“1”《三》DS18B20读入一个字节的时序:DS18B20读入一个字节的程序:DS18B20读入一个字节的说明:1》将数据线拉低“0”2》延时6us3》将数据线拉高“1”,释放总线准备接收数据4》延时4us5》读数据线的状态得到一个状态位,并进行数据处理6》延时30us7》将数据线拉高“1”8》重复1~7步骤,直到读完一个字节《四》DS18B20的转化、读与显示检测并读取DS18B20的值:这个程序中的和下文会解释怎么读取读取的温度值地位放入LSB,高位放入MSB中DS18B20的转化:注意:这个程序是衔接上面检测读取DS18B20的程序的转化下图是将十进制的数转化成lcd显示的字符:例如:如果分离出来的shi=5,依据这个图中字符5的ASCII码为0x35,那么lcd显示字符5就应为0x30+shi;DS18B20温度的显示:注意:这个程序是和上面DS18B20转化的程序衔接的《五》获取DS18B20 ROM序列号在主函数while语句中写入让程序停在这儿就可以通过LCD读取DS18B20的序列号了;需要注意的是:若单总线上有多个DS18B20时,读不到正确的序列号,因为单片机在总线上发出读序列号的命令后每一个DS18B20都会开始上传自己的序列号,因此读不到正确的序列号,只能一个一个地读序列号。
ORG 0000HAJMP MAINORG 0030HMAIN: MOV R5,#0FFHMAIN1:MOV P0,#00H ;系统自检。
自高位向低位带小数点显示8扫描256次CLR P2.4LCALL DELAYSETB P2.4CLR P2.5LCALL DELAYSETB P2.5CLR P2.6LCALL DELAYSETB P2.6CLR P2.7LCALL DELAYSETB P2.7DJNZ R5,MAIN1SETB P2.4 ;关显示SETB P2.5SETB P2.6SETB P2.7SJMP MAIN2DELAY:MOV R7 ,#05H //;延时LP8: MOV R6,#19HLP7:DJNZ R6,LP7DJNZ R7,LP8RET; DS18B20初始化汇编程序;*****************************************//MAIN2:LCALL DISP //;主程序SETB P3.2 // ;18B20DQ置1拉高LCALL INIT // ;调初始化MOV A,#0CCH //;跳过ROM匹配------0CCLCALL WRITE // ;调写DS18B20的程序MOV A,#44H // ;发出温度转换命令LCALL WRITE // ;调写DS18B20的程序MOV R6,#34H //;延时136微秒转换时间,写一个字约需70微秒。
DJNZ R6,$LCALL DISPLCALL INITMOV A,#0CCHLCALL WRITEMOV A,#0BEH // ;发出读温度命令LCALL WRITELCALL READCLR CLCALL CONVTEMPLCALL DISPBCDLCALL DISPSJMP MAIN2WRITE:MOV R0,#8 // ;写子程序CLR CWR1: CLR P3.2MOV 20H,#3 // ;延时17微秒DJNZ 20H,$RRC AMOV P3.2,CMOV 21H,#10 // ;发送后延时45微秒DJNZ 21H,$SETB P3.2NOPDJNZ R0,WR1 // ;8位未发送完转SETB P3.2RETREAD: MOV R6,#2 // ;读子程序CLR PSW.5 // ;清清标志F0RE0:MOV R2,#8RE1:CLR CSETB P3.2 // ;拉高DQNOP // ;延时2微秒CLR P3.2 // ;拉低DQSETB P3.2MOV 22H,#3RE2:DJNZ 22H,RE2MOV C,P3.2MOV 23H,#10RE3:DJNZ 23H,RE3RRC ADJNZ R2,RE1 //;8位未读完继续读CPL PSW.5JNB PSW.5,RE4 // ;高8位保存至28HMOV 29H,A // ;低8位及小数保存至29HRE4:MOV 28H,ADJNZ R6,RE0 //;高8位未读继续RETINIT:SETB P3.2 // ;初始化开始DQ置1(整个时隙和理论值不是很准确)NOP //;延时L0:CLR P3.2 // ;DQ拉低MOV 24H,#100 // ;延时400微秒DJNZ 24H,$SETB P3.2 // ;DQ拉高MOV 25H,#10 // ;置40微秒延时常数L01:JNB P3.2,L2 // ;有18B20响应转L2DJNZ 25H,L01 // ;无18B20响应等待40微秒SJMP L0 // ;无18B20重新初始化L2:MOV R7,#60 // ,延时240微秒L3:DJNZ R7,L3SETB P3.2 //;DQ拉高、退出RETCONVTEMP:MOV A,28H //;温度转换ANL A,#80H //;温度正负判别JZ TEMPC1 //;温度为正转CLR C // ;温度为负调整MOV A,29HCPL AADD A,#01HMOV 29H,AMOV A,28HCPL AADDC A,#00HMOV 28H,AMOV 26H,#0BH // ;温度为负26H内送#0BHSJMP TEMPC11TEMPC1:MOV 26H,#0AH //;温度为正26H内送#0AHTEMPC11:MOV A,26HSWAP AMOV 26H,A // ;26H高4位为温度符号MOV A,29H // ;取温度小数部分ANL A,#0FH ;去整数个位MOV DPTR,#DOTTABMOVC A,@A+DPTRMOV 27H,A // ;查表得小数值,并保存至27H单元MOV A,29H // ;温度整数部分拼装后暂时存入AANL A,#0F0H // ;留下整数个位SWAP AMOV 29H,AMOV A,28HANL A,#0FHSWAP AHEX2BCD1:MOV B,#64H // ;温度整数部分除100得整数百位,并存入R7中DIV ABMOV R7,A // ;R7中为百位,B中为十位和个位MOV A,#0AH // ;温度整数部分除10得整数十位和个位XCH A,B // ;除数与被除数交换DIV ABSWAP AORL A,BTEMPC10:MOV 29H,A // ;温度十位和个位存入29H单元中,十位在高4位,个位在低4位ANL A,#0F0H // ;取温度十位SWAP AORL A,26H //;十位加温度符号存入26H单元;高4位为符号MOV 26H,AMOV A,29HANL A,#0FH // ;取温度个位SWAP AORL A,27HMOV 27H,A // ;27H单元中高4位为个位,低4位为小数MOV A,R7JZ TEMPC12 // ;百位为0退出ANL A,#0FH // ;百位不为0即温度为正和十位重新拼装后存入26H,高4位为百位SWAP A // ;MOV R7,AMOV A,26HANL A,#0FH ; // ;去除26H单元的符号ORL A,R7 //;百位和十位拼装,放入26H单元高4位为百位MOV 26H,A // ;低4位为十位TEMPC12:RETDOTTAB:DB 00H,01H,01H,02H,03HDB 03H,04H,04H,05H,06HDB 06H,07H,08H,08H,09H,09HDISPBCD:MOV A,27H // ;BCD码转换ANL A,#0FHMOV 70H,A // ;取小数,并保存在70H中SWAP AANL A,#0FHMOV 71H,A // ;取整数个位,并保存在71H中MOV A,26HANL A,#0FHMOV 72H,A //;取整数十位,并保存在72H中MOV A,26HSWAP AANL A,#0FHMOV 73H,A // ;取整数百位,并保存在73H中MOV A,72H //;取整数十位ANL A,#0F0HCJNE A,#00H,DISPBCD2SJMP DISPBCD2DISPBCD0:MOV A,26H // ;取整数百位ANL A,#0F0HCJNE A,#00H,DISPBCD2 //;百位不等于0退出MOV A,26HSW AP AANL A,#0FH //;十位保留符号MOV 73H,#0AHMOV 72H,ADISPBCD2:RETDISP:MOV R1,#70H // ;显示子程序MOV R5,#11101111B // ;送Y4位码PLAY:MOV P0,#0FFH // ;关段码MOV A,R5 // ;取Yn位码MOV P2,A // ;送位码MOV A,@R1 //;取段码MOV DPTR,#TABMOVC A,@A+DPTRMOV P0,A // ;送段码MOV A,R5JB ACC.5,LOOP1 // ;位码未指向Y2(整数个位)转CLR P0.7 ;;开小数点LOOP1:LCALL DL1MS //;调显示延时INC R1 // ;指向下一位显示段码MOV A,R5 ;取显示位码JNB ACC.7,ENDOUTRL A // ;向下一位位码MOV R5,AAJMP PLAYENDOUT:MOV P0,#0FFHMOV P3,#0FFHRETTAB: DB 0C0H,0F9H,0A4H,0B0HDB 99H,92H,82H,0F8HDB 80H,90H,0FFH,0BFHDL1MS:MOV R6,#14H // ;延时1mS DL1: MOV R7,#19HDL2: DJNZ R7,DL2DJNZ R6,DL1RETEND。
DS18B20的一线工作协议流程是:初始化→ROM操作指令→存储器操作指令→数据传输,其工作时序包括:初始化时序、写时序、读时序。
初始化时序DS18B20初始化时序主机首先发出一个480-960微秒的低电平脉冲,然后释放总线变为高电平,并在随后的480微秒时间内对总线进行检测,如果有低电平出现说明总线上有器件已做出应答,若无低电平出现一直都是高电平说明总线上无器件应答。
作为从器件的DS18B20在一上电后就一直在检测总线上是否有480-960微秒的低电平出现,如果有,在总线转为高电平后等待15-60微秒后将总线电平拉低60-240微秒做出响应存在脉冲,告诉主机本器件已做好准备,若没有检测到就一直在检测等待。
对DS18B20的写和读操作接下来就是主机发出各种操作命令,但各种操作命令都是向DS18B20写0和写1组成的命令字节,接收数据时也是从DS18B20读取0或1的过程,因此首先要搞清楚主机是如何进行写0、写1、读0和读1的。
写周期最少为60微秒,最长不超过120微秒,写周期一开始作为主机先把总线拉低1微秒表示写周期开始,随后若主机想写0,则继续拉低电平最少60微秒直至写周期结束,然后释放总线为高电平;若主机想写1,在一开始拉低总线电平1微秒后就释放总线为高电平,一直到写周期结束。
而作为从机的DS18B20则在检测到总线被拉低后等待15微秒然后从15μs到45μs开始对总线采样,在采样期内总线为高电平则为1,若采样期内总线为低电平则为0。
DS18B20写操作对于读数据操作时序也分为读0时序和读1时序两个过程,读时序是从主机把单总线拉低之后,在1微秒之后就得释放单总线为高电平,以让DS18B20把数据传输到单总线上。
DS18B20在检测到总线被拉低1微秒后,便开始送出数据,若是要送出0就把总线拉为低电平直到读周期结束;若要送出1则释放总线为高电平。
主机在一开始拉低总线1微秒后释放总线,然后在包括前面的拉低总线电平1微秒在内的15微秒时间内完成对总线进行采样检测,采样期内总线为低电平则确认为0,采样期内总线为高电平则确认为1,完成一个读时序过程,至少需要60μs才能完成。
DS18B20美国达拉斯公司生产的单总线协议的数字温度检测芯片,数据的写入与读取都在一根总线上进行操作,在总线上可以连接多个DS18B20,因为每个DS18B20都有唯一的光刻ROM序列号,所以可以进行ROM匹配,搜索指令进行选择相应的从机序列号。
编写DS18B20的检测程序主要包括:初始化函数(复位脉冲+存在脉冲),写数据函数,读取数据的函数。
对DS18B20的操作包括:初始化函数,ROM指令,RAM指令这三个部分。
接下来我先说一下这三个部分所对应的时序图的理解吧。
初始化:由于上拉电阻的存在,总线默认状态是高电平,接着主机将总线拉低,维持480us 到960us的时间,再接着就是释放总线,维持时间为15us到60us,接着就由从机发出一个低电平信号,将总线拉低,表示该DS18B20是正常地,或者说是存在的,其维持时间为60us 到240us。
上面一图是写入数据的时序图。
写时序:默认状态为高电平,先将总线拉低,至少维持1us 的延时时间,接着就往总线上进行写数据操作,接着DS18B20就开始采样数据了,整个过程时间为60us到120us。
下面一图是读取数据的时序图。
读时序:默认状态为高电平,先将总线拉低,接着在15us 之前,主机进行数据采样,其维持时间也为60us到120us。
下面是我在理解了DS18B20的原理之后所写的程序,调试成功了,且能实时读取外界温度的功能,这里是不读取小数部分的温度,只读取温度的正数值。
#include<reg52.h>#define uint unsigned int#define uchar unsigned charuchar code table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};sbit DQ=P2^2;sbit duan=P2^6;sbit wei=P2^7;//是在11.0592M赫兹的频率下void delay_ms(uint t){uint i;for(;t>0;t--)for(i=110;i>0;i--);} //约为tms的延时程序void delay(uint x){while(x--);}void init_ds18b20(){uchar n;DQ=1;delay(2); //约为38usDQ=0;delay(80); //约为800usDQ=1;delay(4); //约为58usn=DQ;delay(10); //约为110us}void write_byte(uchar dat){uchar i;for(i=0;i<8;i++){DQ=0; //无论是写0或写1都要有至少1us的低电平DQ=dat&0x01;//总线直接等于写入的数据(低位在前,高位在后)delay(4); //约为58usDQ=1; //释放总线,为下一步的数据变换做准备dat>>=1;//数据进行移位操作}delay(4);}uchar read_byte(){uchar i,value;for(i=0;i<8;i++){DQ=0;value>>=1; //移位7次DQ=1; //先要释放总线,那样才能采样到有效数据if(DQ) //判断8次{value|=0x80;}delay(6); //约为78us}return value;}uchar read_temperature(){uchar a,b;init_ds18b20(); //每次操作指令前,都必须进行初始化设置write_byte(0xcc);//跳过ROM指令write_byte(0x44);//进行温度转换处理delay(300);//进行一定地延时约为3ms左右init_ds18b20();write_byte(0xcc);//跳过ROM操作write_byte(0xbe);//读取温度a=read_byte();//温度低字节b=read_byte();//温度高字节b<<=4;//b左移四位,低四位为0000b=b+(a&0xf0)>>4;//将a的低四位屏蔽,不取小数点,进行右移四位,合并成一个字节的数据return b;}void display(uchar aa,uchar bb) {duan=1;P0=table[aa];duan=0;P0=0xff;wei=1;P0=0xfe;wei=0;delay_ms(5);duan=1;P0=table[bb];duan=0;P0=0xff;wei=1;P0=0xfd;wei=0;delay_ms(5);}void main(){uchar num,shi,ge;while(1){num=read_temperature();shi=num/10; //分离出十位ge=num%10; //分离出个位display(shi,ge);}}。
18B20操作方法:一、初始化18B20根据初始化时序图,编写初始化函数。
1.发送初始化脉冲,即DQ=0;延时486us。
2.释放总线,即DQ=1;延时57us。
3.读总线状态,检测是否收到存在脉冲。
即判断DQ是否为0,若为0则证明18B20存在。
4.释放总线,即DQ=1;延时57us。
二、向18B20写入ROM指令根据写0、1时序图,编写写“位”函数。
先判断写入数据为“1”还是“0”,可通过“按位与(&)、右移一位(>>1)”运算来实现。
若写入位数据为“1”,执行以下时序:1.发送时隙初始化脉冲,即DQ=0;延时2us。
2.释放总线,即DQ=1;延时45us。
若写入位数据为“0”,执行以下时序:1.发送时隙初始化脉冲,即DQ=0;延时57us。
2.释放总线,即DQ=1;延时2us。
按照以上时序规则,依次写入8个位(借助for循环),即可实现写入ROM指令的操作。
编写好写ROM指令函数后,依次执行写(0xCC)、写(0xBE)两条指令,便可进入下一步。
三、从18B20读出温度数据根据读0、1时序图,编写读“位”函数。
1.发送时隙初始化脉冲,即DQ=0;延时1us。
2.释放总线,即DQ=1;延时2us(要求15us内完成该操作,故延迟较小)。
3.单片机采样,即读取DQ值(temp=DQ);延时45us。
按照以上读时隙规则,依次读出8个位(借助for循环和左移7位(7<<)、右移1位(>>1)及按位与(&)的运算)便可形成一个字节的数据。
四、生成温度数据对读出的字节数据进行处理,转换成整数。
1.初始化18B20。
2.写入ROM指令(写(0xCC)、写(0xBE)两条指令)。
3.接收数据。
(先低字节,后高字节)4.处理数据。
(a、定义无符号整形变量(占2个字节);b、高字节左移8位(8<<)并赋值给无符号整形变量,并判断该数据的正负(制定数据并按位与(&)),例如判断(high&0xF8)==0xF8,根据情况添加正负标志位flag=1或flag=0。
;单片机DS18B20温度计C语言程序; 有程序#include<reg51.h>#include<intrins.h>#include <math.H> //要用到取绝对值函数abs()//通过DS18B20测试当前环境温度, 并通过数码管显示当前温度值, 目前显示范围: -55~ +125度sbit wela = P2^7; //数码管位选sbit dula = P2^6; //数码管段选sbit ds = P2^2;int tempValue;//0-F数码管的编码(共阳极)unsigned char code table[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};//0-9数码管的编码(共阳极), 带小数点unsigned char code tableWidthDot[]={0x40, 0x79, 0x24, 0x30,0x19, 0x12, 0x02,0x78, 0x00, 0x10};//延时函数, 对于11.0592MHz时钟, 例i=10,则大概延时10ms.void delay(unsigned int i){unsigned int j;while(i--){for(j = 0; j < 125; j++);}}//初始化DS18B20//让DS18B20一段相对长时间低电平, 然后一段相对非常短时间高电平, 即可启动 void dsInit(){//对于11.0592MHz时钟, unsigned int型的i, 作一个i++操作的时间大于?us unsigned int i;ds = 0;i = 100; //拉低约800us, 符合协议要求的480us以上while(i>0) i--;ds = 1; //产生一个上升沿, 进入等待应答状态i = 4;while(i>0) i--;}void dsWait(){unsigned int i;while(ds);while(~ds); //检测到应答脉冲i = 4;while(i > 0) i--;}//向DS18B20读取一位数据//读一位, 让DS18B20一小周期低电平, 然后两小周期高电平,//之后DS18B20则会输出持续一段时间的一位数据bit readBit(){unsigned int i;bit b;ds = 0;i++; //延时约8us, 符合协议要求至少保持1usds = 1;i++; i++; //延时约16us, 符合协议要求的至少延时15us以上b = ds;i = 8;while(i>0) i--; //延时约64us, 符合读时隙不低于60us要求return b;}//读取一字节数据, 通过调用readBit()来实现unsigned char readByte(){unsigned int i;unsigned char j, dat;dat = 0;for(i=0; i<8; i++){j = readBit();//最先读出的是最低位数据dat = (j << 7) | (dat >> 1);}return dat;}//向DS18B20写入一字节数据void writeByte(unsigned char dat){unsigned int i;unsigned char j;bit b;for(j = 0; j < 8; j++){b = dat & 0x01;dat >>= 1;//写"1", 将DQ拉低15us后, 在15us~60us内将DQ拉高, 即完成写1if(b){ds = 0;i++; i++; //拉低约16us, 符号要求15~60us内ds = 1;i = 8; while(i>0) i--; //延时约64us, 符合写时隙不低于60us要求}else //写"0", 将DQ拉低60us~120usds = 0;i = 8; while(i>0) i--; //拉低约64us, 符号要求ds = 1;i++; i++; //整个写0时隙过程已经超过60us, 这里就不用像写1那样, 再延时64us 了}}//向DS18B20发送温度转换命令void sendChangeCmd(){dsInit(); //初始化DS18B20, 无论什么命令, 首先都要发起初始化dsWait(); //等待DS18B20应答delay(1); //延时1ms, 因为DS18B20会拉低DQ 60~240us作为应答信号writeByte(0xcc); //写入跳过序列号命令字Skip RomwriteByte(0x44); //写入温度转换命令字Convert T}//向DS18B20发送读取数据命令void sendReadCmd(){dsInit();dsWait();delay(1);writeByte(0xcc); //写入跳过序列号命令字Skip RomwriteByte(0xbe); //写入读取数据令字Read Scratchpad}//获取当前温度值int getTmpValue(){unsigned int tmpvalue;int value; //存放温度数值float t;unsigned char low, high;sendReadCmd();//连续读取两个字节数据low = readByte();high = readByte();//将高低两个字节合成一个整形变量//计算机中对于负数是利用补码来表示的//若是负值, 读取出来的数值是用补码表示的, 可直接赋值给int型的valuetmpvalue = high;tmpvalue <<= 8;tmpvalue |= low;value = tmpvalue;//使用DS18B20的默认分辨率12位, 精确度为0.0625度, 即读回数据的最低位代表0.0625度t = value * 0.0625;//将它放大100倍, 使显示时可显示小数点后两位, 并对小数点后第三进行4舍5入//如t=11.0625, 进行计数后, 得到value = 1106, 即11.06 度//如t=-11.0625, 进行计数后, 得到value = -1106, 即-11.06 度value = t * 100 + (value > 0 ? 0.5 : -0.5); //大于0加0.5, 小于0减0.5return value;}unsigned char const timeCount = 3; //动态扫描的时间间隔//显示当前温度值, 精确到小数点后一位//若先位选再段选, 由于IO口默认输出高电平, 所以当先位选会使数码管出现乱码void display(int v){unsigned char count;unsigned char datas[] = {0, 0, 0, 0, 0};unsigned int tmp = abs(v);datas[0] = tmp / 10000;datas[1] = tmp % 10000 / 1000;datas[2] = tmp % 1000 / 100;datas[3] = tmp % 100 / 10;datas[4] = tmp % 10;if(v < 0){//关位选, 去除对上一位的影响P0 = 0xff;wela = 0;//段选P0 = 0x40; //显示"-"号dula = 1; //打开锁存, 给它一个下降沿量dula = 0;//位选P0 = 0xfe;wela = 1; //打开锁存, 给它一个下降沿量wela = 0;delay(timeCount);}for(count = 0; count != 5; count++){//关位选, 去除对上一位的影响P0 = 0xff;wela = 1; //打开锁存, 给它一个下降沿量wela = 0;//段选if(count != 2){P0 = table[datas[count]]; //显示数字}else{P0 = tableWidthDot[datas[count]]; //显示带小数点数字}dula = 0;//位选P0 = _crol_(0xfd, count); //选择第(count + 1) 个数码管wela = 1; //打开锁存, 给它一个下降沿量wela = 0;delay(timeCount);}}void main(){unsigned char i;while(1){//启动温度转换sendChangeCmd();//显示5次for(i = 0; i < 40; i++){display(tempValue);}tempValue = getTmpValue();}以下是我编的程序,可用#include <reg52.h>#include <intrins.h>//-----------------------------------------------------------sbit DQ=P1^5;//-----------------------------------------------------------unsigned char number[10]={0X3F,0X06,0X5B,0X4F,0X66,0X6D,0X7D,0X07,0X7F,0X6F};//数字0~9unsigned char wei[8]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80}; //数码管位循环unsigned char Flag;unsigned char Templ,Temph;unsigned int temp;//-----------------------------------------------------------//函数声明//-----------------------------------------------------------void delay(unsigned char i); //延时程序//----------------------------------void Int18b20(void); //18b20初始化void Write18b20(unsigned char dat); //向18b20写一字节unsigned char Read18b20(void); //从18b20读一字节void Start18b20(void); //开始转换温度void Get18b20(void); //读出温度void chinT(void); //数据转换//----------------------------------void display(void); //显示程序//-----------------------------------------------------------//函数功能:延时//-----------------------------------------------------------/*************精确延时函数*****************/void delay(unsigned char i){while(--i);}/*此延时函数针对的是12Mhz的晶振delay(0); //延时518us 误差:518-2*256=6delay(1); //延时7us (原帖写"5us"是错的)delay(10); //延时25us 误差:25-20=5delay(20); //延时45us 误差:45-40=5delay(100); //延时205us 误差:205-200=5delay(200); //延时405us 误差:405-400=5*///-----------------------------------------------------------//DS18b20的相关程序//-----------------------------------------------------------//初始化//-----------------------------------------------------------void Int18b20(void){DQ=1;_nop_();_nop_();DQ=0; //拉低delay(100); //延时205usdelay(200); //延时405us //等待400~960微秒,最短为480us DQ=1;delay(1); //延时7usdelay(20); //延时45us //等待15~60微秒(等待回复)if(DQ==1) //判断初始化的情况是否成功{Flag=0; //复位失败}else{Flag=1;while(!DQ); //等待回复完成}delay(200); //延时405us //等待完成初始化}//-----------------------------------------------------------//写一字节//-----------------------------------------------------------void Write18b20(unsigned char dat){unsigned char i;for(i=0;i<8;i++){DQ=1;_nop_();DQ=0;delay(1); //延时7us //拉低后延时小于15usif(dat&0x01){DQ=1;}else{DQ=0;}dat=dat>>1;delay(20); //延时45usdelay(10); //延时25us //延时大于60usDQ=1;delay(1); //延时7us //延时大于1us}}//-----------------------------------------------------------//读一字节//-----------------------------------------------------------unsigned char Read18b20(void){unsigned char i,dat=0;for(i=0;i<8;i++){DQ=1;_nop_();DQ=0;delay(1); //延时7usdat=dat>>1;DQ=1;delay(1); //延时7us //确保在15us后60us前读数据if(DQ){dat|=0x80;}delay(20); //延时45us //确保读时续大于60us}return dat;}//-----------------------------------------------------------//开始转换温度//-----------------------------------------------------------void Start18b20(void){Int18b20();Write18b20(0xcc); //跳过ROM指令Write18b20(0x44); //温度转换指令}//-----------------------------------------------------------//读出温度//-----------------------------------------------------------void Get18b20(void){Int18b20();Write18b20(0xcc); //跳过ROM指令Write18b20(0xbe); //读暂存器指令Templ=Read18b20();Temph=Read18b20();}//-----------------------------------------------------------//数据转换//-----------------------------------------------------------void chinT(void){float Tt;temp=Temph; //先把高八位有效数据赋于temptemp=(temp<<8); //将数据从temp低八位移到高八位temp=temp|Templ; //将两字节合成一个整型变量Tt=temp*0.0625; //得到真实十进制温度值(因为DS18B20可以精确到0.0625度) temp=Tt*10+0.5; //放大十倍(将小数点后一位变成个位,个位变成十位,十位变成百位,并四舍五入)}//-----------------------------------------------------------//显示程序//-----------------------------------------------------------void display(void){unsigned int i;unsigned char A1,A2,A3;A1=temp/100; //百位(温度的十位)A2=temp%100/10; //十位(温度的个位)A3=temp%10; //个位(温度的小数点后一位)for(i=0;i<20;i++){P0=0x00;P2=0x00;P0=number[A1];P2=wei[0];delay(220);P0=0x00;P2=0x00;P0=number[A2];P2=wei[1];delay(220);P0=0x00;P2=0x00;P0=number[A3];P2=wei[2];delay(220);P0=0x00;P2=0x00;P0=0x80;P2=wei[1];delay(220);}}//-----------------------------------------------------------//----------------------------------------------------------- void main(void){while(1){Int18b20();if(Flag){Start18b20(); //开始转换温度Get18b20(); //得到温度chinT(); //数据转换display(); //显示}else P3=0x01;}}。