这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界» 论坛首页» 高校专区» 坤创E-Geek/天科大新电社» 08. 单片机对DS18B20温度传感器进行数据采集和使用

共22条 1/3 1 2 3 跳转至

08. 单片机对DS18B20温度传感器进行数据采集和使用

高工
2019-01-27 23:36:24 打赏

马上就是腊月23了,也是中华民族传统的小年了。赶在小年之前,大Z在此更新一篇代码~希望给大家助力一波。

在了解了单片机片上的IO口、中断和定时计数器等资源后,今天我们来进行一个单片机与其外部器件进行数据通信的习题操练。当然,今天我们首先进行的是大家学单片机第一个接触的传感器,即温度传感器DS18B20。对这个传感器,我就不过多的进行介绍了,相信大家也都看过它的使用手册和时序图。 DS18B20是蓝桥杯竞赛考过的题目,但是不排除今年不会考到。对于蓝桥板上的传感器资源,也不过DS18B20、超声波、红外、光敏电阻+AD转换了。因此,围绕这四个板上资源出题的概率还是比较大的。很有必要进行相关练习的。

DS18B20的使用,其实并不像大家想的那么难,只需按照其时序图,一步一步的来写它的各个函数,大家只要耐心一点,都能推出来。当然请务必注意一点,对于时序图中的延时函数产生的延时,一定要务必按照时序图中所限定的范围哦~不然是采集不到正确的温度数据的。

接下来我们一起先看一下本节针对DS18B20所设计的习题(注意今天和前几天不同,今天只有一道题哦~)。但是该题却有3个要求,如下:

(1)完成DS18B20温度采集,并使用数码管上显示;

(2)超限(上限30,下限20)声光报警;

(3)利用按键可以设定上下限报警值,超上限控制继电器吸合。

说明:由于小红板上没有继电器,所以采用第五个led灯(即LED8)来模拟继电器

下面仍照惯例给出本题目的代码,并在文末给出所有代码压缩包的下载链接,需要的小可耐们,请移步下载哦~不要嫌贵,下载免费!!

-----------------------蓝桥板代码---------------------

蓝桥板代码:

