打印
[应用方案]

N76E003 夏普GP2Y1010 PM2.5

[复制链接]
781|8
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
首先来看传感器内部结构与单片机的连接图。由下图可知,实际上使用的I/O就是3、5脚。其中3脚为PWM驱动LED闪烁频率的引脚,在下文中可以看到时序。而5脚Vo则是传感器检测到的灰尘,而输出的电压值。在下文的程序中,将使用N76E003单片机自带的带隙电压进行测量,以此保证ADC不被供电电压影响。

下图为GP2Y1010传感器的线序(注意,线的颜色不一定一致)



使用特权

评论回复
沙发
21mengnan|  楼主 | 2019-6-11 22:39 | 只看该作者
下图为3脚输入的电平,这里我们使用PWM5/P0.3(这里注意看左侧的电路,LED导通的条件)。

经下图公式计算可得

(16MHz/8)/100HZ=20000
20000-1——》0x4e1f(PWMPH=0x4e;PWMPL=0x1f)

0.032*20000=640
640——》0x280(PWMnH=0x2;PWMnH=0x80)

使用特权

评论回复
板凳
21mengnan|  楼主 | 2019-6-11 22:39 | 只看该作者
如果单片机管脚的输出能力不行,最好加上一个三极管,这时需要反向的PWM。这里使用N76E003的极性控制功能
PWM5_OUTPUT_INVERSE;//开启极性控制       

使用特权

评论回复
地板
21mengnan|  楼主 | 2019-6-11 22:40 | 只看该作者
上图是GP2Y10输出的波形,但是我的9.9包邮的逻辑分析仪可能太LOW了,没办法测量出来,所以只能万用表了,PWM信号出来,万用表测量到的就是电压(PS:这里测量到的电压,并不是真正的数据电压,而只是高低电平的比例电压,并不能体现检测到的灰尘)。

下图1是在GP2Y10里插了把螺丝刀

使用特权

评论回复
5
21mengnan|  楼主 | 2019-6-11 22:41 | 只看该作者

下图2是没有插螺丝刀


使用特权

评论回复
6
21mengnan|  楼主 | 2019-6-11 22:41 | 只看该作者
下图才是正确的传感器输出电压检测方式,我们可以看到,输出电压峰值跟我们输入的PWM相差0.28ms。实际测量过程中,需要选择一个合适的触发形式,不然测量的数值很不稳定,在程序中使用PWM0终点触发ADC中断(你也可以使用中点触发,可能会更好一些)
ADC中断触发的相关知识看这里N76E003 ADC中断

使用特权

评论回复
7
21mengnan|  楼主 | 2019-6-11 22:41 | 只看该作者
下面就是完整程序了,具体流程是先读取带隙电压,再对传感器的输出电压进行读取
有关带隙电压的相关程序与知识,请看这里N76E003之ADC带隙电压(Band-gap)
#include "N76E003.h"
#include "Common.h"
#include "Delay.h"
#include "SFR_Macro.h"
#include "Function_define.h"
//#include "DHT11.h"
//#include "BMP180.h"
//#include "HMC5883.h"
//#include "BH1750.h"

#define uint unsigned int
#define uchar unsigned  char

double  Bandgap_Voltage,ADC_Voltage;                        //please always use "double" mode for this
unsigned  char xdata ADCdataH[5], ADCdataL[5];
int ADCsumH=0, ADCsumL=0;
unsigned char ADCavgH,ADCavgL;

UINT8 BandgapHigh,BandgapLow,BandgapMark;
double Bandgap_Value,Bandgap_Voltage_Temp;
double Coe,bgvalue,RC_value;//比例系数,测量带隙电压

