一、传感器的概述
GP2Y1010AUOF是日本夏普公司开发的一款光学灰尘浓度检测传感器。此传感器内部成对角分布的红外发光二极管和光电晶体管,利用光敏原理来工作。用于检测特别细微的颗粒,如香烟颗粒、细微灰尘。依靠输出脉冲的高度来判断颗粒浓度。
二、传感器的一些参数
三、传感器的工作原理
图(1)
图(2)
夏普GP2Y1010AU0F灰尘传感器价格较便宜,只能检测出室内空气中的灰尘和烟尘含量.并不能测出所谓的PM2.5浓度,然而现在市面上有好多红外发光二极管的传感器都称自己是PM2.5传感器,能测PM2.5的值,其实并不是,真正能测PM2.5浓度的是那种上百的激光传感器,这种红外的连PM10都测不了,只能用来玩玩,或者大概描述空气质量的等级而已,经我多次实验,发现这传感器显示的灰尘浓度与网上公布的AQI空气质量指数比较接近,跟真实的PM2.5浓度有很大的区别,这测出的灰尘浓度其实就是所有不同直径的颗粒物总和,里面包含了PM1.0,PM2.5,PM10
其原理如上图(2)所示,传感器中心有个洞可以让空气自由流过,定向发射LED光,通过检测经过空气中灰尘折射过后的光线来判断灰尘的含量。
四、传感器与STM32的连接
(注:把图中的430单片机直接换成STM32就行,接线顺序跟电阻、电容的大小都不变)
在这里简单地说一下,为什么要这样接?
1. 电阻R1和电容C1:因为V-LED和LED-GND是给红外发光二极管供电的,所以不能直接接上5V,需要串一个150欧的电阻来限流,另外为了稳定供电,还需要在给发光二极管供电的正极和负极上并一个220uf的电容。
2. 三极管:可以增加LED的驱动能力(建议加上,加上后比较稳定)
3. 电阻R2:起到限流作用,因为该传感器的最大工作电流为20mA
4. 电阻R3和R4:起分压作用(因为该传感器是5V供电,而32单片机的AD采样最大电压为3.3V)
5. 上图中的P1.2为脉冲输入脚,为传感器提供输入信号(该PWM的占空比规定为0.032)
6. 上图中的P6.5为单片机的ADC模拟输入脚,用来输出信号的
(图1) (图2)
图1为脉冲输入波形,周期为10ms,高电平为0.32ms
图2为AD采样时序,由图可知,在输入上升沿到输出的峰值,时间为280us左右,就在此时进行采样,因为整个高电平持续的时间为320us,所以在打开红外发光二极管280us后采样,然后延时40us后关闭红外发光二极管,最后再延时9680us(输入波形的周期为10ms),这就实现了一次完整的工作
数据手册上面有关电压值与灰尘浓度的关系比例图
由图可知,该曲线在前半部分是有一定的斜率的,大约到0.6mg/m3左右,该曲线不再增长,此时输出的电压最大为3.6V左右,但是在曲线的前半部分,是可以得出电压值与灰尘浓度的关系:Dust density = 0.17 * Output Voltage
根据技术手册可知,当空气洁净的时候,Vo的范围是0~1.5V,典型值是0.9V
当空气灰尘浓度很高的时候,Vo的数值大于3.6V。但是该传感器输出的最大电压为3.6V,所以当灰尘浓度再增加时,我们这款传感器已经测不出了
0.9V表示空气洁净,3.6V表示空气灰尘很多。由于空气中不可能一点灰尘都没有,所以取个正常值0.9V,换成灰尘浓度就是0.053mg/m3
当达到最大电压值3.6V时,此时的灰尘浓度为0.512mg/m3
所以我们这个传感器的范围就是0~512ug/m3(这个512只是一个估算大约的值,实际情况中还是有可能超出这值的)
五、主要的程序代码
Main.c
#include "stm32f10x.h"
#include "bsp_SysTick.h"
#include "bsp_usart1.h"
#include "bsp_GP2Y.h"
#include "bsp_pwm_output.h"
#include "bsp_TiMbase.h"
#define FILTER_N 7
int A[32];
volatile u32 time = 0; // ms 计时变量
void Delay(__IO uint32_t nCount)
{
for(; nCount != 0; nCount--);
}
voidTIM3_Configuration(void);
void TIM3_NVIC_Configuration(void);
int main(void)
{
float calcVoltage ;
int filter_sum, i ,j ,dust;
int filter_max, filter_min;
int filter_buf[FILTER_N];
SysTick_Init();
USART1_Config();
TIM3_Configuration();
TIM3_NVIC_Configuration();
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3 , ENABLE);
Adc_Init();
TIM3_PWM_Init();
Delay_ms(200); //等待传感器稳定工作//
while(1)
{
if(time==200) //10ms发生一次中断,等到中断200次后,即2s//
{
time=0;
for(i = 0; i < FILTER_N; i++)
{
GP2Y_Low; //打开红外二极管//
Delay_us(280); //延时280us//
filter_buf[i]=Get_Adc(ADC_Channel_10); //采样,读取AD值//
Delay_us(19); //延时19us,因为这里我设了AD采样的周 期为239.5,所以AD转换一次需耗时21us,19加21再加280刚好是320us,这跟上面说的高电平持续的时间为0.32ms//
GP2Y_High; //关闭红外二极管//
Delay_us(9680); //延时9680us//
}
filter_max = filter_buf[0];
filter_min = filter_buf[0];
filter_sum = filter_buf[0];
for(i = FILTER_N - 1; i > 0; i--)
{
if(filter_buf[i] > filter_max)
filter_max=filter_buf[i];
else if(filter_buf[i] < filter_min)
filter_min=filter_buf[i];
filter_sum = filter_sum + filter_buf[i];
filter_buf[i] = filter_buf[i - 1];
}
i = FILTER_N - 2;
filter_sum = filter_sum - filter_max - filter_min + i/2; //加上i/2是为了四舍五入//
filter_sum = filter_sum / i;
calcVoltage=filter_sum*(3.3/ 4096)*2; /因为上面采集到的是AD值,这里要把它转换为电压值//
(注:为什么我在公式的最后要乘以2呢?这个2是一定不能少的,因为我们将它与32单片机连接的时候,加了两个10K的电阻分压,读取到的电压值已减小了一半,但这不是实际采取到的电压,所以要在最后乘以2返回原来的电压值)
dust=(0.17*calcVoltage-0.1)*1000; //乘以1000单位换成ug/m3//
if (dust<0)
dust=0; //限位//
if (dust>500)
dust=500;
printf("\r\n电压值:%fV\n",calcVoltage);
printf("\r\n灰尘浓度:%dug/m3\n",dust);
}
}
}
以上就是主要的一些程序,由于该传感器不太稳定,输出波形抖动较大,所以在程序里我加上了数字滤波算法,我采用那种去极值取平均的中位值滤波法,在传感器工作一次时,取输出波形的连续几个波峰的峰值,存到数组里,然后进行去掉最大值,最小值的操作,剩下的取平均
六、实际操作
实物连接图如下:
把程序烧进单片机,观察其输出的值
对比右图可知,一般室内的灰尘浓度所对应的电压值都是0.9V左右
再对比一下网上公布的空气指数
对比可知,该传感器测出的值与网上公布的AQI指数比较接近
我们再来看看这输入波形和输出波形
黄色的是输入波形,蓝色的是输出波形
(注:这图像上显示的电压值是分压后的)
当我往传感器的中心孔里放根杜邦线时,可以看到其输出波形立马飙升,说明这传感器还是挺灵敏的
当往孔里插根杜邦线或者一支笔时,测出的值立马到达最大值3.6V左右,这是对颗粒物的灵敏度,对于烟雾类型的也很敏感,我利用电烙铁焊锡时产生的烟雾,经传感器测量也能到达最大值,显示的灰尘浓度达530ug/m3.
由于这传感器的内部存有空隙,所以当你外加烟雾给它时,会有少量的烟雾残留在内部的空隙里,才会出现为什么我把烟雾撤去之后,显示的浓度依然很大,这时你需往孔里吹口气,将里面残留的烟雾吹走,这时才恢复你室内正常的浓度,否则的话,你得等待一段时间,待里面的烟雾慢慢散去.