/************************************************************************************************ 1、完成DS18B20温度采集,并使用数码管上显示。 2、超限(上限30,下限20)声光报警。 3、利用按键可以设定上下限报警值,超上限控制继电器吸合。 *************************************************************************************************/ #include #include"intrins.h" # #define uchar unsigned char #define uint unsigned int sbit DQ = P1^4; //单总线接口 uchar code smgtab[]={0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90,0XBF,0XFF}; uchar tt; uchar wendu; uchar min=20,max=30; uchar yi,er,san,si,wu,liu,qi,ba; uchar shezhi,jia,jian,qingchu,flag; void init(); //蓝桥杯板子初始化程序 void keyScan(); //键盘扫描 void delayms(uint z);//ms级延时函数 uchar temget(); //ds18b20获取温度 bit init_ds18b20(void);//ds18b20初始化 void timer0Init(void);//5毫秒@11.0592MHz void Delay_OneWire(unsigned int t);//ds18b20延时函数 void Write_DS18B20(unsigned char dat);//ds18b20写函数 unsigned char Read_DS18B20(void);//ds18b20读函数 void displayOne(uchar yi,uchar er);//第一 二个数码管显示函数 void displayTwo(uchar san,uchar si);//第三 四个数码管显示函数 void displayThree(uchar wu,uchar liu);//第五 六个数码管显示函数 void displayFour(uchar qi,uchar ba);//第七 八个数码管显示函数 /**********************主函数***********************************/ void main() { init(); timer0Init(); //5毫秒@11.0592MHz yi=11;er=11;san=11;si=11;wu=11;liu=11; while(1) { if(shezhi==0) { EA=1; //开总中断 ET0=1; //开定时器0中断 P2=0x80;P0=0xef; wendu=temget(); yi=11;er=11;san=11;si=11;wu=11;liu=11; qi=wendu/10; ba=wendu%10; } else if(shezhi==1) { EA=0;ET0=0; //关闭总中断与定时器0的中断 P2=0x80;P0=0x7f; if(flag==1) { if(jia==1) { jia=0; if(min>=0){min=min+1;} } else if(jian==1) { jian=0; if(min>0){min=min-1;} else if(min==0){min=0;} } } else if(flag==0) { if(jia==1){jia=0;max=max+1;} else if(jian==1){jian=0;max=max-1;} } yi=10;er=min/10;san=min%10;si=11;wu=11;liu=10;qi=max/10;ba=max%10; } keyscan(); displayOne(yi,er); displayTwo(san,si); displayThree(wu,liu); displayFour(qi,ba); } } void delayms(uint z) { uint x,y; for(x=z;x>0;x--) for(y=845;y>0;y--); } void init() { P2=0xa0; P0=0x00; //关闭继电器蜂鸣器 P2=0x80; P0=0xff; //关闭led灯 P2=0xc0; P0=0xff; //选择数码管 P2=0xff; P0=0xff; //关闭数码管 } void timer0Init(void) //5毫秒@11.0592MHz { AUXR |= 0x80; //定时器时钟1T模式 TMOD &= 0xF0; //设置定时器模式 TL0 = 0x00; //设置定时初值 TH0 = 0x28; //设置定时初值 TF0 = 0; //清除TF0标志 TR0 = 1; //定时器0开始计时 } void timer0()interrupt 1 { tt++; if(tt>=200) { tt=0; if(wendumin)&&(wendumax) { P2=0xa0;P0=0x50; //继电器开启 P2=0x80;P0=0xfe; } } } void keyScan() { if(P30==0) //s7 设置 { delayms(5); if(P30==0) { if(shezhi==0){shezhi=1;} else if(shezhi==1){shezhi=0;} } while(!P30); } else if(P31==0) //s6 修改最小值与最大值的切换 { delayms(5); if(P31==0) { if(flag==0){flag=1;} else if(flag==1){flag=0;} } while(!P31); } else if(P32==0) //s5 设置加 { delayms(5); if(P32==0) { jia=1; } while(!P32); } else if(P33==0) //s4 设置减 { delayms(5); if(P33==0) { jian=1; } while(!P33); } } //单总线延时函数 void Delay_OneWire(unsigned int t) { unsigned char i; while(t--){ for(i=0; i<8; i++); } } //通过单总线向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; } //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; } uchar temget() { uchar temp,low,high; init_ds18b20(); Write_DS18B20(0xcc); Write_DS18B20(0x44); //转换温度 Delay_OneWire(200); init_ds18b20(); Write_DS18B20(0xcc); Write_DS18B20(0xbe); low=Read_DS18B20(); //读取温度 high=Read_DS18B20(); //读取温度 temp=high<<4; temp|=(low>>4); return temp; } void displayOne(uchar yi,uchar er) { P2=0xc0; P0=0x01; //选通第一个数码管 P2=0xff; P0=smgtab[yi];//位选 delayms(1); P2=0xc0; P0=0x02; //选通第二个数码管 P2=0xff; P0=smgtab[er];//位选 delayms(1); } void displayTwo(uchar san,uchar si) { P2=0xc0; P0=0x04; //选通第三个数码管 P2=0xff; P0=smgtab[san];//位选 delayms(1); P2=0xc0; P0=0x08; //选通第四个数码管 P2=0xff; P0=smgtab[si];//位选 delayms(1); } void displayThree(uchar wu,uchar liu) { P2=0xc0; P0=0x10; //选通第五个数码管 P2=0xff; P0=smgtab[wu];//位选 delayms(1); P2=0xc0; P0=0x20; //选通第六个数码管 P2=0xff; P0=smgtab[liu];//位选 delayms(1); } void displayFour(uchar qi,uchar ba) { P2=0xc0; P0=0x40; //选通第七个数码管 P2=0xff; P0=smgtab[qi];//位选 delayms(1); P2=0xc0; P0=0x80; //选通第八个数码管 P2=0xff; P0=smgtab[ba];//位选 delayms(1); }


-----------------------小红板代码----------------------

小红板代码:

