[应用方案] N76E003 夏普GP2Y1010 PM2.5

[复制链接]
1097|8
 楼主| 21mengnan 发表于 2019-6-11 22:38 | 显示全部楼层 |阅读模式
首先来看传感器内部结构与单片机的连接图。由下图可知,实际上使用的I/O就是3、5脚。其中3脚为PWM驱动LED闪烁频率的引脚,在下文中可以看到时序。而5脚Vo则是传感器检测到的灰尘,而输出的电压值。在下文的程序中,将使用N76E003单片机自带的带隙电压进行测量,以此保证ADC不被供电电压影响。
523635cffbcd5195cc.png
下图为GP2Y1010传感器的线序(注意,线的颜色不一定一致)
654255cffbce79b225.png


 楼主| 21mengnan 发表于 2019-6-11 22:39 | 显示全部楼层
下图为3脚输入的电平,这里我们使用PWM5/P0.3(这里注意看左侧的电路,LED导通的条件)。
728275cffbcfe40877.png
经下图公式计算可得
346035cffbd0d85821.png
(16MHz/8)/100HZ=20000
20000-1——》0x4e1f(PWMPH=0x4e;PWMPL=0x1f)

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

45255cffbd21144f4.png
 楼主| 21mengnan 发表于 2019-6-11 22:39 | 显示全部楼层
如果单片机管脚的输出能力不行,最好加上一个三极管,这时需要反向的PWM。这里使用N76E003的极性控制功能
PWM5_OUTPUT_INVERSE;//开启极性控制       
950485cffbd3c6c233.png
 楼主| 21mengnan 发表于 2019-6-11 22:40 | 显示全部楼层
上图是GP2Y10输出的波形,但是我的9.9包邮的逻辑分析仪可能太LOW了,没办法测量出来,所以只能万用表了,PWM信号出来,万用表测量到的就是电压(PS:这里测量到的电压,并不是真正的数据电压,而只是高低电平的比例电压,并不能体现检测到的灰尘)。

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

 楼主| 21mengnan 发表于 2019-6-11 22:41 | 显示全部楼层
607855cffbd608c76c.png
下图2是没有插螺丝刀

758795cffbd7463db0.png
 楼主| 21mengnan 发表于 2019-6-11 22:41 | 显示全部楼层
下图才是正确的传感器输出电压检测方式,我们可以看到,输出电压峰值跟我们输入的PWM相差0.28ms。实际测量过程中,需要选择一个合适的触发形式,不然测量的数值很不稳定,在程序中使用PWM0终点触发ADC中断(你也可以使用中点触发,可能会更好一些)
ADC中断触发的相关知识看这里N76E003 ADC中断
761835cffbd8b75cc5.png
 楼主| 21mengnan 发表于 2019-6-11 22:41 | 显示全部楼层
