单片机论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 4061|回复: 19
收起左侧

基于STC89C52单片机空气PM2.5系统设计资料(仿真+论文+源码)

  [复制链接]
mwnn 发表于 2018-3-17 09:18 | 显示全部楼层 |阅读模式
这是我之前做的单片机毕业设计,差不多花了我两个月时间,附件里面包含PM2.5系统的单片机源代码,用AD画的原理图,PCB图
还有proteus仿真工程文件以及课程设计的文档,另外还有成品实物图,请大家多多指教!
单片机按键简介.png IMG_20171217_163136.jpg IMG_20171217_162918.jpg

仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
0.png

单片机源程序如下:
  1. #include <reg52.h>
  2. #include <intrins.h>
  3. #define uint unsigned int
  4. #define uchar unsigned char //宏定义
  5. sbit RS=P1^6;//液晶接口
  6. sbit EN=P1^7;

  7. sbit LED = P2^0;//粉尘传感器控制接口

  8. sbit ADCS = P3^7;//AD0832接口
  9. sbit ADCLK =P3^5;
  10. sbit ADDI = P3^6;
  11. sbit ADDO = P3^6;                  

  12. sbit SET= P1^1;//按键接口
  13. sbit ADD= P1^2;
  14. sbit DEC= P1^3;

  15. sbit BEEP=P2^1;//蜂鸣器接口

  16. uchar set_st;
  17. uchar tab[5];
  18. uint DUST_SET=150; //固体颗粒的阈值

  19. //bit shanshuo_st; //闪烁间隔标志
  20. bit beep_st; //蜂鸣器间隔标志
  21. uchar x=4; //计数器
  22. //定义标识
  23. uchar FlagStart = 0;
  24. float DUST_Value;
  25. uint DUST;
  26. uchar num=0;
  27. uchar mm;
  28. uchar abc;
  29. uchar ADC_Get[10]={0}; //定义AD采样数组
  30. uchar str[5]={0};

  31. /*****初始化定时器0*****/
  32. void InitTimer(void)
  33. {
  34.         TMOD = 0x01;
  35.         TL0 = (65536-10000)/256; //定时10ms
  36.         TH0 = (65536-10000)%256;
  37.         TR0 = 1;
  38.         ET0 = 1;
  39.         EA = 1;
  40. }
  41. /*************************lcd1602程序**************************/
  42. void delay1ms(uint ms)//延时1毫秒
  43. {
  44.     uint i,j;
  45.         for(i=0;i<ms;i++)
  46.         for(j=0;j<100;j++);
  47. }

  48. void wr_com(uchar com)//写指令//
  49. {
  50.     delay1ms(1);
  51.         RS=0;
  52. //        RW=0;
  53.         EN=0;
  54.         P0=com;
  55.         delay1ms(1);
  56.         EN=1;
  57.         delay1ms(1);
  58.         EN=0;
  59. }
  60. void wr_dat(uchar dat)//写数据//
  61. {
  62.     delay1ms(1);;
  63.         RS=1;
  64. //        RW=0;
  65.         EN=0;
  66.         P0=dat;
  67.         delay1ms(1);
  68.         EN=1;
  69.         delay1ms(1);
  70.         EN=0;
  71. }
  72. /*****************************液晶初始化
  73. *********************************************/
  74. void lcd_init()//初始化设置//
  75. {
  76.         delay1ms(15);
  77.         wr_com(0x38);
  78.         delay1ms(5);
  79.         wr_com(0x01);
  80.         delay1ms(5);
  81.         wr_com(0x06);
  82.         delay1ms(5);
  83.         wr_com(0x0c);
  84.         delay1ms(5);

  85.         wr_com(0x80);
  86.         wr_dat('P');//
  87.         wr_com(0x81);
  88.         wr_dat('M');//:
  89.         wr_com(0x82);
  90.         wr_dat('2');//
  91.         wr_com(0x83);
  92.         wr_dat('.');//:
  93.         wr_com(0x84);
  94.         wr_dat('5');//:
  95.         wr_com(0x85);
  96.         wr_dat(':');


  97.         wr_com(0x8b);
  98.         wr_dat('m');
  99.         wr_com(0x8c);
  100.         wr_dat('g');
  101.         wr_com(0x8d);
  102.         wr_dat('/');
  103.         wr_com(0x8e);
  104.         wr_dat('m');
  105.         wr_com(0x8f);
  106.         wr_dat('3');
  107.        


  108. /////////////////////////////////////

  109.         wr_com(0xc0);
  110.         wr_dat('A');
  111.         wr_com(0xc1);
  112.         wr_dat('l');
  113.         wr_com(0xc2);
  114.         wr_dat('a');
  115.         wr_com(0xc3);
  116.         wr_dat('r');
  117.         wr_com(0xc4);
  118.         wr_dat('m');
  119.         wr_com(0xc5);
  120.         wr_dat(':');

  121.         wr_com(0xcb);
  122.         wr_dat('m');
  123.         wr_com(0xcc);
  124.         wr_dat('g');
  125.         wr_com(0xcd);
  126.         wr_dat('/');
  127.         wr_com(0xce);
  128.         wr_dat('m');
  129.         wr_com(0xcf);
  130.         wr_dat('3');
  131. }
  132. /*****************显示函数******************************/
  133. void disp(unsigned int Data)//PM2.5值显示
  134. {
  135.         uint Temp;
  136.         Temp=Data%10000;
  137.         str[0]=Temp/1000+0x30; //千位
  138.         Temp%=1000;
  139.         str[1]='.';
  140.         str[2]=Temp/100+0x30; //百位
  141.         Temp%=100;
  142.         str[3]=Temp/10+0x30; //十位
  143.         str[4]=Temp%10+0x30; //个位
  144.         wr_com(0x86);
  145.         wr_dat(str[0]);
  146.         wr_com(0x87);
  147.         wr_dat(str[1]);
  148.         wr_com(0x88);
  149.         wr_dat(str[2]);
  150.         wr_com(0x89);
  151.         wr_dat(str[3]);
  152.         wr_com(0x8a);
  153.         wr_dat(str[4]);

  154. }
  155. /************************报警值显示************************************/
  156. void baojing()
  157. {
  158.         wr_com(0xc6);
  159.         wr_dat(tab[0]+0x30);
  160.         wr_com(0xc7);
  161.         wr_dat(tab[1]);
  162.         wr_com(0xc8);
  163.         wr_dat(tab[2]+0x30);
  164.         wr_com(0xc9);
  165.         wr_dat(tab[3]+0x30);
  166.         wr_com(0xca);
  167.         wr_dat(tab[4]+0x30);
  168. }
  169. /*****延时子程序*****/
  170. void Delay(uint num)
  171. {
  172. while( --num );
  173. }
  174. /**************************按键检测
  175. *******************************************/
  176. void checkkey()
  177. {
  178.         if(SET==0)
  179.         {
  180.         Delay(2000);
  181.         do{}while(SET==0);
  182.         set_st++;
  183.         if(set_st>1)set_st=0;
  184.         }
  185.         if(set_st==0)
  186.         {
  187.         }
  188.         else if(set_st==1)
  189.         {
  190.         if(DEC==0)
  191.         {
  192.         Delay(2000);
  193.         do{}while(DEC==0);
  194.         if(DUST_SET>0)DUST_SET--;
  195.         if(DUST_SET==0)DUST_SET=0;
  196.         }
  197.         if(ADD==0)
  198.         {
  199.         Delay(2000);
  200.         do{}while(ADD==0);
  201.         DUST_SET++;
  202.         if(DUST_SET>800)DUST_SET=800;
  203.         }
  204.         }
  205.         tab[0]=DUST_SET/1000;
  206.         tab[1]='.';
  207.         tab[2]=DUST_SET%1000/100;
  208.         tab[3]=DUST_SET%100/10;
  209.         tab[4]=DUST_SET%10;
  210. }
  211. /*****报警子程序*****/
  212. void Alarm()
  213. {
  214.         if(x>=10){beep_st=~beep_st;x=0;}
  215.         if(DUST>DUST_SET&&beep_st==1)BEEP=0;
  216.         else BEEP=1;
  217. //        if(DUST>0&&DUST<100){LED2=0;LED3=1;LED4=1;}
  218. //        if(DUST>=10&&DUST<300){LED2=1;LED3=0;LED4=1;}
  219. //        if(DUST>=300){LED2=1;LED3=1;LED4=0;}
  220.         }
  221. /**************************AD0832转换程序
  222. ***********************************************/
  223. uchar ADC0832(bit mode,bit channel) //AD转换,返回结果
  224. {
  225.         uchar i,dat,ndat;
  226.         ADCS = 0;//拉低CS端
  227.         _nop_();
  228.         _nop_();
  229.         ADDI = 1; //第1个下降沿为高电平
  230.         ADCLK = 1;//拉高CLK端
  231.         _nop_();
  232.         _nop_();
  233.         ADCLK = 0;//拉低CLK端,形成下降沿1
  234.         _nop_();
  235.         _nop_();
  236.         ADDI = mode; //低电平为差分模式,高电平为单通道模式。
  237.         ADCLK = 1;//拉高CLK端
  238.         _nop_();
  239.         _nop_();
  240.         ADCLK = 0;//拉低CLK端,形成下降沿2
  241.         _nop_();
  242.         _nop_();
  243.         ADDI = channel; //低电平为CH0,高电平为CH1
  244.         ADCLK = 1;//拉高CLK端
  245.         _nop_();
  246.         _nop_();
  247.         ADCLK = 0;//拉低CLK端,形成下降沿3
  248.         ADDI = 1;//控制命令结束(经试验必需)
  249.         dat = 0;
  250.         //下面开始读取转换后的数据,从最高位开始依次输出(D7~D0)
  251.         for(i = 0;i < 8;i++)
  252.         {
  253.         dat <<= 1;
  254.         ADCLK=1;//拉高时钟端
  255.         _nop_();
  256.         _nop_();
  257.         ADCLK=0;//拉低时钟端形成一次时钟脉冲
  258.         _nop_();
  259.         _nop_();
  260.         dat |= ADDO;
  261.         }
  262.         ndat = 0; //记录D0
  263.         if(ADDO == 1)
  264.         ndat |= 0x80;
  265.         //下面开始继续读取反序的数据(从D1到D7)
  266.         for(i = 0;i < 7;i++)
  267.         {
  268.         ndat >>= 1;
  269.         ADCLK = 1;//拉高时钟端
  270.         _nop_();
  271.         _nop_();
  272.         ADCLK=0;//拉低时钟端形成一次时钟脉冲
  273.         _nop_();
  274.         _nop_();
  275.         if(ADDO==1)
  276.         ndat |= 0x80;
  277.         }
  278.         ADCS=1;//拉高CS端,结束转换
  279.         ADCLK=0;//拉低CLK端
  280.         ADDI=1;//拉高数据端,回到初始状态
  281.         if(dat==ndat)
  282.         return(dat);
  283.         else
  284.         return 0;
  285. }
  286. /*****定时器0中断服务程序*****/
  287. void timer0(void) interrupt 1
  288. {
  289.         uint j;
  290.         TL0 = (65536-10000)/256; //定时10ms
  291.         TH0 = (65536-10000)%256;
  292.         LED=1; //开启传感器的LED
  293.         x++;
  294.         for (j=0;j<30;j++); //0.28ms //延时0.28ms
  295.         abc=ADC0832(1,0); //开启ADC采集
  296.         FlagStart=1;
  297.         TR0 = 0; //先关闭定时器0
  298.         EA = 0;
  299.         LED=0;//关闭传感器LED
  300. }
  301. //中值滤波
  302. //算法:先进行排序,然后将数组的中间值作为当前值返回。
  303. uchar Error_Correct(uchar *str,uchar num)
  304. {
  305.         unsigned char i=0;
  306.         unsigned char j=0;
  307.         unsigned char Temp=0;
  308.         //排序
  309.         for(i=0;i<num-1;i++)
  310.         {
  311.         for(j=i+1;j<num;j++)
  312.         {
  313.            if(str[i]<str[j])
  314.                 {
  315.                 Temp=str[i];
  316.                 str[i]=str[j];
  317.                 str[j]=Temp;
  318.                 }
  319.         }
  320. }

  321.         //去除误差,取中间值
  322.         return str[num/2];
  323. }
  324. /*****主函数*****/
  325. void main(void)
  326. {
  327.         InitTimer(); //初始化定时器
  328.         BEEP=1;
  329.         lcd_init();//初始化显示
  330.         delay1ms(500);
  331.         while(1)
  332.         {

  333.          checkkey();//按键检测
  334.         if(set_st==0)
  335.         {
  336.                 //wr_com(0x0c);
  337.                 if(FlagStart==1) //1次数据采集完成
  338.                 {
  339.                 num++;
  340.                 ADC_Get[num]=abc;
  341.                 if(num>9)
  342.                 {
  343.                 num=0;
  344. //                DUST=Error_Correct(ADC_Get,10); //求取10次AD采样的值
  345. //                DUST_Value=(DUST/256.0)*5000; //转化成电压值MV
  346. //                DUST_Value=DUST_Value*0.17-100; //固体悬浮颗粒浓度计算 Y=0.17*X-0.1 X--采样电压V
  347.        
  348.                 DUST=Error_Correct(ADC_Get,10);
  349.             DUST_Value=(DUST/256.0)*5;//转化成电压值
  350.             DUST_Value=(DUST_Value*0.17-0.1)*1000;//固体悬浮颗粒浓度计
  351.        
  352.                 if(DUST_Value<0) DUST_Value=0;
  353.                 if(DUST_Value>760) DUST_Value=760; //限位
  354.                 DUST=(uint)DUST_Value;
  355.                 }
  356.                 TL0 = (65536-10000)/256;
  357.                 TH0 = (65536-10000)%256;
  358.                 TR0 = 1; //开启定时器0
  359.                 EA = 1;
  360.                 FlagStart=0;
  361.                 }
  362.                 Alarm(); //报警检测
  363.         }
  364.         disp(DUST);//显示粉尘浓度值
  365.         baojing();//显示报警值

  366.                 if(set_st==1)//报警值闪动
  367.                 {
  368.                 wr_com(0xca);
  369.                 wr_com(0x0d);
  370.                 delay1ms(150);
  371.                 }
  372.         }
  373. }
