[文章]基于小凌派开发板实现烟雾报警功能

阅读量0
1
0
烟雾检测传感器使用的是MQ-2烟雾传感器。MQ-2型烟雾传感器属于二氧化锡半导体气敏材料,属于表面离子式N型半导体。处于200~300摄氏度时,二氧化锡吸附空气中的氧,形成氧的负离子吸附,使半导体中的电子密度减少,从而使其电阻值增加。当与烟雾接触时,如果晶粒间界处的势垒收到烟雾的调至而变化,就会引起表面导电率的变化。利用这一点就可以获得这种烟雾存在的信息,烟雾的浓度越大,导电率越大,输出电阻越低,则输出的模拟信号就越大。

                        
图片1.png


使用MQ-2烟雾传感器来检测周围环境烟雾浓度,再通过小凌派开发板采集信号。因为采集的信号是电压值所以通过adc转换成数字信号。这里有个需要注意的地方RK2206的ADC默认参考电压是内部2.4v所以初始化ADC时通过配置soc_con29 寄存器改成外部3.3v参考电压。

参考代码

  1. typedef union
  2. {
  3.     uint32_t value;
  4.     struct
  5.     {
  6.         uint16_t grf_saradc_ana_reg_low: 4;
  7.         uint16_t grf_saradc_vol_sel: 1;
  8.         uint16_t grf_saradc_ana_reg_high: 11;
  9.         struct
  10.         {
  11.             uint16_t grf_saradc_ana_reg_low: 4;
  12.             uint16_t grf_saradc_vol_sel: 1;
  13.             uint16_t grf_saradc_ana_reg_high: 11;
  14.         } rw;
  15.     };
  16. } GRF_SOC_CON29;
  17. static uint32_t iss_adc_dev_init(iss_mq2_dev_s *adc)
  18. {
  19.     if (PinctrlInit(adc->adc) != 0)
  20.     {
  21.         printf("adc pin %d init failedn", adc->adc.gpio);
  22.     }
  23.     if (LzSaradcInit() != 0)
  24.     {
  25.         printf("saradc  %d init failedn", adc->port);
  26.     }
  27.     volatile GRF_SOC_CON29 *soc = (GRF_SOC_CON29*)&GRF->SOC_CON29;
  28.     soc->rw.grf_saradc_vol_sel = 1;
  29.     soc->grf_saradc_vol_sel    = 0;
  30.     soc->rw.grf_saradc_vol_sel = 0;
  31.    
  32.     adc->init = 1;
  33.     return 0;
  34. }
复制代码

读取ADC电压
  1. static float iss_get_voltage(void)
  2. {
  3.     unsigned int ret;
  4.     unsigned int data;
  5.    
  6.     ret = LzSaradcReadValue(m_iss_mq2, &data);
  7.     if (ret != 0)
  8.     {
  9.         printf("ADC Read Failn");
  10.     }
  11.     return (float)data * 3.3  / 1024;
  12. }<span style="font-size: 10pt; background-color: transparent;"> </span>
复制代码
计算ppm值
阻值R与空气中被测气体的浓度C的计算关系式
log R = mlog C + n (m,n均为常数)
传感器的电阻计算
Rs = (Vc/VRL-1) X RL
Vc为回路电压,VRL是传感器4脚6脚输出电压,RL是负载

  1. #define  CAL_PPM            20             //校准环境中PPM值
  2. #define  RL                  1              //RL阻值
  3. float e53_iss_get_mq2_ppm(void)
  4. {
  5.     float voltage, rs, ppm;
  6.    
  7.     voltage = iss_get_voltage();
  8.     rs = (5 - voltage) / voltage * RL; //计算rs
  9.     ppm = 613.9f * pow(rs / m_r0, -2.074f); //计算ppm
  10.     return ppm;
  11. }
复制代码

ppm值校准
  1. void e53_iss_mq2_ppm_calibration(void)
  2. {
  3.     float voltage = iss_get_voltage();
  4.     float rs = (5 - voltage) / voltage * RL;
  5.    
  6.     m_r0 = rs / pow(CAL_PPM / 613.9f, 1 / -2.074f);
  7.     printf("R0 =%fn", m_r0);
  8. }
复制代码

因为使用的是无源蜂鸣器,所以通过pwm驱动蜂鸣器报警。
pwm初始化

  1. static uint32_t iss_pwm_dev_init(iss_pwm_dev_s *p)
  2. {
  3.     if (PwmIoInit(p->pwmio) != 0)
  4.     {
  5.         printf("Pwm pin  %d init failedn", p->pwmio.pwm.gpio);
  6.     }
  7.     if (LzPwmInit(p->port) != 0)
  8.     {
  9.         printf("Pwm  %d init failedn", p->port);
  10.     }
  11.    
  12.     p->init = 1;
  13.     return 0;
  14. }
