野火电子论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 811|回复: 0

【野火】瑞萨RA MCU创意氛围赛+室内空气质量监测盒子

[复制链接]
发表于 2023-8-8 23:48:05 | 显示全部楼层 |阅读模式
本帖最后由 Dyc. 于 2023-8-23 21:39 编辑

一、背景

   空气污染越来越被大家重视,人们80%的时间都是在室内度过的,室内的空气环境质量对人们的身体健康更是息息相关,有幸参加野火电子与瑞萨联合举办的创意氛围赛,借着这次能白嫖的机会,把手里现有的传感器在RA平台上完成一个室内空气质量监测的盒子实现,有不足之处希望各位大佬指正修改开源(减少脑细胞死亡),下面介绍一下整个系统的架构,以及各个模块功能作用。


二、系统设计与实现
   白嫖当然申请最高配置的(野火启明RA6M5),各个传感器模块采集数据到RA6M5,进行数据处理和组包,在OLED屏山显示实时采集的数据,监测各个模块采集数据是否在合理范围,当超出安全值时,根据不同梯度范围,使蜂鸣器发出不同音调的声音进行提示。数据组包完成后,与板载的ESP8266进行通信,将采集的数据通过WiFi远程传输到Blinker服务器中,手机端访问blinker应用可查看历史和当前监测的室内环境数据信息。


系统架构

系统架构


三、硬件模块
   整个系统分为四个模块,分别是数据采集:各个传感器感知数据, 数据处理传输:启明RA6M5(最强大脑),板载ESP8266,数据显示:0.96寸OLED屏,Blinker终端显示, 报警提示:蜂鸣器。传感器:温湿度采集 SH30、颗粒物浓度监测 PMS1003、 二氧化碳浓度监测 MH-Z19B、甲醛浓度监测 DS-HCHO,每个模块的具体性能就不一一列举了,此处省略1000字(淘宝百度很详细),这里贴几张图占位置。
SH30:

sh30

sh30
                                       DS-HCHO:

HCHO

HCHO


PMS1003:

pms1003

pms1003
                                 MH-Z19B:

mh-z19b

mh-z19b


其余模块都在板子上,可看野火淘宝旗舰店官方高清大图