复制代码
QQ图片20180317090208.png
所有资料51hei提供下载:

c程序.zip

44.67 KB, 下载次数: 116, 下载积分: 黑币 -5

keil写的源程序

仿真.zip

111.06 KB, 下载次数: 120, 下载积分: 黑币 -5

proteus仿真工程文件

原理图PCB图.pdf

706.98 KB, 下载次数: 101, 下载积分: 黑币 -5

原理图及PCB

粉尘传感器参数.docx

185.15 KB, 下载次数: 86, 下载积分: 黑币 -5

粉尘传感器参数

基于单片机的PM2.5空气质量检测论文.doc

1.86 MB, 下载次数: 136, 下载积分: 黑币 -5

论文

评分

参与人数 6黑币 +30 收起 理由
kljie1000 + 9
Meadors + 5 绝世好帖!
蹬车拽小卡 + 5 很给力!
天才2333333 + 5 很给力!
iamtheflash + 4 很给力!
樱月樱诗 + 2 很给力!

查看全部评分

回复

使用道具 举报

yc123 发表于 2018-3-30 19:13 | 显示全部楼层
兄弟你好,我也在做这个传感器,我用了你的程序,但是灰尘传感器没输出,你知道是什么原因吗?
回复

使用道具 举报

BOOKS 发表于 2018-4-2 18:35 | 显示全部楼层
论文重复率多少?
回复

