为了正常的体验网站,请在浏览器设置里面开启Javascript功能!
首页 > 单片机DS18B20温度传感器C语言程序含CRC校验

单片机DS18B20温度传感器C语言程序含CRC校验

2021-09-07 4页 doc 142KB 17阅读

用户头像 个人认证

志宏

暂无简介

举报
单片机DS18B20温度传感器C语言程序含CRC校验单片机DS18B20温度传感器C语言程序含CRC校验第PAGE11页共NUMPAGES14页单片机中使用DS18B20的C语言程序和CRC校验单片机中使用DS18B20温度传感器C语言程序(参考1)/********************************************************************************                              DS18B20测温程序   硬件:AT89S52   (1)单线ds18b20接P2.2   (2)...
单片机DS18B20温度传感器C语言程序含CRC校验
单片机DS18B20温度传感器C语言程序含CRC校验第PAGE11页共NUMPAGES14页单片机中使用DS18B20的C语言程序和CRC校验单片机中使用DS18B20温度传感器C语言程序(参考1)/********************************************************************************                              DS18B20测温程序   硬件:AT89S52   (1)单线ds18b20接P2.2   (2)七段数码管接P0口   (3)使用外部电源给ds18b20供电,没有使用寄生电源   软件:KeiuVision3**********************************************************************************/#include"reg52.h"#include"intrins.h"#defineucharunsignedchar#defineuintunsignedintsbitds=P2^2;sbitdula=P2^6;sbitwela=P2^7;ucharflag;uinttemp;              //参数temp一定要声明为int型ucharcodetable[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};    //不带小数点数字编码ucharcodetable1[]={0xbf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,0x87,0xff,0xef};       //带小数点数字编码/*延时*/voidTempDelay(ucharus){  while(us--);}voiddelay(uintcount)//延时子函数{uinti;while(count){i=200;while(i>0)i--;count--;}}/*串口初始化,波特率9600,方式1*/voidinit_com(){  TMOD=0x20;     //设置定时器1为模式2  TH1=0xfd;      //装初值设定波特率  TL1=0xfd;  TR1=1;         //启动定时器  SM0=0;         //串口通信模式设置  SM1=1;//REN=1;         //串口允许接收数据  PCON=0;        //波特率不倍频//SMOD=0;      //波特率不倍频//EA=1;         //开总中断//ES=1;         //开串行中断}/*数码管的显示*/voiddisplay(uinttemp){   ucharbai,shi,ge;   bai=temp/100;   shi=temp%100/10;   ge=temp%100%10;dula=0;   P0=table[bai];//显示百位dula=1;        //从0到1,有个上升沿,解除锁存,显示相应段dula=0;        //从1到0再次锁存   wela=0;   P0=0xfe;wela=1;wela=0;delay(1);   //延时约2msP0=table1[shi];//显示十位dula=1;   dula=0;P0=0xfd;wela=1;   wela=0;   delay(1);   P0=table[ge];//显示个位dula=1;   dula=0;P0=0xfb;wela=1;   wela=0;   delay(1);}/*****************************************时序:初始化时序、读时序、写时序。所有时序都是将主机(单片机)作为主设备,单总线器件作为从设备。而每一次命令和数据的传输都是从主机主动启动写时序开始,如果要求单总线器件回送数据,在进行写命令后,主机需启动读时序完成数据接收。数据和命令的传输都是低位在先。初始化时序:复位脉冲存在脉冲       读;1或0时序       写;1或0时序只有存在脉冲信号是从18b20(从机)发出的,其它信号都是由主机发出的。存在脉冲:让主机(总线)知道从机(18b20)已经做好了准备。******************************************//*--------------------------------------------------------------------------------------------------------------------初始化:检测总线控制器发出的复位脉冲和ds18b20的任何通讯都要从初始化开始初始化序列包括一个由总线控制器发出的复位脉冲和跟在其后由从机发出的存在脉冲。初始化:复位脉冲+存在脉冲具体操作:总线控制器发出(TX)一个复位脉冲(一个最少保持480μs的低电平信号),然后释放总线,进入接收状态(RX)。单线总线由5K上拉电阻拉到高电平。探测到I/O引脚上的上升沿后DS1820等待15~60μs,然后发出存在脉冲(一个60~240μs的低电平信号)。具体看18b20单线复位脉冲时序和1-wirepresencedetect"的时序图-------------------------------------------------------------------------------------------------------------------*/voidds_reset(void){  ds=1;  _nop_();       //1us  ds=0;  TempDelay(80);//当总线停留在低电平超过480us,总线上所以器件都将被复位,这里延//时约530us总 线停留在低电平超过480μs,总线上的所有器件都将被复位。  _nop_();  ds=1;          //产生复位脉冲后,微处理器释放总线,让总线处于空闲状态,原因查18b20中文资料TempDelay(5);//释放总线后,以便从机18b20通过拉低总线来指示其是否在线,                 //存在检测高电平时间:15~60us,所以延时44us,进行1-wirepresencedetect(单线存在检测)  _nop_();  _nop_();  _nop_();  if(ds==0)       flag=1;      //detect18b20success  else       flag=0;      //detect18b20failTempDelay(20);   //存在检测低电平时间:60~240us,所以延时约140us  _nop_();  _nop_();  ds=1;         //再次拉高总线,让总线处于空闲状态/**/}原理解释:控制器对18B20操作流程:1,复位:首先我们必须对DS18B20芯片进行复位,复位就是由控制器(单片机)给DS18B20单总线至少480uS的低电平信号。当18B20接到此复位信号后则会在15~60uS后回发一个芯片的存在脉冲。2,存在脉冲:在复位电平结束之后,控制器应该将数据单总线拉高,以便于在15~60uS后接收存在脉冲,存在脉冲为一个60~240uS的低电平信号。至此,通信双方已经达成了基本的,接下来将会是控制器与18B20间的数据通信。/*----------------------------------------读/写时间隙:DS1820的数据读写是通过时间隙处理位和命令字来确认信息交换。------------------------------------------*/bitds_read_bit(void)   //读一位{  bitdat;  ds=0;        //单片机(微处理器)将总线拉低_nop_();      //读时隙起始于微处理器将总线拉低至少1us  ds=1;       //拉低总线后接着释放总线,让从机18b20能够接管总线,输出有效数据  _nop_();  _nop_();         //小延时一下,读取18b20上的数据,因为从ds18b20上输出的数据//在读"时间隙"下降沿出现15us内有效  dat=ds;          //主机读从机18b20输出的数据,这些数据在读时隙的下降沿出现//15us内有效  TempDelay(10);   //所有读"时间隙"必须60~120us,这里77us  return(dat);      //返回有效数据}原理:图8读时间隙时控制时的采样时间应该更加的精确才行,读时间隙时也是必须先由主机产生至少1uS的低电平,示读时间的起始。随后在总线被释放后的15uS中DS18B20会发送内部数据位,这时控制如果发现总线为高电平表示读出“1”,如果总线为低电平则表示读出数据“0”。每一位的读取之前都由控制器加一个起始信号。注意:如图8所示,必须在读间隙开始的15uS内读取数据位才可以保证通信的正确。在通信时是以8位“0”或“1”为一个字节,字节的读或写是从高位开始的,即A7到A0.字节的读写顺序也是如图2自上而下的。uchards_read_byte(void)//读一字节{ucharvalue,i,j;value=0;          //一定别忘了给初值for(i=0;i<8;i++){   j=ds_read_bit();    value=(j<<7)|(value>>1);  //这一步的说明在一个word文档里面??}return(value);       //返回一个字节的数据}voidds_write_byte(uchardat)//写一个字节{uchari;bitonebit;       //一定不要忘了,onebit是一位for(i=1;i<=8;i++){   onebit=dat&0x01;   dat=dat>>1;//由低到高传送数据if(onebit)     //写1{ds=0;_nop_();        _nop_();     //看时序图,至少延时1us,才产生写"时间隙"ds=1;      //写时间隙开始后的15μs内允许数据线拉到高电平    TempDelay(5);//所有写时间隙必须最少持续60us}else        //写0{ds=0;    TempDelay(8);   //主机要生成一个写0时间隙,必须把数据线拉到低电平并保持至少60μs,这里64usds=1;_nop_();    _nop_();}}}主机(单片机)控制18B20完成温度转换要经过三个步骤:每一次读写之前都要18B20进行复位操作,复位成功后发送一条ROM指令,最后发送RAM指令,这样才能对DS18b20进行预定的操作。复位要求主CPU将数据线下拉500us,然后释放,当ds18B20受到信号后等待16~60us,后发出60~240us的存在低脉冲,主CPU收到此信号表示复位成功******************************************//*----------------------------------------进行温度转换:先初始化然后跳过ROM:跳过64位ROM地址,直接向ds18B20发温度转换命令,适合单片工作发送温度转换命令------------------------------------------*/voidtem_change(){ds_reset();delay(1);             //约2msds_write_byte(0xcc);//单线情况下,跳跃ROM指令ds_write_byte(0x44);//温度转换指令}/*----------------------------------------获得温度:------------------------------------------*/uintget_temperature(){floatwendu;uchara,b;ds_reset();delay(1);             //约2msds_write_byte(0xcc);ds_write_byte(0xbe);//发送读温度命令a=ds_read_byte();//读出温度低8位b=ds_read_byte();//读温度高8位temp=b;temp<<=8;temp=temp|a;wendu=temp*0.0625;    //得到真实十进制温度值,因为DS18B20                                  //可以精确到0.0625度,所以读回数据的最低位代表的是//0.0625度temp=wendu*10+0.5;      //放大十倍,这样做的目的将小数点后第一位                                     //也转换为可显示数字,同时进行一个四舍五入操作。returntemp;}/*----------------------------------------读ROM  ------------------------------------------*//*voidds_read_rom()                 //这里没有用到{  uchara,b;  ds_reset();  delay(30);  ds_write_byte(0x33);  a=ds_read_byte();  b=ds_read_byte();}*/voidmain(){  uinta;  init_com();  while(1)  {tem_change();         //12位转换时间最大为750msfor(a=10;a>0;a--){display(get_temperature());}  }}单片机中使用DS18B20温度传感器C语言程序含CRC校验(参考2)CRC是序列号的校验码用来验证序列号对不对的。序列号一般是没标的要自己读。给你个读序列号的程序改下端口就能用:#include#include#defineucharunsignedchar#defineuintunsignedintsbitDQ=P2^0;//定义DS18B20端口DQsbitBEEP=P3^7;//蜂鸣器驱动线bitpresence;sbitLCD_RS=P2^6;sbitLCD_RW=P2^5;sbitLCD_EN=P2^4;ucharcodecdis1[]={"DS18B20OK"};ucharcodecdis2[]={""};ucharcodecdis3[]={"DS18B20ERR0R"};ucharcodecdis4[]={"PLEASECHECK"};unsignedchardatadisplay[2]={0x00,0x00};unsignedchardataRomCode[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};unsignedcharTemp;unsignedcharcrc;voidbeep();#definedelayNOP();{_nop_();_nop_();_nop_();_nop_();};/*******************************************************************/voiddelay1(intms){unsignedchary;while(ms--){for(y=0;y<250;y++){_nop_();_nop_();_nop_();_nop_();}}}/******************************************************************//*检查LCD忙状态*//*lcd_busy为1时,忙,等待。lcd-busy为0时,闲,可写指令与数据。*//******************************************************************/bitlcd_busy(){bitresult;LCD_RS=0;LCD_RW=1;LCD_EN=1;delayNOP();result=(bit)(P0&0x80);LCD_EN=0;return(result);}/*******************************************************************//*写指令数据到LCD*//*RS=L,RW=L,E=高脉冲,D0-D7=指令码。*//*******************************************************************/voidlcd_wcmd(ucharcmd){while(lcd_busy());LCD_RS=0;LCD_RW=0;LCD_EN=0;_nop_();_nop_();P0=cmd;delayNOP();LCD_EN=1;delayNOP();LCD_EN=0;}/*******************************************************************//*写显示数据到LCD*//*RS=H,RW=L,E=高脉冲,D0-D7=数据。*//*******************************************************************/voidlcd_wdat(uchardat){while(lcd_busy());LCD_RS=1;LCD_RW=0;LCD_EN=0;P0=dat;delayNOP();LCD_EN=1;delayNOP();LCD_EN=0;}/*******************************************************************//*LCD初始化设定*//*******************************************************************/voidlcd_init(){delay1(15);lcd_wcmd(0x01);//清除LCD的显示内容lcd_wcmd(0x38);//16*2显示,5*7点阵,8位数据delay1(5);lcd_wcmd(0x38);delay1(5);lcd_wcmd(0x38);delay1(5);lcd_wcmd(0x0c);//显示开,关光标delay1(5);lcd_wcmd(0x06);//移动光标delay1(5);lcd_wcmd(0x01);//清除LCD的显示内容delay1(5);}/*******************************************************************//*设定显示位置*//*******************************************************************/voidlcd_pos(ucharpos){lcd_wcmd(pos|0x80);//数据指针=80+地址变量}/*******************************************************************//*us级延时函数*//*******************************************************************/voidDelay(unsignedintnum){while(--num);}/*******************************************************************//*初始化ds1820*//*******************************************************************/Init_DS18B20(void){DQ=1;//DQ复位Delay(8);//稍做延时DQ=0;//将DQ拉低Delay(90);//精确延时大于480usDQ=1;//拉高总线Delay(8);presence=DQ;//读取存在信号Delay(100);DQ=1;return(presence);//返回信号,0=presence,1=nopresence}/*******************************************************************//*读一位(bit)*//*******************************************************************/ucharread_bit(void){unsignedchari;DQ=0;//将DQ拉低开始读时间隙DQ=1;//thenreturnhighfor(i=0;i<3;i++);//延时15μsreturn(DQ);//返回DQ线上的电平值}/*******************************************************************//*读一个字节*//*******************************************************************/ReadOneChar(void){unsignedchari=0;unsignedchardat=0;//for(i=8;i>0;i--)//{//read_bit();//DQ=0;//给脉冲信号//dat>>=1;//DQ=1;//给脉冲信号for(i=0;i<8;i++){//读取字节,每次读取一个字节if(read_bit())dat|=0x01<0;i--)//{for(i=0;i<8;i++)//写入字节,每次写入一位{//DQ=0;//DQ=dat&0x01;//Delay(5);//DQ=1;temp=dat>>i;temp&=0x01;write_bit(temp);//dat>>=1;}Delay(5);}/*******************************************************************//*读取64位序列码*//*******************************************************************/Read_RomCord(void){unsignedcharj;Init_DS18B20();WriteOneChar(0x33);//读序列码的操作for(j=0;j<8;j++){RomCode[j]=ReadOneChar();}}/*******************************************************************//*DS18B20的CRC8校验程序*//*******************************************************************/ucharCRC8(){uchari,x;ucharcrcbuff;crc=0;for(x=0;x<8;x++){crcbuff=RomCode[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;}}returncrc;}/*******************************************************************//*数据转换与显示*//*******************************************************************/Disp_RomCode(){ucharj;ucharH_num=0x40;//LCD第二行初始位置for(j=0;j<8;j++){Temp=RomCode[j];display[0]=((Temp&0xf0)>>4);if(display[0]>9){display[0]=display[0]+0x37;}else{display[0]=display[0]+0x30;}lcd_pos(H_num);lcd_wdat(display[0]);//高位数显示H_num++;display[1]=(Temp&0x0f);if(display[1]>9){display[1]=display[1]+0x37;}else{display[1]=display[1]+0x30;}lcd_pos(H_num);lcd_wdat(display[1]);//低位数显示H_num++;}}/*******************************************************************//*蜂鸣器响一声*//*******************************************************************/voidbeep(){unsignedchary;for(y=0;y<100;y++){Delay(60);BEEP=!BEEP;//BEEP取反}BEEP=1;//关闭蜂鸣器Delay(40000);}/*******************************************************************//*DS18B20OK显示菜单*//*******************************************************************/voidOk_Menu(){ucharm;lcd_init();//初始化LCDlcd_pos(0);//设置显示位置为第一行的第1个字符m=0;while(cdis1[m]!='\0'){lcd_wdat(cdis1[m]);//显示字符m++;}lcd_pos(0x40);//设置显示位置为第二行第1个字符m=0;while(cdis2[m]!='\0'){lcd_wdat(cdis2[m]);//显示字符m++;}}/*******************************************************************//*DS18B20ERROR显示菜单*//*******************************************************************/voidError_Menu(){ucharm;lcd_init();//初始化LCDlcd_pos(0);//设置显示位置为第一行的第1个字符m=0;while(cdis3[m]!='\0'){lcd_wdat(cdis3[m]);//显示字符m++;}lcd_pos(0x40);//设置显示位置为第二行第1个字符m=0;while(cdis4[m]!='\0'){lcd_wdat(cdis4[m]);//显示字符m++;}}/*******************************************************************//*主函数*//*******************************************************************/voidmain(){P0=0xff;P2=0xff;while(1){Ok_Menu();Read_RomCord();//读取64位序列码CRC8();//CRC效验if(crc==0)//CRC效验正确{Disp_RomCode();//显示64位序列码beep();}while(!presence){Init_DS18B20();delay1(1000);}Error_Menu();do{Init_DS18B20();beep();}while(presence);}}/****************************************************************************************************/曾经编写的DS18B20程序原来一切正常,但是最近拿来用时发现偶尔会出现数据错误,例如正常室温20度,但是偶尔会出现负值或很高的温度,怀疑新购的DS18B20时序参数同上批有点差别,有遇到过这种情况的吗?大家在使用DS18B20时是读出全部9个自己并用CRC进行校验吗?请大家指教。晶振频率11.0592MHz,AT89C52,我的代码如下:unsignedcharDS18B20_ReadByte(){unsignedchari,dat=0;for(i=0;i<8;i++){dat>>=1;//开始另一个读周期前必须有1us以上的高电平恢复期DQ=1;Delay2us();//产生读起始信号,数据线保持在低电平至少1μs,DS18B20在总线下降沿后输出15us的有效数据DQ=0;Delay2us();DQ=1;Delay8us();if(DQ)dat|=0x80;//延时60us以上来满足DS18B20的时序Delay65us();}returndat;}/*************************************************************************************************对总线上唯一的DS18B20进行温度转换及读取,返回带符号整形值。计算温度时需要乘以0.0625,如果出错返回值为200℃,超过其测温范围**************************************************************************************************/intDS18B20_GetTemperature(void){unsignedchari,tempL,tempH;//温度转换if(!DS18B20_Reset())return0x0C80;DS18B20_WriteByte(0xCC);//跳过ROMDS18B20_WriteByte(0x44);//进行温度转换//等待温度转换结束for(i=0;i<200;i++){if(DS18B20_ReadByte()==0xFF)break;Delay5ms();}//读取温度if(!DS18B20_Reset())return0x0C80;DS18B20_WriteByte(0xCC);//跳过ROMDS18B20_WriteByte(0xBE);//读寄存器tempL=DS18B20_ReadByte();//先读低8位数据tempH=DS18B20_ReadByte();//再读高8位数据DS18B20_Reset();//通过再次复位中断读取return(tempH<<8)|tempL;}**单总线需要校验,不然容易出错。**我都是以前读过的数据,如果跟当次差异太大就重新读下检验**在读取ds18b20的时候必须要关闭总中断,否则会影响他的时序!**单片机中bit和sbit有什么区别:sbit不可以做为函数参数传送的。sbit映射到IO口(P1^1这种IO口的“位”);bit在RAM中的可位寻址空间中,一般用作程序判断的标志位。你可以认为它们一个对外(sbit),一个对内(bit)。bit和intchar之类的差不多,只不过char=8位,bit=1位而已。/*****************************************************************************************************/DS18B20芯片的CRC8算法用计算法实现五一期间,抽空把DS1818B20芯片的CRC8算法的计算法编制完成如下,请指教,软件在盛唐EPS11仿真编程器上测试通过,运行良好。ucharCalculateCRCValue(ucharucNewData,ucharucCRCValue){boolbXorValue;//ucharucTempValue;//模拟CRC硬件内部的8位数据寄存器ucharucCount;for(ucCount=0;ucCount<8;ucCount++){//提取新数据位与CRC寄存器的内容的异或值的D0位作为内部通道的输入bXorValue=(ucNewData^ucCRCValue)&0x01;//执行X4、X5的异或操作if(bXorValue){ucTempValue=ucCRCValue^0x18;}else{ucTempValue=ucCRCValue;}//CRC寄存器无进位右移ucTempValue>>=1;//补上进位位,即D0位if(bXorValue){ucCRCValue=ucTempValue|0x80;}else{ucCRCValue=ucTempValue;}//为处理下一位作准备ucNewData>>=1;}returnucCRCValue;}//入口参数:待校验的数据缓冲区和数据长度//测试数据,取自盛唐EPS11仿真编程器//0x280xB40xC10xE90x000x000x000xF0//DS18B2064bitRomCode//对应的校验码为:0xE10xE40x1C0x4B0x660xB80xF00x00//DS18B20的家族代码为0x28,再加上CRC校验,确保读写通讯可靠。boolDS18B20_CheckCRC8(uchar*ucDataBuff,ucharucDataLength){ucharucCRCValue;ucharucCount;ucCRCValue=0;for(ucCount=0;ucCount
/
本文档为【单片机DS18B20温度传感器C语言程序含CRC校验】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。 本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。 网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。

历史搜索

    清空历史搜索