找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 6562|回复: 7
收起左侧

PM2.5测量例子

[复制链接]
ID:114481 发表于 2016-4-16 08:52 | 显示全部楼层 |阅读模式
#include<reg52.h>       //包含单片机寄存器的头文件
#include <intrins.h>    //包含_nop_()函数定义的头文件
#define uchar unsigned char
#define uint unsigned int
sfr  ADC_CONTR=0X0BC;  //AD寄存器设置
sfr  ADC_RES=0x0BD;
sfr  ADC_RESL=0x0BE;
sfr  P1ASF=0x09D;
uchar a,q,t;
uchar FlagStart;
uchar VALUE;
uint num,DUST_Value,DUST;
long int s1,d0,b,c,d,biao,biao1,biao2;
uchar code qw[]={1,1,1};
uchar qs[4]={0,0,9,0};
uchar key_buffer[8]={0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};//2013-01-03
sbit rs=P2^5;          //将rS位定义为P2.5引脚
sbit e=P2^7;           //将e位定义为P2.7引脚
sbit rw=P2^6;          //将rw位定义为P2.6引脚
sbit k1=P1^4;
sbit k2=P1^5;
sbit k3=P1^6;
sbit k4=P1^7;
sbit D1=P2^1;          //正常指示灯(绿灯)
sbit D2=P2^0;          //警情指示灯(红灯)
sbit LED=P1^1;         //  传感器led
sbit beep=P1^3;//蜂鸣器
sbit fuli=P2^2;//负离子发生器
sbit fan=P2^3;//风扇
uchar code tad[]="value:0000ppm";
uchar code tad1[]="Alarm:0760ppm";
uchar ADC_Get[10]={0};    //定义AD采样数组
uchar str[5]={0};
/*****************************************************
函数功能:延时若干毫秒
入口参数:x
***************************************************/
void delay(uchar x)
{
uint a,b;
for(a=x;a>0;a--)
  for(b=100;b>0;b--);
}
/*****************************************************
函数功能:ad数据转换
***************************************************/
uchar ADC( uchar ch)    //ch为几通道 ,返回结果
{  uchar i;
  uint temp1;
  P1ASF|=1<<ch;
  ADC_CONTR=0x88+ch;
  for(i=100;i>0;i--);
  while(( ADC_CONTR&0x10)==0);//判断AD是否转换完
  ADC_CONTR&=~0x10;  
  temp1=(ADC_RES<<2)+ADC_RESL;
  return temp1;
}