使用道具 举报

无时崩溃 发表于 2018-4-14 20:32 | 显示全部楼层
感谢楼主分享
回复

使用道具 举报

51菜鸟学习者 发表于 2018-4-17 14:42 | 显示全部楼层
固体悬浮颗粒浓度计算公式怎么来的
回复

使用道具 举报

大树下面吃草莓 发表于 2018-5-3 14:16 | 显示全部楼层
这个需要用到蓝牙模块吗?
回复

使用道具 举报

大树下面吃草莓 发表于 2018-5-6 19:29 | 显示全部楼层
很不错的分享。
回复

使用道具 举报

大树下面吃草莓 发表于 2018-5-6 19:40 | 显示全部楼层
很不错的分享。
回复

使用道具 举报

mqcxt 发表于 2018-5-8 15:59 | 显示全部楼层
感谢大兄弟的分享,正在找这方面的材料。
回复

使用道具 举报

邵帅 发表于 2018-5-8 20:33 | 显示全部楼层
感谢分享,很有用
回复

使用道具 举报

Hero98 发表于 2018-5-27 16:10 | 显示全部楼层
楼主,能加好友聊嘛
回复

使用道具 举报

Hero98 发表于 2018-5-27 16:12 | 显示全部楼层
楼主,我现在在做这个 作为课程的创新设计(买了HTU21D温湿度传感器和YW-51GJ PM2.5的传感器)能加qq好友 嘛,想请教您几个问题
回复