复制代码

pwm 启动
  1. static uint32_t iss_pwm_start(iss_pwm_dev_s *pwm)
  2. {
  3.     if (pwm->init == 0)
  4.     {
  5.         printf("PWM not initn");
  6.         return 1;
  7.     }
  8.     else if (LzPwmStart(pwm->port, pwm->duty * pwm->cycle / 100, pwm->cycle) != 0)
  9.     {
  10.         printf("PWM Start Failn");
  11.         return 1;
  12.     }
  13.     pwm->onoff = 1;
  14.     return 0;
  15. }
复制代码

pwm停止
  1. static uint32_t iss_pwm_stop(iss_pwm_dev_s *pwm)
  2. {
  3.     if (pwm->init == 0)
  4.     {
  5.         printf("PWM not initn");
  6.         return 1;
  7.     }
  8.     else if (pwm->onoff == 0)
  9.     {
  10.         return 0;
  11.     }
  12.     else if (LzPwmStop(pwm->port) != 0)
  13.     {
  14.         printf("PWM Stop Failn");
  15.         return 1;
  16.     }
  17.     pwm->onoff = 0;
  18.     return 0;
  19. }
复制代码

蜂鸣器报警控制,需要报警时启动pwm,不需要报警时停止pwm
  1. void e53_iss_beep_status_set(e53_iss_status_e status)
  2. {
  3.     if (status == ON)
  4.     {
  5.         iss_pwm_start(&m_iss_beep);
  6.     }
  7.     if (status == OFF)
  8.     {
  9.         iss_pwm_stop(&m_iss_beep);
  10.     }
  11. }
复制代码

整个模块初始化
  1. uint32_t e53_iss_init()
  2. {
  3. uint32_t ret = 1;

  4.     ret = iss_led_dev_init(&m_iss_led);
  5.     if (ret != 0)
  6.     {
  7.         printf(“led init errn”);
  8.     }
  9.     ret = iss_pwm_dev_init(&m_iss_beep);
  10.     if (ret != 0)
  11.     {
  12.          printf(“pwm init errn”);
  13.     }
  14.     ret = iss_adc_dev_init(&m_iss_mq2);
  15.     if (ret != 0)
  16.     {
  17.          printf(“adc init errn”);
  18.     }
  19.     return ret;
  20. }
复制代码

创建一个任务处理函数
这里需要注意的是ppm校准需要提前测试,再把值写死到代码里。
还有需要注意的是mq2传感器需要预热,即提前通电大约半分钟到一分钟左右。用手放在传感器外壳感觉微微发热即可。如果不预热就开始测量其测量值会偏差很大,而且会随着加热而变化。

  1. void e53_iss_thread(void *args)
  2. {
  3.     float ppm = 0;
  4.     uint32_t id    = 0;
  5.     uint8_t  index = 0;

  6.     e53_iss_init();
  7.     printf("%sn", __FUNCTION__);
  8.     /*传感器校准*/
  9.     LOS_Msleep(2000); // 开机2s后进行校准
  10.     // e53_iss_mq2_ppm_calibration(); // 校准传感器校准后不需要重复调用
  11.     while (1)
  12.     {
  13.         ppm = e53_iss_get_mq2_ppm();
  14.         printf("ppm:%.1f n", ppm);
  15.         /*判断是否达到报警阈值*/
  16.         if (ppm > e53_iss_get_mq2_alarm_value())
  17.         {
  18.             e53_iss_beep_status_set(ON);
  19.             printf("over %u ppm alarmn", e53_iss_get_mq2_alarm_value());
  20.         }
  21.         else
  22.         {
  23.             e53_iss_led_status_set(OFF);
  24.             e53_iss_beep_status_set(OFF);
  25.         }
  26. LOS_Msleep(1000);
  27.     }
  28. }
复制代码

最后创建一个任务调用上面处理函数即可。
烧写程序后通过串口打印结果

  1. ppm:55.6
  2. ppm:60.9
复制代码

当检测到烟雾超过设定值时蜂鸣器报警响起。低于设置值时蜂鸣器停止报警。这样基于小凌派的烟雾报警功能就实现了。


回帖

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容图片侵权或者其他问题,请联系本站作侵删。 侵权投诉
链接复制成功,分享给好友