四、系统实现
详情见代码: 室内空气质量监测.zip (2.9 MB, 下载次数: 19)
针对上面的系统架构中各个模块在,代码中的具体实现,下面简要列举几个模块
1.这是系统进入的原始接口,实现方式是串行模式,最开始初始化系统,LED、按键、串口打印、串口通信,温度传感器、CO2、空气质量传感器、OLED、HCHO、Beep,然后进入while循环依次调用各模块数据读取接口。
  1. void hal_entry(void)
  2. {
  3.     /* TODO: add your own code here */

  4.     LED_Init();         // LED 初始化
  5.     Key_IRQ_Init(); // KEY 外部中断初始化

  6.     Debug_UART4_Init(); // SCI4 UART 调试串口初始化
  7.     Debug_UART9_Init();

  8.     gxht30_init(); //白 sda:p105 黄 scl:p104
  9.     double  a = 0.0;
  10.     double  b = 0.0;
  11.     uint8_t buff1[22];
  12.     uint8_t buff2[25];
  13.     uint8_t buff3[23];
  14.     uint8_t buff4[16];

  15.     OLED_Init();    // scl - P505    sda - P506

  16.     CO2_init();//白-> rx3: 408  棕->tx3:409   红:5v  黑:Gnd
  17.     int co2=0;

  18.      struct PM25 *PM_data = NULL;
  19.      PM_data = (struct PM25 *)malloc(sizeof(struct PM25));
  20.      PM25_init();// 蓝 -> rx5:p513   黑 -> tx5:p805  红色:5v  黄色:GND

  21.      HCHO_init(); //黄——> rx2:p302  绿——>tx2:p301
  22. //    printf("start\r\n");

  23.     OLED_Clear();
  24.     R_BSP_SoftwareDelay(3, BSP_DELAY_UNITS_MILLISECONDS);
  25.     while(1)
  26.     {
  27.         LED2_ON;
  28.         if (recv_flag) {//debug
  29.             recv_flag = false;
  30.             sprintf(Send_buff, "%2x %4d %2.2f %2.2f %5d %.2f %2x", 0x42, co2, a, b, PM2_5, hcho_data, 0xff);//28
  31.             printf ("%s\r\n", Send_buff);
  32.             memset(Send_buff, 0, sizeof(Send_buff));
  33.         }

  34.         if (uart9_recv_flag) {// send data to esp8266
  35.             if (!CO2_read()) {
  36.                 co2 = co2_data;
  37.                 // Buzzer_co2(co2);
  38.                 // printf("co2:%d\r\n", co2);
  39.             }
  40.             if(gxht30_read()) {
  41.                 a = gxht30_get_temperature();
  42.                 b = gxht30_get_humidity();
  43.                 // printf("Temp:%.2f Humi:%.2f\r\n", a, b);
  44.             }
  45.             PM25_read(PM_data);
  46.             if (PM_data != NULL) {
  47.                 // printf("PM1_0:%d PM2_5:%d PM10:%d\r\n", PM1_0, PM2_5, PM10);
  48.             }

  49.              if (HCHO_read()) {
  50.                  // Buzzer_hcho(hcho_data);
  51.                  // printf("hcho:%.2f %s\r\n", hcho_data, hcho_unit);
  52.              }

  53.             sprintf(buff1,"Temp:%.2f Humi:%.2f", a , b);
  54.             sprintf(buff2,"PM1.0:%d  PM2.5:%d", PM1_0, PM2_5);
  55.             sprintf(buff3,"PM10:%d   CO2:%d", PM10 , co2);
  56.             sprintf(buff4,"HCHO:%.2f %s", hcho_data, hcho_unit);

  57.             sprintf(Send_buff, "%2x %4d %2.2f %2.2f %5d %2x\r\n", 0x42, co2, a, b, PM2_5, 0xff);//28

  58.             // printf ("buff1:%d\n", strlen(buff1));
  59.             // printf ("buff2:%d\n", strlen(buff2));
  60.             // printf ("buff3:%d\n", strlen(buff3));
  61.             // printf ("buff4:%d\n", strlen(buff4));
  62.             LED3_ON;
  63.             uart9_recv_flag = false;
  64.             uint32_t send_leng = 0;
  65.             send_leng = strlen(Send_buff);
  66.             uart9_Write_data(Send_buff, send_leng);
  67.             memset(Send_buff, 0, sizeof(Send_buff));
  68.             LED3_OFF;

  69.             OLED_ShowString(0, 0, "Temp:", 12, 1);
  70. //显示2个数字
  71. //x,y :起点坐标
  72. //len :数字的位数
  73. //size:字体大小
  74. //mode:模式  0,填充模式;1,叠加模式
  75. //num:数值(0~4294967295);
  76. // void OLED_ShowNum(uint8_t x, uint8_t y, uint32_t num, uint8_t len, uint8_t size, uint8_t mode)
  77.             // OLED_ShowNum(26, 0, 20, 2, 12, 1);
  78.             OLED_ShowString(0, 0, buff1, 12, 1);
  79.             OLED_ShowString(0, 13, buff2, 12, 1);
  80.             OLED_ShowString(0, 26, buff3, 12, 1);
  81.             OLED_ShowString(0, 38, buff4, 12, 1);
  82.             OLED_Refresh_Gram();
  83.         }

  84.     //    OLED_ShowHzStringRow(30, 0, (const char*)"启明", 1);
  85.     //    OLED_ShowString(62, 0, (const uint8_t*)"R6M5", 16, 1);
  86.     //    OLED_ShowHzStringRow(32, 24, (const char*)"电子发烧友", 1);

  87.         /* 判断按键 KEY1_SW2 是否被按下 */
  88.         if (key1_sw2_press)
  89.         {
  90.             key1_sw2_press = false; //标志位清零
  91.             // PM_SLEEP_ON;
  92.             // BEEP_ON = true;
  93.             OLED_Clear();
  94.             R_BSP_SoftwareDelay(10, BSP_DELAY_UNITS_MILLISECONDS); // 10ms
  95.             OLED_ON();
  96.         }

  97.         /* 判断按键 KEY2_SW3 是否被按下 */
  98.         if (key2_sw3_press)
  99.         {
  100.             key2_sw3_press = false; //标志位清零
  101. //            PM_SLEEP_OFF;
  102. //            BEEP_ON = false;
  103.             OLED_OFF();
  104.             LED3_TOGGLE;            //LED3 翻转
  105.         }
  106.         R_BSP_SoftwareDelay(2, BSP_DELAY_UNITS_SECONDS);
  107.         LED2_OFF;
  108.         R_BSP_SoftwareDelay(2, BSP_DELAY_UNITS_SECONDS);
  109.     }
  110.    free(PM_data);


  111. #if BSP_TZ_SECURE_BUILD
  112.     /* Enter non-secure code */
  113.     R_BSP_NonSecureEnter();
  114. #endif
  115. }