/************************************************** 1、完成DS18B20温度采集,并使用数码管上显示。 2、超限(上限30,下限20)声光报警。 3、利用按键可以设定上下限报警值,超上限控制继电器吸合。 由于小红板没有继电器模块,因此用LED8点亮来模拟继电器开启 **************************************************/ #include"reg52.h" #include #define uchar unsigned char #define uint unsigned int sbit P_HC595_SER = P2^7; //pin 14 SER data input sbit P_HC595_RCLK = P2^5; //pin 12 RCLk store (latch) clock sbit P_HC595_SRCLK = P2^6; //pin 11 SRCLK Shift data clock sbit s5=P3^0; sbit s10=P3^1; sbit s15=P3^2; sbit s20=P3^3; sbit DQ = P2^2; //单总线接口 sbit beep=P2^3; //蜂鸣器 uchar code smgtab[]={0X3F,0X06,0X5B,0X4F,0X66,0X6D,0X7D,0X07,0X7F,0X6F,0X40,0X00}; //共阴数码管段值 bit fla; uchar min=20,max=30; uchar wendu,tt; uchar shanshuo; uchar shezhi,jia,jian,qingchu,flag; uchar yi,er,san,si,wu,liu,qi,ba; uchar temget();//ds18b20获取温度 void smg_Init();//数码管初始化函数 void delayms(uint z);//ms级延时函数 bit init_ds18b20(void);//ds18b20初始化 void timer0Init(void); //50毫秒@11.0592MHz void keyScan();//键盘扫描 void Send_595(unsigned char dat); void Delay_OneWire(unsigned int t); //ds18b20延时函数 void Write_DS18B20(unsigned char dat);//ds18b20写函数 unsigned char Read_DS18B20(void);//ds18b20读函数 void displayOne(uchar yi,uchar er);//第一 二个数码管显示函数 void displayTwo(uchar san,uchar si);//第三 四个数码管显示函数 void displayThree(uchar wu,uchar liu);//第五 六个数码管显示函数 void displayFour(uchar qi,uchar ba);//第七 八个数码管显示函数 /*****************************主函数**********************************************/ void main() { smg_Init(); timer0Init(); while(1) { if(shezhi==0) //未设置前只显示当前室温 { EA=1; //开总中断 ET0=1; //开定时器0中断 wendu=temget(); if(wendu=min)&&(wendu<=max)) { shanshuo=1; } else if(wendu>max) { beep=0; P1=0xef; //由于小红板没有继电器模块,因此用LED8点亮来模拟继电器开启 } yi=11;er=11;san=11;si=11;wu=11;liu=11; qi=wendu/10; ba=wendu%10; } else if(shezhi==1) //设置后可以调整温度上下限值 { EA=0;ET0=0; beep=1; if(flag==0) { if(jia==1){jia=0;max=max+1;} else if(jian==1){jian=0;max=max-1;} } else if(flag==1) { if(jia==1) { jia=0; if(min>=0){min=min+1;} } else if(jian==1) { jian=0; if(min>0){min=min-1;} else if(min==0){min=0;} } } yi=10;er=min/10;san=min%10;si=11;wu=11;liu=10;qi=max/10;ba=max%10; } keyScan(); displayOne(yi,er); displayTwo(san,si); displayThree(wu,liu); displayFour(qi,ba); } } void delayms(uint z) { uint x,y; for(x=z;x>0;x--) for(y=110;y>0;y--); } void smg_Init() { Send_595(0x00); //同时选择8个数码管 Send_595(0x00); //让8个数码管同时显示消隐字符 P_HC595_RCLK = 0; P_HC595_RCLK = 1; //使用P2.5制造一个上升沿将这两个字节数据同时送给数码管,完成段选和位选 } void Send_595(unsigned char dat) //发送一个字节 { unsigned char i; for(i=0; i<8; i++) { if(dat & 0x80) //判断dat的最高位是否为1 P_HC595_SER = 1; //最高位如果为1,则令P2.7 = 1 else P_HC595_SER = 0; //最高位如果为0,则令P2.7 = 0 P_HC595_SRCLK = 0; P_HC595_SRCLK = 1; P_HC595_SRCLK = 0; //使用P2.6制造一个上升沿将这一位数据送到74HC595的QA输出端 dat = dat << 1; //将dat左移一位,取次高位 } } void timer0Init(void) //50毫秒@11.0592MHz { TR0 = 1;//启动T0 TMOD = 0x01;//T0为定时器,工作模式1 16位计数器 TH0 = 0x4b; TL0 = 0xfc;//0x4bfc 定时50ms } void timer0()interrupt 1 { tt++; if((shanshuo==0)&&(tt==8)) //室温小于设定值 { tt=0; if(fla==0) {fla=1;P1=0XFE;beep=0;} //D3闪烁 else if(fla==1){fla=0;P1=0XFF;beep=0;} } else if((shanshuo==1)&&(tt==6)) //室温在最小值与最大值之间 { tt=0; if(fla==0) {fla=1;P1=0XFD;beep=1;} //D4闪烁 else if(fla==1){fla=0;P1=0XFF;beep=1;} } } void keyScan() { if(s5==0) //s5 //设置 { delayms(5); if(s5==0) { if(shezhi==0){shezhi=1;} else if(shezhi==1){shezhi=0;} } while(!s5); } else if(s10==0) //s10 { delayms(5); if(s10==0) { if(flag==0){flag=1;} //切换温度上下限的状态 else if(flag==1){flag=0;} } while(!s10); } else if(s15==0) //s15 设置加 { delayms(5); if(s15==0) { jia=1; } while(!s15); } else if(s20==0) //s20 设置减 { delayms(5); if(s20==0) { jian=1; } while(!s20); } } void displayOne(uchar yi,uchar er) { Send_595(0xfe); //选通第一个数码管 Send_595(smgtab[yi]);//段选 P_HC595_RCLK = 0; P_HC595_RCLK = 1; //使用P2.5制造一个上升沿将这两个字节数据同时送给数码管,完成段选和位选 delayms(1); Send_595(0xfd); //选通第二个数码管 Send_595(smgtab[er]);//段选 P_HC595_RCLK = 0; P_HC595_RCLK = 1; //使用P2.5制造一个上升沿将这两个字节数据同时送给数码管,完成段选和位选 delayms(1); } void displayTwo(uchar san,uchar si) { Send_595(0xfb); //选通第三个数码管 Send_595(smgtab[san]);//段选 P_HC595_RCLK = 0; P_HC595_RCLK = 1; //使用P2.5制造一个上升沿将这两个字节数据同时送给数码管,完成段选和位选 delayms(1); Send_595(0xf7); //选通第四个数码管 Send_595(smgtab[si]);//段选 P_HC595_RCLK = 0; P_HC595_RCLK = 1; //使用P2.5制造一个上升沿将这两个字节数据同时送给数码管,完成段选和位选 delayms(1); } void displayThree(uchar wu,uchar liu) { Send_595(0xef); //选通第五个数码管 Send_595(smgtab[wu]);//段选 P_HC595_RCLK = 0; P_HC595_RCLK = 1; //使用P2.5制造一个上升沿将这两个字节数据同时送给数码管,完成段选和位选 delayms(1); Send_595(0xdf); //选通第六个数码管 Send_595(smgtab[liu]);//段选 P_HC595_RCLK = 0; P_HC595_RCLK = 1; //使用P2.5制造一个上升沿将这两个字节数据同时送给数码管,完成段选和位选 delayms(1); } void displayFour(uchar qi,uchar ba) { Send_595(0xbf); //选通第七个数码管 Send_595(smgtab[qi]);//段选 P_HC595_RCLK = 0; P_HC595_RCLK = 1; //使用P2.5制造一个上升沿将这两个字节数据同时送给数码管,完成段选和位选 delayms(1); Send_595(0x7f); //选通第八个数码管 Send_595(smgtab[ba]);//段选 P_HC595_RCLK = 0; P_HC595_RCLK = 1; //使用P2.5制造一个上升沿将这两个字节数据同时送给数码管,完成段选和位选 delayms(1); } /********************************************************************************************** ds18b20驱动函数 /***********************************************************************************************/ //单总线延时函数 void Delay_OneWire(unsigned int t) { while(t--); } //通过单总线向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; } //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; } uchar temget() { uchar temp,low,high; init_ds18b20(); Write_DS18B20(0xcc); Write_DS18B20(0x44); //温度转换 Delay_OneWire(200); init_ds18b20(); Write_DS18B20(0xcc); Write_DS18B20(0xbe); low=Read_DS18B20(); //读温度 high=Read_DS18B20(); //读温度 temp=high<<4; temp|=(low>>4); return temp; } /***************************************************************************************/