/*****************************************************
        液晶显示器LED1602
******************************************************/
void write_date(uchar date)
{
rs=1;
P0=date;
delay(5);
e=1;
delay(5);
e=0;
}
void write_com(uchar com)
{
rs=0;
P0=com;
delay(5);
e=1;
delay(5);
e=0;
}
void init()
{
uchar num;
e=0;
write_com(0x38);
write_com(0x0c);
write_com(0x06);
write_com(0x01);
write_com(0x80);
for(num=0;num<14;num++)
  {
   write_date(tad[num]);
    delay(2);
   }
  write_com(0x80+0x40);
for(num=0;num<14;num++)
   {
   write_date(tad1[num]);
    delay(2);
   }
}
void write_sfm(uint date)//向1602送显示
{
uint qian,bai,shi,ge;
bai=date%10000%1000/100;
shi=date%10000%1000%100/10;
ge=date%10000%1000%100%10;
write_com(0x80+6);
write_date(0x30+qian);
write_date(0x30+bai);
write_date(0x30+shi);
write_date(0x30+ge);
}
/*****************************************************
中值滤波/算法:先进行排序,然后将数组的中间值作为当前值返回。*/
uchar Error_Correct(uchar *str,uchar num)
{
   unsigned char i=0;
   unsigned char j=0;
   uchar Temp=0;
   
   //排序
   for(i=0;i<num-1;i++)
     {
   for(j=i+1;j<num;j++)
    {
      if(str[i]<str[j])
     {
     Temp=str[i];
     str[i]=str[j];
     str[j]=Temp;
  
  }
   
    }
}
    //去除误差,取中间值
    return str[num/2];
}
/*****************************************************
函数功能:报警子程序
*****************************************************/
void zx()//控制
{
long int sa;
sa=(qs[3]*1000+(qs[2]*100)+(qs[1]*10)+qs[0]); //报警设定值
if(DUST>sa) //烟雾检测值大于设定值
{
  D1=1;  //正常指示绿灯灭
  D2=0; //报警红灯亮
     fuli=0;
  fan=0;
  biao2=1;//蜂鸣器报警
}
else
{
  D1=0; //正常指示绿灯亮
  D2=1;  //报警红灯灭
  fuli=1;
  fan=1;
  biao2=0;
  beep=1;  //蜂鸣器不响
}
}
/*****************************************************
函数功能:按键识别
******************************************************/   
void key_scan()//按键识别
{
uchar i;
static uchar key_value,key_state=0;
P1=0xf0;//设置P1口高4位为输入口

if((P1&0xf0)!=0xf0)//有键按下
{
  delay(2); //延时消抖   
  key_state =P1&0xf0;
  if(key_state!=0xf0) //再判有键按下
  {
   switch(key_state)
   {
    case 0xe0:  //S1按下
      key_value=1;
      break;
    case 0xd0://S2按下
     key_value=2;
      break;
    case 0xb0: //S3按下
     key_value=3;
      break;
    case 0x70: //S4按下
     key_value=4;
      break;
   }
   for(i=0;i<7;i++) //按键队列FIFO处理
    {
     key_buffer[i]=key_buffer[i+1];
    }
    key_buffer[7]=key_value; //最新按键值存入缓冲队列      
  }
  while((P1&0xf0)!=0xf0);  //等待按键释放
}
}  
/*****************************************************
函数功能:按键处理
******************************************************/   
void key_do()  // 按键处理
{
uchar d,i;
while((key_buffer[0]!=0xff)||(key_buffer[1]!=0xff)||(key_buffer[2]!=0xff)||(key_buffer[3]!=0xff)||(key_buffer[4]!=0xff)||
       (key_buffer[5]!=0xff)||(key_buffer[6]!=0xff)||(key_buffer[7]!=0xff))//有键按下
  {
   switch(key_buffer[0])
   {
    case 1:  //S1按下
      biao++;
      TR0=0;
        write_com(0x80+0x40+9);//定位光标闪烁的位置
     write_com(0x0f); //打开光标闪烁
      if(biao==5)
      {
      TR0=1;
      biao=0;
     write_com(0x0f); //打开光标闪烁
       }
      biao1=0;
      break;
    case 2://S2按下
       if(biao==1)
      {
       if(biao1==0)
       {
        write_com(0x80+0x40+9);//定位光标闪烁的位置
        write_com(0x0f); //打开光标闪烁
       }            
       d=qs[0];
       d++;
       if(d==10) d=0;            
       write_com(0x80+0x40+9);
       write_date(0x30+d);//送显示
       write_com(0x80+0x40+9);//重新定位光标闪烁的位置         
       qs[0]=d;
       //biao1=1;
      }
      if(biao==2)
      {
       if(biao1==0)
        write_com(0x80+0x40+8);//定位光标闪烁的位置  
       d=qs[1];
       d++;
       if(d==10) d=0;            
       write_com(0x80+0x40+8);
       write_date(0x30+d);//送显示
       write_com(0x80+0x40+8);//重新定位光标闪烁的位置         
       qs[1]=d;
       //biao1=1;
      }
      if(biao==3)
      {
       if(biao1==0)
        write_com(0x80+0x40+7);//定位光标闪烁的位置  
       d=qs[2];
       d++;
       if(d==10) d=0;            
       write_com(0x80+0x40+7);
       write_date(0x30+d);//送显示
       write_com(0x80+0x40+7);//重新定位光标闪烁的位置         
       qs[2]=d;        
      }
      if(biao==4)
      {
       if(biao1==0)
        write_com(0x80+0x40+6);//定位光标闪烁的位置  
       d=qs[3];
       d++;
       if(d==10) d=0;            
       write_com(0x80+0x40+6);
       write_date(0x30+d);//送显示
       write_com(0x80+0x40+6);//重新定位光标闪烁的位置         
       qs[3]=d;        
      }
      biao1=1;
      break;
    case 3: //S3按下
      if(biao==1)
      {
       if(biao1==0)
       {
        write_com(0x80+0x40+9);//定位光标闪烁的位置
        write_com(0x0f); //打开光标闪烁
       }            
       d=qs[0];
       d--;
       if(d==-1) d=9;            
       write_com(0x80+0x40+9);
       write_date(0x30+d);//送显示
       write_com(0x80+0x40+9);//重新定位光标闪烁的位置         
       qs[0]=d;
      // biao1=1;
      }
        if(biao==2)
      {
       if(biao1==0)
        write_com(0x80+0x40+8);//定位光标闪烁的位置  
       d=qs[1];
       d--;
       if(d==-1) d=9;            
       write_com(0x80+0x40+8);
       write_date(0x30+d);//送显示
       write_com(0x80+0x40+8);//重新定位光标闪烁的位置         
       qs[1]=d;
      }
      if(biao==3)
      {
       if(biao1==0)
        write_com(0x80+0x40+7);//定位光标闪烁的位置  
       d=qs[2];
       d--;
       if(d==-1) d=9;            
       write_com(0x80+0x40+7);
       write_date(0x30+d);//送显示
       write_com(0x80+0x40+7);//重新定位光标闪烁的位置         
       qs[2]=d;        
      }
      if(biao==4)
      {
       if(biao1==0)
        write_com(0x80+0x40+6);//定位光标闪烁的位置  
       d=qs[3];
       d--;        
       if(d==-1) d=9;            
       write_com(0x80+0x40+6);
       write_date(0x30+d);//送显示
       write_com(0x80+0x40+6);//重新定位光标闪烁的位置         
       qs[3]=d;        
      }      
      biao1=1;
       break;
    case 4: //S4按下
      TR0=1;
      biao=0;
      write_com(0x0c);//关闭光标闪烁
       break;
    default: break;
   }
   for(i=0;i<7;i++) //按键队列FIFO处理
    {
     key_buffer[i]=key_buffer[i+1];
    }
    key_buffer[7]=0xff; //缓冲队列单元恢复无键按下标志      
  }
}  