复制代码

2、CO2模块
根据数据CO2数据使用手册,实现数据读取校验功能
  1. int CO2_read()
  2. {
  3.     uint8_t co2_tmp_buff[9];
  4.     memset(co2_tmp_buff, 0, sizeof(co2_tmp_buff));

  5.     int ret =0;

  6.     if (only_once_skip)
  7.     {
  8.         only_once_skip = 0;
  9.         // first data is error, so skip
  10.         Write_data(str);
  11.         R_BSP_SoftwareDelay (100, BSP_DELAY_UNITS_MILLISECONDS);

  12.         co2_err = R_SCI_UART_Read (&g_uart3_ctrl, co2_tmp_buff, 9);
  13.         assert(FSP_SUCCESS == co2_err);
  14.         memset(co2_tmp_buff, 0, sizeof(co2_tmp_buff));
  15.         R_BSP_SoftwareDelay (500, BSP_DELAY_UNITS_MILLISECONDS);
  16.     }

  17.     uint8_t i;
  18.     for (i = 0; i < 1; i++)
  19.     {
  20.         Write_data(str);
  21.         R_BSP_SoftwareDelay (100, BSP_DELAY_UNITS_MILLISECONDS);

  22.         co2_err = R_SCI_UART_Read (&g_uart3_ctrl, co2_tmp_buff, 9);
  23.         assert(FSP_SUCCESS == co2_err);
  24.         while ((UART_EVENT_RX_COMPLETE != g_uart3_event) && timeout_ms > 0)
  25.         {
  26.             R_BSP_SoftwareDelay(1U, BSP_DELAY_UNITS_MILLISECONDS);
  27.             timeout_ms--;
  28.         }
  29.         if (UART_EVENT_ERR_FRAMING == g_uart3_event)
  30.         {
  31.         
  32.             __BKPT(0);
  33.         }
  34.         g_uart3_event = UART_EVENT_ERR_FRAMING;
  35.         timeout_ms    = 100000;

  36.         // uint8_t j =0;//打印接收到的原始数据
  37.         // for (j =0; j < 9; j++)
  38.         // {
  39.         //     printf("num:%d 0x%02x\n",j, co2_tmp_buff[j]);
  40.         // }

  41.         co2_data = 0;
  42.         co2_data = co2_tmp_buff[2] *256 + co2_tmp_buff[3];
  43.             
  44.         ret = getCheckSum(co2_tmp_buff);

  45.         if (ret == 0)
  46.         {
  47.             co2_data = 0;
  48.             co2_data = co2_tmp_buff[2] *256 + co2_tmp_buff[3];
  49.         //    printf("%s()%d co2_data:%d\n", __func__, __LINE__, co2_data);
  50.             break;
  51.         }
  52.         printf("%s()%d CO2 check sum error\r\n",__func__, __LINE__);
  53.         i = 0;//retry only once
  54.     }

  55.     return ret;
  56. }
复制代码

3、温度传感器
根据sht30数据手册,完成数据采集读取功能
  1. bool gxht30_read()
  2. {

  3.     Humiture_HS3003_writeRegister(gxht30_cmd_read_interval_measure, 2);
  4.     uint8_t data[6] = { 0 };
  5.     timeout_ms1           = 100000;

  6.     gxht30_err = R_SCI_I2C_Read(&g_sci8_i2c_ctrl, data, sizeof(data), true);//true  false
  7.     assert(FSP_SUCCESS == gxht30_err);
  8.     while ((I2C_MASTER_EVENT_RX_COMPLETE != sci8_i2c_event) && timeout_ms1)
  9.     {
  10.         R_BSP_SoftwareDelay(1U, BSP_DELAY_UNITS_MILLISECONDS);
  11.         timeout_ms1--;
  12.     }
  13.     if (I2C_MASTER_EVENT_ABORTED == sci8_i2c_event)
  14.     {
  15.         __BKPT(0);
  16.     }

  17.     sci8_i2c_event = I2C_MASTER_EVENT_ABORTED;
  18.     timeout_ms1           = 100000;

  19.     //check CRC, when fail, return false
  20.     if (data[2] != crc8 (data, 2) || data[5] != crc8 (&data[3], 2))
  21.     {
  22.         return false;
  23.     }
  24.     temperature = ((((data[0] * 256.0) + data[1]) * 175) / 65535.0) - 45;
  25.     humidity = (((data[3] * 256.0) + data[4]) * 100) / 65535.0;

  26. //    printf("Temp:%.2f\r\n", temperature);
  27. //    printf("Humidity:%.2f\r\n", humidity);
  28.     return true;
  29. }