----------------所有代码打包下载链接------------------

08单片机对DS18B20温度传感器进行数据和使用_全部代码打包.zip

大家可以继续提前接着往下进行09.单片机进行AD转换并存储(EEPROM)的题目练习~如对代码有任何问题,请回帖留言咯。别忘了,常来留言会增加得到U盘的概率哦~

今天文末依旧没鸡汤,赶在小年前,提前祝大家小年快乐,回家不“挨打”,嘿嘿~!





关键词: DS18B20 DS18B20 单片机 数据采集

助工
2019-01-27 23:55:46 打赏
2楼
哈哈,占个沙发,给楼主点赞

管理员
2019-01-28 09:28:44 打赏
3楼

谢谢楼主分享


院士
2019-01-28 09:59:31 打赏
4楼

这个温传非常考验时序的处理。

可以充分理解定时器的使用,大家努力学习啊


高工
2019-01-28 10:45:49 打赏
5楼

支持楼主,点赞。如果多取几个温度值来求平均值,输出数据更稳定准确呦。


菜鸟
2019-01-28 12:15:55 打赏
6楼

关于定时器装初值有个小疑问

平时用的比较多的是

TH0 = (65536-46080)/256;
TL0 = (65536-46080)%256;

而这种确实没见过 ,为啥0x4bfc是50ms ?

TH0 = 0x4b;

TL0 = 0xfc;//0x4bfc 定时50ms


菜鸟
2019-01-28 15:24:21 打赏
7楼

一样道理的,只是16进制转10进制,没啥不同的


菜鸟
2019-01-28 15:26:10 打赏
8楼

只是不同的人写法不一样而已,


高工
2019-01-28 15:38:13 打赏
9楼

用stc-isp烧录软件可以生成定时器的,比较节省时间。生成的就是初值就是十六进制的。了解一下QQ图片20190128153139.png


菜鸟
2019-01-28 15:38:57 打赏
10楼

(65536-(50000/1.08))/256算出结果为19452,而19452的高8位为4B,低八位为fc,高8位给值是TH0,低八位给值是Tl0;



共22条 1/3 1 2 3 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册]