使用道具 举报

红莲丶天壤劫火 发表于 2018-6-3 20:17 | 显示全部楼层
感谢分享
回复

使用道具 举报

湖南一霸 发表于 2018-6-12 02:59 | 显示全部楼层
谢谢你,很好用
回复

使用道具 举报

liuzhen16 发表于 2018-7-18 10:38 | 显示全部楼层
好文章 顶起来
回复

使用道具 举报

流年未果 发表于 2018-11-10 15:34 | 显示全部楼层
yc123 发表于 2018-3-30 19:13
兄弟你好,我也在做这个传感器,我用了你的程序,但是灰尘传感器没输出,你知道是什么原因吗?

我下载了程序 无法运行  是什么原因呢   reg52.h这个显示错误 什么意思呢  我是小白  还不太懂
回复

使用道具 举报

midrich 发表于 2018-11-14 09:51 | 显示全部楼层
正在做这个项目,用的传感器也是这个夏普的GP2Y1014
回复

使用道具 举报

WFX777888 发表于 2019-1-8 17:01 | 显示全部楼层
谢谢分享资料
回复

使用道具 举报

3037646792 发表于 2019-1-9 08:56 | 显示全部楼层
很nice
回复

使用道具 举报

eosd 发表于 2019-1-10 08:53 | 显示全部楼层

谢谢分享资料
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|小黑屋|单片机论坛 |51黑电子论坛单片机.

Powered by 单片机教程网

快速回复 返回顶部 返回列表