复制代码
4、空气质量传感器
这里使用的PMS1003,可以采集PM1.0, PM2.5, PM10等颗粒物浓度,可以根据项目需求进行调整
  1. int PM25_read(struct PM25 *p)
  2. {
  3.     read_flag = 0;
  4.     memset(tmp_Buff,0,sizeof(tmp_Buff));

  5.     while(1)
  6.     {
  7.         uint8_t ch;
  8.         read(&g_uart5_ctrl, &ch, 1);
  9.         if (uart_recv0_complete_flag == true && read_flag == 32)
  10.         {
  11.             uart_recv0_complete_flag = false;
  12.             int ret = 0;
  13.             read_flag = 0;
  14.         //    int j =0;//PM2.5 原始数据
  15.         //    for (j =0; j < read_flag; j++)
  16.         //    {
  17.         //        printf("num:%d 0x%02lx\n",j, tmp_Buff[j]);
  18.         //    }
  19.             ret = data_checksum(p);
  20.             if (ret == 0)
  21.             {
  22.                 break;
  23.             }

  24.             printf("%s()%d PM2.5 data checksum error\r\n", __func__, __LINE__);
  25.             break;
  26.         }
  27.     }

  28.     return 0;
  29. }
复制代码
5、HCHO
甲醛浓度传感器,目前使用的这个模块能采集多种有毒有害气体,根据数据手册实现了采集校验,区分气体类型功能
  1. int HCHO_read()
  2. {
  3.     uint8_t hcho_tmp_buff[10];
  4.     memset(hcho_tmp_buff, 0, sizeof(hcho_tmp_buff));

  5.     int ret =0;
  6.     uint8_t str[7] = {0x42, 0x4d, 0x01, 0x00, 0x00, 0x00, 0x90};
  7.     int equivalent = 1;//当量

  8.     if (hcho_only_once_skip)
  9.     {
  10.         hcho_only_once_skip = 0;
  11.         // first data is error, so skip
  12.         HCHO_Write_data(str);
  13.         R_BSP_SoftwareDelay (100, BSP_DELAY_UNITS_MILLISECONDS);

  14.         hcho_err = R_SCI_UART_Read (&g_uart2_ctrl, hcho_tmp_buff, 10);
  15.         assert(FSP_SUCCESS == hcho_err);
  16.         memset(hcho_tmp_buff, 0, sizeof(hcho_tmp_buff));
  17.         R_BSP_SoftwareDelay (500, BSP_DELAY_UNITS_MILLISECONDS);
  18.     }

  19.     uint8_t i;
  20.     for (i = 0; i < 1; i++)
  21.     {

  22.         HCHO_Write_data(str);
  23.         R_BSP_SoftwareDelay (100, BSP_DELAY_UNITS_MILLISECONDS);

  24.         hcho_err = R_SCI_UART_Read (&g_uart2_ctrl, hcho_tmp_buff, 10);
  25.         assert(FSP_SUCCESS == hcho_err);
  26.         while ((UART_EVENT_RX_COMPLETE != g_uart2_event) && hcho_timeout_ms > 0)
  27.         {
  28.             R_BSP_SoftwareDelay(1U, BSP_DELAY_UNITS_MILLISECONDS);
  29.             hcho_timeout_ms--;
  30.         }
  31.         if (UART_EVENT_ERR_FRAMING == g_uart2_event)
  32.         {
  33.             __BKPT(0);
  34.         }
  35.         g_uart2_event = UART_EVENT_ERR_FRAMING;
  36.         hcho_timeout_ms    = 100000;

  37.         // int j =0;//打印HCHO原始数据
  38.         // for (j =0; j < 10; j++)
  39.         // {
  40.         //     printf("num:%d 0x%02x\n",j, hcho_tmp_buff[j]);
  41.         // }
  42.         // printf("\n");

  43.         ret = HCHOCheckSum(hcho_tmp_buff);
  44.         if (ret == 0)
  45.         {
  46.             if (hcho_tmp_buff[3] == 0x14)
  47.             {
  48.                 // 数据单位标识
  49.                 if (hcho_tmp_buff[4] == 0x01)
  50.                 {
  51.                     hcho_unit = "ppm";
  52.                 }
  53.                 else if (hcho_tmp_buff[4] == 0x02)
  54.                 {
  55.                     hcho_unit = "VOL";
  56.                 }
  57.                 else if (hcho_tmp_buff[4] == 0x03)
  58.                 {
  59.                     hcho_unit = "LEL";
  60.                 }
  61.                 else if (hcho_tmp_buff[4] == 0x04)
  62.                 {
  63.                     hcho_unit = "Ppb";
  64.                 }
  65.                 else if (hcho_tmp_buff[4] == 0x05)
  66.                 {
  67.                     hcho_unit = "Mg/m3";
  68.                 }
  69.                 else
  70.                 {
  71.                     hcho_unit = "unknown";
  72.                 }

  73.                 //当量判断
  74.                 if (0x01 == hcho_tmp_buff[5])
  75.                 {
  76.                     equivalent = 1;
  77.                 }
  78.                 else if(0x02 == hcho_tmp_buff[5])
  79.                 {
  80.                     equivalent = 10;
  81.                 }
  82.                 else if(0x03 == hcho_tmp_buff[5])
  83.                 {
  84.                     equivalent = 100;
  85.                 }
  86.                 else if(0x04 == hcho_tmp_buff[5])
  87.                 {
  88.                     equivalent = 1000;
  89.                 }
  90.                 else
  91.                 {
  92.                     printf("%s():%d equivalent read error\r\n", __func__, __LINE__);
  93.                 }

  94.                 hcho_data = (float)((hcho_tmp_buff[6]<<8) | hcho_tmp_buff[7]);
  95.                 hcho_data = hcho_data / (float)equivalent;
  96.                 // printf("%s():%d hcho_data:%.2f %s\r\n", __func__, __LINE__, hcho_data, hcho_unit);
  97.                 ret = 1;
  98.                 break;
  99.             }
  100.         }
  101.         printf("%s():%d HCHO check sum error\r\n", __func__, __LINE__);
  102.         i = 0;//retry only once
  103.     }

  104.     ret = -1;
  105.     return ret;
  106. }