/*
程序功能:读取UID中带隙电压值;通过ADC,测量实际的带隙电压;得到比例系数COE;
本程序需要放在ADC正常测量前。
*/
void READ_BANDGAP()
{
                unsigned int i;
                set_IAPEN;
                IAPCN = READ_UID;
                IAPAL = 0x0d;
    IAPAH = 0x00;
    set_IAPGO;
                BandgapLow = IAPFD;
                BandgapMark = BandgapLow&0xF0;
                       
                if (BandgapMark==0x80)
                {
                                BandgapLow = BandgapLow&0x0F;
                                IAPAL = 0x0C;
                                IAPAH = 0x00;
                                set_IAPGO;
                                BandgapHigh = IAPFD;
                                Bandgap_Value = (BandgapHigh<<4)+BandgapLow;
                                Bandgap_Voltage_Temp = Bandgap_Value*3/4;
                                Bandgap_Voltage = Bandgap_Voltage_Temp - 33;                        //the actually banggap voltage value is similar this value.
                }
                if (BandgapMark==0x00)
                {
                                BandgapLow = BandgapLow&0x0F;
                                IAPAL = 0x0C;
                                IAPAH = 0x00;
                                set_IAPGO;
                                BandgapHigh = IAPFD;
                                Bandgap_Value = (BandgapHigh<<4)+BandgapLow;
                                Bandgap_Voltage= Bandgap_Value*3/4;
                }
                if (BandgapMark==0x90)
                {
                                IAPAL = 0x0E;
                                IAPAH = 0x00;
                                set_IAPGO;
                                BandgapHigh = IAPFD;
                                IAPAL = 0x0F;
                                IAPAH = 0x00;
                                set_IAPGO;
                                BandgapLow = IAPFD;
                                BandgapLow = BandgapLow&0x0F;
                                Bandgap_Value = (BandgapHigh<<4)+BandgapLow;
                                Bandgap_Voltage= Bandgap_Value*3/4;
                }
                clr_IAPEN;
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------               
                                Enable_ADC_BandGap;        //使能ADC带隙电压                                                                                       
                                CKDIV = 0x02;                                // IMPORTANT!! Modify system clock to 4MHz ,then add the ADC sampling clock base to add the sampling timing.
                                for(i=0;i<5;i++)                //采样5次,不要前面三次
                                {                                                                                                                                                                       
                                                clr_ADCF;
                                                set_ADCS;                                                                                                                               
                                                while(ADCF == 0);
                                                ADCdataH[i] = ADCRH;
                                                ADCdataL[i] = ADCRL;
                                }               
                                CKDIV = 0x00;
//--------均值滤波--------------------------------------------
                                for(i=2;i<5;i++)                                                                                                        // use the last 3 times data to make average
                                {
                                        ADCsumH = ADCsumH + ADCdataH[i];
                                        ADCsumL = ADCsumL + ADCdataL[i];
                                }                               
                                ADCavgH = ADCsumH/3;
                                ADCavgL = ADCsumL/3;
                                bgvalue = (ADCavgH<<4) + ADCavgL;
                                Coe=(Bandgap_Voltage/bgvalue);
                                ADCsumH = 0;
                                ADCsumL = 0;       
}



void ADC_ISR (void) interrupt 11
{
        if(ADCF)
        {
                clr_ADCF;//清除ADC转化完成标志,进行下一次转换
                set_ADCS;//当单次转换完成后,ADCS会硬件置0,需要重新使能
                RC_value= (ADCRH<<4) + ADCRL;//得到ADC转换值
                ADC_Voltage=RC_value*Coe;//测量数据*修正系数=实际值
        }
}

void main(void)
{
                   Set_All_GPIO_Quasi_Mode;//所有IO设置为双向模式       
                READ_BANDGAP();
                Enable_ADC_AIN5;//配置使能P04,作为AIN5。
                PWM0_END_TRIG_ADC;//PWM0末端触发ADC中断
                set_EADC;//使能ADC中断
                EA = 1;
                set_ADCS;//使能ADCS,启动ADC测量
//------------------------------------------------       
//                PWM5_P03_OUTPUT_ENABLE;//使能PWM5,通过P03引脚输出
                PWM0_P12_OUTPUT_ENABLE;
                clr_PWMTYP;//边沿对齐模式
                clr_PWMMOD0;//设置为独立输出模式
                clr_PWMMOD1;
                PWM_CLOCK_DIV_8;//8分频模式
                PWMPH = 0x4e;
                PWMPL = 0x2f;
            set_SFRPAGE;//PWM4 and PWM5 duty seting is in SFP page 1
            PWM0H = 0x02;               
            PWM0L = 0x81;
                   clr_SFRPAGE;     
//                PWM0_OUTPUT_INVERSE;//开启极性控制       
            set_LOAD;//载入周期和占空比
            set_PWMRUN;//开始输出PWM
   while(1)
    {
       //构建你的代码,LOAD会自动重载,PWM持续输出。
    }
}

使用特权

评论回复
8
21mengnan|  楼主 | 2019-6-11 22:42 | 只看该作者

最后得到的数据是3.48V左右(依然插螺丝刀),通过数据手册,可以得知,在没有污染时,电压典型值是0.9V,而污染严重时,输出电压的最小值是3.4V,结合下图2的输出电压曲线,相信大家都已经明白了(这个传感器检测到的污染,再高也就了这样了。。。。)

使用特权

评论回复
9
21mengnan|  楼主 | 2019-6-11 22:42 | 只看该作者
GP2Y10精度不高,而且使用过时的红外测灰尘方式,无法很好的测量到空气中PM2.5,可能PM10都有些难,用来测量污染物上升或者下降的趋势貌似可行。如果对测量精度有要求,还是推荐使用激光传感器,我没钱,买不起,所以…
GP2Y1023AU0F有兴趣的同学可以试试这个,据说精度不错,可以测PM2.5,使用输入捕获测量即可。
据说攀藤的激光传感器精度也很不错,只是价格比较贵。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

60

主题

906

帖子

1

粉丝