void init1()
{
biao=0;
biao1=0;
biao2=0;
beep=1;
rw=0;
   FlagStart=0;
   DUST_Value=0;
   LED=0;
EA=1;
ET0=1;
TMOD = 0x11;      
TL0 = (65536-10000)/256; //定时10ms   
TH0 = (65536-10000)%256;
TH1=(65536-600000)/256;//重赋初值
TL1=(65535-60000)%256;
ET1=1;
TR1=1;   
TR0=1;
D1=0;//绿色灯
D2=1;//红色灯
init();
}
/**************************************
/*****定时器0中断服务程序*****/
void Timer0_ISR (void) interrupt 1 using 0
{
  uint j;
TL0 = (65536-10000)/256;     
TH0 = (65536-10000)%256;   
     LED=1;
      //开启传感器的LED
     for (j=0;j<222;j++);  //0.28ms  //延时0.28ms
ADC_Get[num]=ADC(0x00);   //开启ADC采集

num++;
if(num>9)
{
   FlagStart=1;
   num=0;
   TR0 = 0;   //先关闭定时器0
   EA = 0;
}
// for (j=0;j<25;j++);          //采集10次,关闭定时器0,进行数据处理
//for (j=0;j<25;j++);
          //关闭传感器LED
LED=0;
}
/*****************************************************
函数功能:主函数
***************************************************/
main()
{
init1();
while(1)
{  
   
  
   
if(FlagStart==1)       //10次采集完成
  {
   DUST=Error_Correct(ADC_Get,10);  //求取10次AD采样的值
   DUST_Value=(DUST/1024.0)*5000;  //转化成电压值MV
   DUST_Value=DUST_Value*0.172-100.0; //DUST_Value=((DUST)*38)/4-202;// //固体悬浮颗粒浓度计算 Y=0.172*X-0.0999      X--采样电压V
   if(DUST_Value<0)       DUST_Value=0;
   if(DUST_Value>760)  DUST_Value=760; //限位
   DUST=(uint)DUST_Value;      //
   write_sfm(DUST);//显示粉尘浓度值
   TL0 = (65536-10000)/256;     
   TH0 = (65536-10000)%256;
   TR0 = 1;   //开启定时器0
   EA = 1;
   FlagStart=0;
   zx();//浓度判断启动警报
   key_scan();
   key_do();
   delay(100);
   
   }
      }
   }
void as() interrupt 3   //定时器T1中断函数 ,定时启动数据转换和AD转换,并根据情况进行蜂鸣器报警
{
TH1=(65536-50000)/256;//重赋初值
TL1=(65535-50000)%256;
t++;  //时间计数加1
if(t==4) //50ms*4=0.2s,0.2s时间到
{  t=0;
  if(biao2==1)
   beep=!beep;  //蜂鸣器报警
}
}
  
  

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

ID:1 发表于 2016-4-16 10:57 来自手机 | 显示全部楼层
这个是什么型号的传感器
回复

使用道具 举报

ID:114394 发表于 2016-5-4 09:00 | 显示全部楼层
l楼主,可不可以分享一下原理图?谢谢
回复

使用道具 举报

ID:189066 发表于 2017-4-14 18:52 | 显示全部楼层
有用不?
回复

使用道具 举报

ID:170423 发表于 2017-4-17 09:22 | 显示全部楼层
很厉害  就是不知道什么型号的
回复

使用道具 举报

ID:175237 发表于 2017-6-29 11:19 | 显示全部楼层
makr学习
回复

使用道具 举报

ID:286922 发表于 2018-3-2 13:56 | 显示全部楼层
楼主,你好
DUST_Value=DUST_Value*0.172-100.0; //DUST_Value=((DUST)*38)/4-202;// //固体悬浮颗粒浓度计算 Y=0.172*X-0.0999      X--采样电压V

这段公式是哪里来的 ,不明白可以解释以下吗
回复

使用道具 举报

ID:248394 发表于 2018-4-18 12:00 | 显示全部楼层
mark,先收藏起立

回复

使用道具 举报

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

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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