复制代码
6、RA6M5与ESP8266通信
通过串口回调,实现RA6M5与ESP8266数据的通信传输功能
  1. void uart9_Write_data(uint8_t *buffer, uint32_t datalen)
  2. {
  3.     R_BSP_SoftwareDelay(10, BSP_DELAY_UNITS_MILLISECONDS);

  4.     uart9_err = R_SCI_UART_Write(&g_uart9_ctrl, buffer, datalen);
  5.     assert(FSP_SUCCESS == uart9_err);
  6.     while ((UART_EVENT_TX_DATA_EMPTY != g_uart9_event) && uart9_timeout_ms > 0)
  7.     {
  8.         R_BSP_SoftwareDelay(1U, BSP_DELAY_UNITS_MICROSECONDS);
  9.         uart9_timeout_ms--;
  10.     }
  11.     if (UART_EVENT_ERR_FRAMING == g_uart9_event)
  12.     {
  13.         __BKPT(0);
  14.     }

  15.     g_uart9_event = UART_EVENT_ERR_FRAMING;
  16.     uart9_timeout_ms    = 100000;
  17. }

  18. void uart9_read_data(uint8_t *buffer, uint32_t datalen)
  19. {
  20.     uart9_err = R_SCI_UART_Read (&g_uart9_ctrl, buffer, datalen);
  21.     assert(FSP_SUCCESS == uart9_err);
  22.     while ((UART_EVENT_RX_COMPLETE != g_uart9_event) && uart9_timeout_ms > 0)
  23.     {
  24.         R_BSP_SoftwareDelay(1U, BSP_DELAY_UNITS_MILLISECONDS);
  25.         uart9_timeout_ms--;
  26.     }
  27.     if (UART_EVENT_ERR_FRAMING == g_uart9_event)
  28.     {
  29.         __BKPT(0);
  30.     }
  31.     g_uart9_event = UART_EVENT_ERR_FRAMING;
  32.     uart9_timeout_ms    = 100000;
  33. }
复制代码






五、界面展示
终端显示画面:

1

1

2

2


板子画面: 野火论坛202308082349248607..png











回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

联系站长|手机版|野火电子官网|野火淘宝店铺|野火电子论坛 ( 粤ICP备14069197号 ) 大学生ARM嵌入式2群

GMT+8, 2024-5-4 10:16 , Processed in 0.045752 second(s), 28 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表