下面就是完整程序了,具体流程是先读取带隙电压,再对传感器的输出电压进行读取
有关带隙电压的相关程序与知识,请看这里N76E003之ADC带隙电压(Band-gap)
  1. #include "N76E003.h"
  2. #include "Common.h"
  3. #include "Delay.h"
  4. #include "SFR_Macro.h"
  5. #include "Function_define.h"
  6. //#include "DHT11.h"
  7. //#include "BMP180.h"
  8. //#include "HMC5883.h"
  9. //#include "BH1750.h"

  10. #define uint unsigned int
  11. #define uchar unsigned  char

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

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

  19. /*
  20. 程序功能:读取UID中带隙电压值;通过ADC,测量实际的带隙电压;得到比例系数COE;
  21. 本程序需要放在ADC正常测量前。
  22. */
  23. void READ_BANDGAP()
  24. {
  25.                 unsigned int i;
  26.                 set_IAPEN;
  27.                 IAPCN = READ_UID;
  28.                 IAPAL = 0x0d;
  29.     IAPAH = 0x00;
  30.     set_IAPGO;
  31.                 BandgapLow = IAPFD;
  32.                 BandgapMark = BandgapLow&0xF0;
  33.                        
  34.                 if (BandgapMark==0x80)
  35.                 {
  36.                                 BandgapLow = BandgapLow&0x0F;
  37.                                 IAPAL = 0x0C;
  38.                                 IAPAH = 0x00;
  39.                                 set_IAPGO;
  40.                                 BandgapHigh = IAPFD;
  41.                                 Bandgap_Value = (BandgapHigh<<4)+BandgapLow;
  42.                                 Bandgap_Voltage_Temp = Bandgap_Value*3/4;
  43.                                 Bandgap_Voltage = Bandgap_Voltage_Temp - 33;                        //the actually banggap voltage value is similar this value.
  44.                 }
  45.                 if (BandgapMark==0x00)
  46.                 {
  47.                                 BandgapLow = BandgapLow&0x0F;
  48.                                 IAPAL = 0x0C;
  49.                                 IAPAH = 0x00;
  50.                                 set_IAPGO;
  51.                                 BandgapHigh = IAPFD;
  52.                                 Bandgap_Value = (BandgapHigh<<4)+BandgapLow;
  53.                                 Bandgap_Voltage= Bandgap_Value*3/4;
  54.                 }
  55.                 if (BandgapMark==0x90)
  56.                 {
  57.                                 IAPAL = 0x0E;
  58.                                 IAPAH = 0x00;
  59.                                 set_IAPGO;
  60.                                 BandgapHigh = IAPFD;
  61.                                 IAPAL = 0x0F;
  62.                                 IAPAH = 0x00;
  63.                                 set_IAPGO;
  64.                                 BandgapLow = IAPFD;
  65.                                 BandgapLow = BandgapLow&0x0F;
  66.                                 Bandgap_Value = (BandgapHigh<<4)+BandgapLow;
  67.                                 Bandgap_Voltage= Bandgap_Value*3/4;
  68.                 }
  69.                 clr_IAPEN;
  70. //----------------------------------------------------------------------------
  71. //----------------------------------------------------------------------------
  72. //----------------------------------------------------------------------------               
  73.                                 Enable_ADC_BandGap;        //使能ADC带隙电压                                                                                       
  74.                                 CKDIV = 0x02;                                // IMPORTANT!! Modify system clock to 4MHz ,then add the ADC sampling clock base to add the sampling timing.
  75.                                 for(i=0;i<5;i++)                //采样5次,不要前面三次
  76.                                 {                                                                                                                                                                       
  77.                                                 clr_ADCF;
  78.                                                 set_ADCS;                                                                                                                               
  79.                                                 while(ADCF == 0);
  80.                                                 ADCdataH[i] = ADCRH;
  81.                                                 ADCdataL[i] = ADCRL;
  82.                                 }               
  83.                                 CKDIV = 0x00;
  84. //--------均值滤波--------------------------------------------
  85.                                 for(i=2;i<5;i++)                                                                                                        // use the last 3 times data to make average
  86.                                 {
  87.                                         ADCsumH = ADCsumH + ADCdataH[i];
  88.                                         ADCsumL = ADCsumL + ADCdataL[i];
  89.                                 }                               
  90.                                 ADCavgH = ADCsumH/3;
  91.                                 ADCavgL = ADCsumL/3;
  92.                                 bgvalue = (ADCavgH<<4) + ADCavgL;
  93.                                 Coe=(Bandgap_Voltage/bgvalue);
  94.                                 ADCsumH = 0;
  95.                                 ADCsumL = 0;       
  96. }



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

  107. void main(void)
  108. {
  109.                    Set_All_GPIO_Quasi_Mode;//所有IO设置为双向模式       
  110.                 READ_BANDGAP();
  111.                 Enable_ADC_AIN5;//配置使能P04,作为AIN5。
  112.                 PWM0_END_TRIG_ADC;//PWM0末端触发ADC中断
  113.                 set_EADC;//使能ADC中断
  114.                 EA = 1;
  115.                 set_ADCS;//使能ADCS,启动ADC测量
  116. //------------------------------------------------       
  117. //                PWM5_P03_OUTPUT_ENABLE;//使能PWM5,通过P03引脚输出
  118.                 PWM0_P12_OUTPUT_ENABLE;
  119.                 clr_PWMTYP;//边沿对齐模式
  120.                 clr_PWMMOD0;//设置为独立输出模式
  121.                 clr_PWMMOD1;
  122.                 PWM_CLOCK_DIV_8;//8分频模式
  123.                 PWMPH = 0x4e;
  124.                 PWMPL = 0x2f;
  125.             set_SFRPAGE;//PWM4 and PWM5 duty seting is in SFP page 1
  126.             PWM0H = 0x02;               
  127.             PWM0L = 0x81;
  128.                    clr_SFRPAGE;     
  129. //                PWM0_OUTPUT_INVERSE;//开启极性控制       
  130.             set_LOAD;//载入周期和占空比
  131.             set_PWMRUN;//开始输出PWM
  132.    while(1)
  133.     {
  134.        //构建你的代码,LOAD会自动重载,PWM持续输出。
  135.     }
  136. }
 楼主| 21mengnan 发表于 2019-6-11 22:42 | 显示全部楼层
918795cffbdb40bd30.png
最后得到的数据是3.48V左右(依然插螺丝刀),通过数据手册,可以得知,在没有污染时,电压典型值是0.9V,而污染严重时,输出电压的最小值是3.4V,结合下图2的输出电压曲线,相信大家都已经明白了(这个传感器检测到的污染,再高也就了这样了。。。。)
351125cffbdc3c2e4c.png
841925cffbdca7f5a9.png
 楼主| 21mengnan 发表于 2019-6-11 22:42 | 显示全部楼层
GP2Y10精度不高,而且使用过时的红外测灰尘方式,无法很好的测量到空气中PM2.5,可能PM10都有些难,用来测量污染物上升或者下降的趋势貌似可行。如果对测量精度有要求,还是推荐使用激光传感器,我没钱,买不起,所以…
GP2Y1023AU0F有兴趣的同学可以试试这个,据说精度不错,可以测PM2.5,使用输入捕获测量即可。
据说攀藤的激光传感器精度也很不错,只是价格比较贵。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

87

主题

1140

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部