基于小凌派开发板实现烟雾报警功能 原创 精华
烟雾检测传感器使用的是MQ-2烟雾传感器。MQ-2型烟雾传感器属于二氧化锡半导体气敏材料,属于表面离子式N型半导体。处于200~300摄氏度时,二氧化锡吸附空气中的氧,形成氧的负离子吸附,使半导体中的电子密度减少,从而使其电阻值增加。当与烟雾接触时,如果晶粒间界处的势垒收到烟雾的调至而变化,就会引起表面导电率的变化。利用这一点就可以获得这种烟雾存在的信息,烟雾的浓度越大,导电率越大,输出电阻越低,则输出的模拟信号就越大。
使用MQ-2烟雾传感器来检测周围环境烟雾浓度,再通过小凌派开发板采集信号。因为采集的信号是电压值所以通过adc转换成数字信号。这里有个需要注意的地方RK2206的ADC默认参考电压是内部2.4v所以初始化ADC时通过配置soc_con29 寄存器改成外部3.3v参考电压。
参考代码
{
uint32_t value;
struct
{
uint16_t grf_saradc_ana_reg_low: 4;
uint16_t grf_saradc_vol_sel: 1;
uint16_t grf_saradc_ana_reg_high: 11;
struct
{
uint16_t grf_saradc_ana_reg_low: 4;
uint16_t grf_saradc_vol_sel: 1;
uint16_t grf_saradc_ana_reg_high: 11;
} rw;
};
} GRF_SOC_CON29;
static uint32_t iss_adc_dev_init(iss_mq2_dev_s *adc)
{
if (PinctrlInit(adc->adc) != 0)
{
printf("adc pin %d init failed\n", adc->adc.gpio);
}
if (LzSaradcInit() != 0)
{
printf("saradc %d init failed\n", adc->port);
}
volatile GRF_SOC_CON29 *soc = (GRF_SOC_CON29*)&GRF->SOC_CON29;
soc->rw.grf_saradc_vol_sel = 1;
soc->grf_saradc_vol_sel = 0;
soc->rw.grf_saradc_vol_sel = 0;
adc->init = 1;
return 0;
}
读取ADC电压
{
unsigned int ret;
unsigned int data;
ret = LzSaradcReadValue(m_iss_mq2, &data);
if (ret != 0)
{
printf("ADC Read Fail\n");
}
return (float)data * 3.3 / 1024;
}
计算ppm值
阻值R与空气中被测气体的浓度C的计算关系式
log R = mlog C + n (m,n均为常数)
传感器的电阻计算
Rs = (Vc/VRL-1) X RL
Vc为回路电压,VRL是传感器4脚6脚输出电压,RL是负载
#define RL 1 //RL阻值
float e53_iss_get_mq2_ppm(void)
{
float voltage, rs, ppm;
voltage = iss_get_voltage();
rs = (5 - voltage) / voltage * RL; //计算rs
ppm = 613.9f * pow(rs / m_r0, -2.074f); //计算ppm
return ppm;
}
ppm值校准
{
float voltage = iss_get_voltage();
float rs = (5 - voltage) / voltage * RL;
m_r0 = rs / pow(CAL_PPM / 613.9f, 1 / -2.074f);
printf("R0 =%f\n", m_r0);
}
因为使用的是无源蜂鸣器,所以通过pwm驱动蜂鸣器报警。
pwm初始化
{
if (PwmIoInit(p->pwmio) != 0)
{
printf("Pwm pin %d init failed\n", p->pwmio.pwm.gpio);
}
if (LzPwmInit(p->port) != 0)
{
printf("Pwm %d init failed\n", p->port);
}
p->init = 1;
return 0;
}
pwm 启动
{
if (pwm->init == 0)
{
printf("PWM not init\n");
return 1;
}
else if (LzPwmStart(pwm->port, pwm->duty * pwm->cycle / 100, pwm->cycle) != 0)
{
printf("PWM Start Fail\n");
return 1;
}
pwm->onoff = 1;
return 0;
}
pwm停止
{
if (pwm->init == 0)
{
printf("PWM not init\n");
return 1;
}
else if (pwm->onoff == 0)
{
return 0;
}
else if (LzPwmStop(pwm->port) != 0)
{
printf("PWM Stop Fail\n");
return 1;
}
pwm->onoff = 0;
return 0;
}
蜂鸣器报警控制,需要报警时启动pwm,不需要报警时停止pwm
{
if (status == ON)
{
iss_pwm_start(&m_iss_beep);
}
if (status == OFF)
{
iss_pwm_stop(&m_iss_beep);
}
}
整个模块初始化
{
uint32_t ret = 1;
ret = iss_led_dev_init(&m_iss_led);
if (ret != 0)
{
printf(“led init err\n”);
}
ret = iss_pwm_dev_init(&m_iss_beep);
if (ret != 0)
{
printf(“pwm init err\n”);
}
ret = iss_adc_dev_init(&m_iss_mq2);
if (ret != 0)
{
printf(“adc init err\n”);
}
return ret;
}
创建一个任务处理函数
这里需要注意的是ppm校准需要提前测试,再把值写死到代码里。
还有需要注意的是mq2传感器需要预热,即提前通电大约半分钟到一分钟左右。用手放在传感器外壳感觉微微发热即可。如果不预热就开始测量其测量值会偏差很大,而且会随着加热而变化。
{
float ppm = 0;
uint32_t id = 0;
uint8_t index = 0;
e53_iss_init();
printf("%s\n", __FUNCTION__);
/*传感器校准*/
LOS_Msleep(2000); // 开机2s后进行校准
// e53_iss_mq2_ppm_calibration(); // 校准传感器校准后不需要重复调用
while (1)
{
ppm = e53_iss_get_mq2_ppm();
printf("ppm:%.1f \n", ppm);
/*判断是否达到报警阈值*/
if (ppm > e53_iss_get_mq2_alarm_value())
{
e53_iss_beep_status_set(ON);
printf("over %u ppm alarm\n", e53_iss_get_mq2_alarm_value());
}
else
{
e53_iss_led_status_set(OFF);
e53_iss_beep_status_set(OFF);
}
LOS_Msleep(1000);
}
}
最后创建一个任务调用上面处理函数即可。
烧写程序后通过串口打印结果
ppm:55.6
ppm:60.9
当检测到烟雾超过设定值时蜂鸣器报警响起。低于设置值时蜂鸣器停止报警。这样基于小凌派的烟雾报警功能就实现了。