马上就是腊月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<stc15f2k60s2.h>
#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(wendu<min)
{
P2=0xa0;P0=0x40;
P2=0x80;P0=0xfe;
}
else if((wendu>min)&&(wendu<max))
{
P2=0xa0;P0=0x00;
P2=0x80;P0=0xff;
}
else if(wendu>max)
{
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<intrins.h>
#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)
{
shanshuo=0;
}
else 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盘的概率哦~
今天文末依旧没鸡汤,赶在小年前,提前祝大家小年快乐,回家不“挨打”,嘿嘿~!


我要赚赏金
