课设

您所在的位置:网站首页 春节前通常有哪些准备活动 课设

课设

#课设| 来源: 网络整理| 查看: 265

51单片机PM2.5+温湿度(程序+原理图+Protel仿真) 一、功能二、模块三、代码程序四、PCB原理图 在这里插入图片描述

一、功能

本系统以STC89C52单片机为核心,主要包括传感器温湿度采集,传感器PM2.5采集,LCD液晶显示,声光报警和按键设置等部分。系统通过搭建的传感器元件采集家居中温度、湿度和PM2.5浓度,并实时显示上述采集数据。

二、模块

2.1、PM 2.5模块 在这里插入图片描述模块引脚说明: 在这里插入图片描述采集数据对照: 在这里插入图片描述

2.2、DHT11温湿度传感器: 在这里插入图片描述 模块接口说明

在这里插入图片描述DHT11数据格式:一次完整的数据传输为40bit,高位先出。 数据格式: 8bit湿度整数数据 +8bit湿度小数数据 +8bi温度整数数据 +8bit温度小数数据 +8bit校验和 数据传送正确时校验和数据等于**“ 8bit湿度整数数据+8bit湿度小数数据+8bi温度整数数据+8bit温度小数数据”** 所得结果的末8位。

三、代码程序 #include #include #define uchar unsigned char // 以后unsigned char就可以用uchar代替 #define uint unsigned int // 以后unsigned int 就可以用uint 代替 sfr ISP_DATA = 0xe2; // 数据寄存器 sfr ISP_ADDRH = 0xe3; // 地址寄存器高八位 sfr ISP_ADDRL = 0xe4; // 地址寄存器低八位 sfr ISP_CMD = 0xe5; // 命令寄存器 sfr ISP_TRIG = 0xe6; // 命令触发寄存器 sfr ISP_CONTR = 0xe7; // 命令寄存器 sbit LcdRs_P = P1^2; // 1602液晶的RS管脚 sbit LcdRw_P = P1^3; // 1602液晶的RW管脚 sbit LcdEn_P = P1^4; // 1602液晶的EN管脚 sbit KeySet_P = P3^2; // “设置”按键的管脚 sbit KeyDown_P = P3^3; // “减”按键的管脚 sbit KeyUp_P = P3^4; // “加”按键的管脚 sbit Buzzer_P = P1^5; // 蜂鸣器 sbit DHT11_P = P1^1; // 温湿度传感器DHT11数据接入 sbit LedTH_P = P2^0; // 温度过高报警指示灯 sbit LedTL_P = P2^1; // 温度过低报警指示灯 sbit LedHH_P = P2^2; // 湿度过高报警指示灯 sbit LedHL_P = P2^3; // 湿度过低报警指示灯 sbit LedPM_P = P2^4; // PM2.5过高报警指示灯 uchar temp; // 保存温度 uchar humi; // 保存湿度 uint pm; // 保存PM2.5 uchar gIndex=0; // 串口接收索引 uint Value[20]={0}; // 串口数据缓存区 uchar AlarmTL; // 温度下限报警值 uchar AlarmTH; // 温度上限报警值 uchar AlarmHL; // 湿度下限报警值 uchar AlarmHH; // 湿度上限报警值 uint AlarmPM; // PM2.5报警值 /*********************************************************/ // 单片机内部EEPROM不使能 /*********************************************************/ void ISP_Disable() { ISP_CONTR = 0; ISP_ADDRH = 0; ISP_ADDRL = 0; } /*********************************************************/ // 从单片机内部EEPROM读一个字节,从0x2000地址开始 /*********************************************************/ unsigned char EEPROM_Read(unsigned int add) { ISP_DATA = 0x00; ISP_CONTR = 0x83; ISP_CMD = 0x01; ISP_ADDRH = (unsigned char)(add>>8); ISP_ADDRL = (unsigned char)(add&0xff); // 对STC89C51系列来说,每次要写入0x46,再写入0xB9,ISP/IAP才会生效 ISP_TRIG = 0x46; ISP_TRIG = 0xB9; _nop_(); ISP_Disable(); return (ISP_DATA); } /*********************************************************/ // 往单片机内部EEPROM写一个字节,从0x2000地址开始 /*********************************************************/ void EEPROM_Write(unsigned int add,unsigned char ch) { ISP_CONTR = 0x83; ISP_CMD = 0x02; ISP_ADDRH = (unsigned char)(add>>8); ISP_ADDRL = (unsigned char)(add&0xff); ISP_DATA = ch; ISP_TRIG = 0x46; ISP_TRIG = 0xB9; _nop_(); ISP_Disable(); } /*********************************************************/ // 擦除单片机内部EEPROM的一个扇区 // 写8个扇区中随便一个的地址,便擦除该扇区,写入前要先擦除 /*********************************************************/ void Sector_Erase(unsigned int add) { ISP_CONTR = 0x83; ISP_CMD = 0x03; ISP_ADDRH = (unsigned char)(add>>8); ISP_ADDRL = (unsigned char)(add&0xff); ISP_TRIG = 0x46; ISP_TRIG = 0xB9; _nop_(); ISP_Disable(); } /*********************************************************/ // 毫秒级的延时函数,time是要延时的毫秒数 /*********************************************************/ void DelayMs(uint time) { uint i,j; for(i=0;i bit bit_i; uchar j; uchar dat=0; for(j=0;j bit_i=1; while(DHT11_P); } else { bit_i=0; } dat temp=TemHig; // 将温度的检测结果赋值给全局变量temp humi=HumiHig; // 将湿度的检测结果赋值给全局变量humi } } /*********************************************************/ // 1602液晶写命令函数,cmd就是要写入的命令 /*********************************************************/ void LcdWriteCmd(uchar cmd) { LcdRs_P = 0; LcdRw_P = 0; LcdEn_P = 0; P0=cmd; DelayMs(2); LcdEn_P = 1; DelayMs(2); LcdEn_P = 0; } /*********************************************************/ // 1602液晶写数据函数,dat就是要写入的数据 /*********************************************************/ void LcdWriteData(uchar dat) { LcdRs_P = 1; LcdRw_P = 0; LcdEn_P = 0; P0=dat; DelayMs(2); LcdEn_P = 1; DelayMs(2); LcdEn_P = 0; } /*********************************************************/ // 1602液晶初始化函数 /*********************************************************/ void LcdInit() { LcdWriteCmd(0x38); // 16*2显示,5*7点阵,8位数据口 LcdWriteCmd(0x0C); // 开显示,不显示光标 LcdWriteCmd(0x06); // 地址加1,当写入数据后光标右移 LcdWriteCmd(0x01); // 清屏 } /*********************************************************/ // 液晶光标定位函数 /*********************************************************/ void LcdGotoXY(uchar line,uchar column) { // 第一行 if(line==0) LcdWriteCmd(0x80+column); // 第二行 if(line==1) LcdWriteCmd(0x80+0x40+column); } /*********************************************************/ // 液晶输出数字(PM2.5的) /*********************************************************/ void LcdPrintNum1(uint num) { LcdWriteData(num/100+48); // 百位 LcdWriteData(num%100/10+48); // 十位 LcdWriteData(num%10+48); // 个位 } /*********************************************************/ // 液晶输出数字(温湿度的) /*********************************************************/ void LcdPrintNum2(uchar num) { LcdWriteData(num/10+48); // 十位 LcdWriteData(num%10+48); // 个位 } /*********************************************************/ // 液晶输出字符串函数 /*********************************************************/ void LcdPrintStr(uchar *str) { while(*str!='\0') LcdWriteData(*str++); } /*********************************************************/ // 液晶显示内容初始化 /*********************************************************/ void LcdShowInit() { LcdGotoXY(0,0); // 液晶光标定位到第0行第0列 LcdPrintStr(" PM2.5: ug/m3 "); // 显示内容 LcdGotoXY(1,0); // 液晶光标定位到第1行第0列 LcdPrintStr("T: C H: %RH"); // 显示内容 LcdGotoXY(1,4); // 温度单位摄氏度上面的圆圈符号 LcdWriteData(0xdf); } /*********************************************************/ // 串口初始化 /*********************************************************/ void UartInit() { SCON = 0x50; // 配置串口寄存器 TMOD = 0x20; // 配置定时器寄存器 TH1 = 0xf4; // 计算波特率的值为2400 TL1 = 0xf4; // 计算波特率的值为2400 EA = 1; // 打开总中断 ES = 1; // 打开串口中断 TR1 = 1; // 启动定时器 } /*********************************************************/ // 按键扫描 /*********************************************************/ void KeyScanf() { if(KeySet_P==0) // 判断设置按键是否被按下 { EA=0; /*将液晶显示改为设置温度的页面****************************************************/ LcdWriteCmd(0x01); LcdGotoXY(0,0); LcdPrintStr("Temperature Set "); LcdGotoXY(1,0); LcdPrintStr(" - C "); LcdGotoXY(1,10); LcdWriteData(0xdf); LcdGotoXY(1,4); // 在液晶上填充温度的下限值 LcdPrintNum2(AlarmTL); LcdGotoXY(1,7); // 在液晶上填充温度的上限值 LcdPrintNum2(AlarmTH); LcdGotoXY(1,5); // 光标定位到第1行第5列 LcdWriteCmd(0x0f); // 光标闪烁 DelayMs(10); // 去除按键按下的抖动 while(!KeySet_P); // 等待按键释放 DelayMs(10); // 去除按键松开的抖动 /*设置温度的下限值****************************************************************/ while(KeySet_P) // “设置键”没有被按下,则一直处于温度下限的设置 { if(KeyDown_P==0) // 判断 “减按键“ 是否被按下 { if(AlarmTL>0) // 只有当温度下限值大于0时,才能减1 AlarmTL--; LcdGotoXY(1,4); // 重新刷新显示更改后的温度下限值 LcdPrintNum2(AlarmTL); LcdGotoXY(1,5); // 重新定位闪烁的光标位置 DelayMs(350); // 延时 } if(KeyUp_P==0) // 判断 “加按键“ 是否被按下 { if(AlarmTL if(AlarmTH>0) // 只有当温度上限值大于0时,才能减1 AlarmTH--; LcdGotoXY(1,7); // 重新刷新显示更改后的温度上限值 LcdPrintNum2(AlarmTH); LcdGotoXY(1,8); // 重新定位闪烁的光标位置 DelayMs(350); // 延时 } if(KeyUp_P==0) // 判断 “加按键“ 是否被按下 { if(AlarmTH if(AlarmHL>0) // 只有当湿度下限值大于0时,才能减1 AlarmHL--; LcdGotoXY(1,4); // 重新刷新显示更改后的湿度下限值 LcdPrintNum2(AlarmHL); LcdGotoXY(1,5); // 重新定位闪烁的光标位置 DelayMs(350); } if(KeyUp_P==0) // 判断 “加按键“ 是否被按下 { if(AlarmHL if(AlarmHH>0) // 只有当湿度上限值大于0时,才能减1 AlarmHH--; LcdGotoXY(1,7); // 重新刷新显示更改后的湿度上限值 LcdPrintNum2(AlarmHH); LcdGotoXY(1,8); // 重新定位闪烁的光标位置 DelayMs(350); } if(KeyUp_P==0) // 判断 “加按键“ 是否被按下 { if(AlarmHH if(AlarmPM>1) // 只有gAlarmPM大于1才能减1 AlarmPM--; LcdGotoXY(1,4); // 液晶光标定位 LcdPrintNum1(AlarmPM); // 刷新改变后的报警值 LcdGotoXY(1,6); DelayMs(200); // 延时一下 } if(KeyUp_P==0) // 判断 “加按键“ 是否被按下 { if(AlarmPM LedTH_P=0; LedTL_P=1; } else if(temp LedTH_P=1; LedTL_P=1; } /*湿度*/ if(humi>AlarmHH) // 湿度是否过高 { LedHH_P=0; LedHL_P=1; } else if(humi LedHH_P=1; LedHL_P=1; } /*PM2.5*/ if(pm>AlarmPM) LedPM_P=0; else LedPM_P=1; /*蜂鸣器*/ if((LedHH_P==0)||(LedHL_P==0)||(LedTH_P==0)||(LedTL_P==0)||(LedPM_P==0)) // 蜂鸣器判断,只要至少1个报警灯亮,蜂鸣器就报警 Buzzer_P=0; else Buzzer_P=1; } /*********************************************************/ // 报警值初始化 /*********************************************************/ void AlarmInit(void) { AlarmTL=EEPROM_Read(0x2000); // 从EEPROM的0x2000这个地址读取温度的报警下限 AlarmTH=EEPROM_Read(0x2001); // 从EEPROM的0x2001这个地址读取温度的报警上限 AlarmHL=EEPROM_Read(0x2002); // 从EEPROM的0x2002这个地址读取湿度的报警下限 AlarmHH=EEPROM_Read(0x2003); // 从EEPROM的0x2003这个地址读取湿度的报警上限 AlarmPM=EEPROM_Read(0x2004)*100+EEPROM_Read(0x2005); // 读取PM2.5报警值 if((AlarmTL==0)||(AlarmTL>100)) // 如果温度下限报警值读出来异常(等于0或大于100),则重新赋值 AlarmTL=20; if((AlarmTH==0)||(AlarmTH>100)) // 如果温度上限报警值读出来异常(等于0或大于100),则重新赋值 AlarmTH=35; if((AlarmHL==0)||(AlarmHL>100)) // 如果温度下限报警值读出来异常(等于0或大于100),则重新赋值 AlarmHL=40; if((AlarmHH==0)||(AlarmHH>100)) // 如果温度上限报警值读出来异常(等于0或大于100),则重新赋值 AlarmHH=85; if((AlarmPM==0)||(AlarmPM>1300)) // 如果读取到的报警值异常,则重新赋值 AlarmPM=200; } /*********************************************************/ // 主函数 /*********************************************************/ void main(void) { uchar i; // 循环变量 uint ret; // 保存PM2.5测量结果 LcdInit(); // 液晶功能初始化 LcdShowInit(); // 液晶显示初始化 UartInit(); // 串口初始化 AlarmInit(); // 报警值初始化 while(1) { /*PM2.5的读取*/ ret=0; // 清零测量结果 for(i=0;i KeyScanf(); // 按键判断 DelayMs(10); } } } /*********************************************************/ // 串口中断服务程序 /*********************************************************/ void UartInt(void) interrupt 4 { uchar VoutH,VoutL; if(RI==1) { RI=0; if(SBUF==0xAA) // 起始位 { while(!RI); VoutH=SBUF; // Vout(H) RI=0; while(!RI); VoutL=SBUF; // Vout(L) RI=0; while(!RI); // Vref(H) RI=0; while(!RI); // Vref(L) RI=0; while(!RI); // 校验位 RI=0; while(!RI); // 停止位 RI=0; Value[gIndex]=VoutH*256+VoutL; gIndex++; if(gIndex==20) gIndex=0; } } } 四、PCB原理图

在这里插入图片描述

项目的仿真和程序代码工程和原理图已经放在下面公众号里面,可以关注公众号:Kevin的学习站,输入关键字:“51单片机PM2.5+温湿度”,就可以免费获取啦!创作不易,但您的点赞、关注、收藏就是对我最大的鼓励! 在这里插入图片描述



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3