初中生
最后登录1970-1-1
在线时间 小时
注册时间2023-8-6
|
本帖最后由 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
DS-HCHO:
HCHO
PMS1003:
pms1003
MH-Z19B:
mh-z19b
其余模块都在板子上,可看野火淘宝旗舰店官方高清大图
四、系统实现
详情见代码:
室内空气质量监测.zip
(2.9 MB, 下载次数: 27)
针对上面的系统架构中各个模块在,代码中的具体实现,下面简要列举几个模块
1.这是系统进入的原始接口,实现方式是串行模式,最开始初始化系统,LED、按键、串口打印、串口通信,温度传感器、CO2、空气质量传感器、OLED、HCHO、Beep,然后进入while循环依次调用各模块数据读取接口。- void hal_entry(void)
- {
- /* TODO: add your own code here */
- LED_Init(); // LED 初始化
- Key_IRQ_Init(); // KEY 外部中断初始化
- Debug_UART4_Init(); // SCI4 UART 调试串口初始化
- Debug_UART9_Init();
- gxht30_init(); //白 sda:p105 黄 scl:p104
- double a = 0.0;
- double b = 0.0;
- uint8_t buff1[22];
- uint8_t buff2[25];
- uint8_t buff3[23];
- uint8_t buff4[16];
- OLED_Init(); // scl - P505 sda - P506
- CO2_init();//白-> rx3: 408 棕->tx3:409 红:5v 黑:Gnd
- int co2=0;
- struct PM25 *PM_data = NULL;
- PM_data = (struct PM25 *)malloc(sizeof(struct PM25));
- PM25_init();// 蓝 -> rx5:p513 黑 -> tx5:p805 红色:5v 黄色:GND
- HCHO_init(); //黄——> rx2:p302 绿——>tx2:p301
- // printf("start\r\n");
- OLED_Clear();
- R_BSP_SoftwareDelay(3, BSP_DELAY_UNITS_MILLISECONDS);
- while(1)
- {
- LED2_ON;
- if (recv_flag) {//debug
- recv_flag = false;
- sprintf(Send_buff, "%2x %4d %2.2f %2.2f %5d %.2f %2x", 0x42, co2, a, b, PM2_5, hcho_data, 0xff);//28
- printf ("%s\r\n", Send_buff);
- memset(Send_buff, 0, sizeof(Send_buff));
- }
- if (uart9_recv_flag) {// send data to esp8266
- if (!CO2_read()) {
- co2 = co2_data;
- // Buzzer_co2(co2);
- // printf("co2:%d\r\n", co2);
- }
- if(gxht30_read()) {
- a = gxht30_get_temperature();
- b = gxht30_get_humidity();
- // printf("Temp:%.2f Humi:%.2f\r\n", a, b);
- }
- PM25_read(PM_data);
- if (PM_data != NULL) {
- // printf("PM1_0:%d PM2_5:%d PM10:%d\r\n", PM1_0, PM2_5, PM10);
- }
- if (HCHO_read()) {
- // Buzzer_hcho(hcho_data);
- // printf("hcho:%.2f %s\r\n", hcho_data, hcho_unit);
- }
- sprintf(buff1,"Temp:%.2f Humi:%.2f", a , b);
- sprintf(buff2,"PM1.0:%d PM2.5:%d", PM1_0, PM2_5);
- sprintf(buff3,"PM10:%d CO2:%d", PM10 , co2);
- sprintf(buff4,"HCHO:%.2f %s", hcho_data, hcho_unit);
- sprintf(Send_buff, "%2x %4d %2.2f %2.2f %5d %2x\r\n", 0x42, co2, a, b, PM2_5, 0xff);//28
- // printf ("buff1:%d\n", strlen(buff1));
- // printf ("buff2:%d\n", strlen(buff2));
- // printf ("buff3:%d\n", strlen(buff3));
- // printf ("buff4:%d\n", strlen(buff4));
- LED3_ON;
- uart9_recv_flag = false;
- uint32_t send_leng = 0;
- send_leng = strlen(Send_buff);
- uart9_Write_data(Send_buff, send_leng);
- memset(Send_buff, 0, sizeof(Send_buff));
- LED3_OFF;
- OLED_ShowString(0, 0, "Temp:", 12, 1);
- //显示2个数字
- //x,y :起点坐标
- //len :数字的位数
- //size:字体大小
- //mode:模式 0,填充模式;1,叠加模式
- //num:数值(0~4294967295);
- // void OLED_ShowNum(uint8_t x, uint8_t y, uint32_t num, uint8_t len, uint8_t size, uint8_t mode)
- // OLED_ShowNum(26, 0, 20, 2, 12, 1);
- OLED_ShowString(0, 0, buff1, 12, 1);
- OLED_ShowString(0, 13, buff2, 12, 1);
- OLED_ShowString(0, 26, buff3, 12, 1);
- OLED_ShowString(0, 38, buff4, 12, 1);
- OLED_Refresh_Gram();
- }
- // OLED_ShowHzStringRow(30, 0, (const char*)"启明", 1);
- // OLED_ShowString(62, 0, (const uint8_t*)"R6M5", 16, 1);
- // OLED_ShowHzStringRow(32, 24, (const char*)"电子发烧友", 1);
- /* 判断按键 KEY1_SW2 是否被按下 */
- if (key1_sw2_press)
- {
- key1_sw2_press = false; //标志位清零
- // PM_SLEEP_ON;
- // BEEP_ON = true;
- OLED_Clear();
- R_BSP_SoftwareDelay(10, BSP_DELAY_UNITS_MILLISECONDS); // 10ms
- OLED_ON();
- }
- /* 判断按键 KEY2_SW3 是否被按下 */
- if (key2_sw3_press)
- {
- key2_sw3_press = false; //标志位清零
- // PM_SLEEP_OFF;
- // BEEP_ON = false;
- OLED_OFF();
- LED3_TOGGLE; //LED3 翻转
- }
- R_BSP_SoftwareDelay(2, BSP_DELAY_UNITS_SECONDS);
- LED2_OFF;
- R_BSP_SoftwareDelay(2, BSP_DELAY_UNITS_SECONDS);
- }
- free(PM_data);
- #if BSP_TZ_SECURE_BUILD
- /* Enter non-secure code */
- R_BSP_NonSecureEnter();
- #endif
- }
复制代码
2、CO2模块
根据数据CO2数据使用手册,实现数据读取校验功能
- int CO2_read()
- {
- uint8_t co2_tmp_buff[9];
- memset(co2_tmp_buff, 0, sizeof(co2_tmp_buff));
- int ret =0;
- if (only_once_skip)
- {
- only_once_skip = 0;
- // first data is error, so skip
- Write_data(str);
- R_BSP_SoftwareDelay (100, BSP_DELAY_UNITS_MILLISECONDS);
-
- co2_err = R_SCI_UART_Read (&g_uart3_ctrl, co2_tmp_buff, 9);
- assert(FSP_SUCCESS == co2_err);
- memset(co2_tmp_buff, 0, sizeof(co2_tmp_buff));
- R_BSP_SoftwareDelay (500, BSP_DELAY_UNITS_MILLISECONDS);
- }
- uint8_t i;
- for (i = 0; i < 1; i++)
- {
- Write_data(str);
- R_BSP_SoftwareDelay (100, BSP_DELAY_UNITS_MILLISECONDS);
-
- co2_err = R_SCI_UART_Read (&g_uart3_ctrl, co2_tmp_buff, 9);
- assert(FSP_SUCCESS == co2_err);
- while ((UART_EVENT_RX_COMPLETE != g_uart3_event) && timeout_ms > 0)
- {
- R_BSP_SoftwareDelay(1U, BSP_DELAY_UNITS_MILLISECONDS);
- timeout_ms--;
- }
- if (UART_EVENT_ERR_FRAMING == g_uart3_event)
- {
-
- __BKPT(0);
- }
- g_uart3_event = UART_EVENT_ERR_FRAMING;
- timeout_ms = 100000;
- // uint8_t j =0;//打印接收到的原始数据
- // for (j =0; j < 9; j++)
- // {
- // printf("num:%d 0x%02x\n",j, co2_tmp_buff[j]);
- // }
- co2_data = 0;
- co2_data = co2_tmp_buff[2] *256 + co2_tmp_buff[3];
-
- ret = getCheckSum(co2_tmp_buff);
- if (ret == 0)
- {
- co2_data = 0;
- co2_data = co2_tmp_buff[2] *256 + co2_tmp_buff[3];
- // printf("%s()%d co2_data:%d\n", __func__, __LINE__, co2_data);
- break;
- }
- printf("%s()%d CO2 check sum error\r\n",__func__, __LINE__);
- i = 0;//retry only once
- }
- return ret;
- }
复制代码
3、温度传感器
根据sht30数据手册,完成数据采集读取功能
- bool gxht30_read()
- {
- Humiture_HS3003_writeRegister(gxht30_cmd_read_interval_measure, 2);
- uint8_t data[6] = { 0 };
- timeout_ms1 = 100000;
- gxht30_err = R_SCI_I2C_Read(&g_sci8_i2c_ctrl, data, sizeof(data), true);//true false
- assert(FSP_SUCCESS == gxht30_err);
- while ((I2C_MASTER_EVENT_RX_COMPLETE != sci8_i2c_event) && timeout_ms1)
- {
- R_BSP_SoftwareDelay(1U, BSP_DELAY_UNITS_MILLISECONDS);
- timeout_ms1--;
- }
- if (I2C_MASTER_EVENT_ABORTED == sci8_i2c_event)
- {
- __BKPT(0);
- }
- sci8_i2c_event = I2C_MASTER_EVENT_ABORTED;
- timeout_ms1 = 100000;
- //check CRC, when fail, return false
- if (data[2] != crc8 (data, 2) || data[5] != crc8 (&data[3], 2))
- {
- return false;
- }
- temperature = ((((data[0] * 256.0) + data[1]) * 175) / 65535.0) - 45;
- humidity = (((data[3] * 256.0) + data[4]) * 100) / 65535.0;
- // printf("Temp:%.2f\r\n", temperature);
- // printf("Humidity:%.2f\r\n", humidity);
- return true;
- }
复制代码 4、空气质量传感器
这里使用的PMS1003,可以采集PM1.0, PM2.5, PM10等颗粒物浓度,可以根据项目需求进行调整
- int PM25_read(struct PM25 *p)
- {
- read_flag = 0;
- memset(tmp_Buff,0,sizeof(tmp_Buff));
- while(1)
- {
- uint8_t ch;
- read(&g_uart5_ctrl, &ch, 1);
- if (uart_recv0_complete_flag == true && read_flag == 32)
- {
- uart_recv0_complete_flag = false;
- int ret = 0;
- read_flag = 0;
- // int j =0;//PM2.5 原始数据
- // for (j =0; j < read_flag; j++)
- // {
- // printf("num:%d 0x%02lx\n",j, tmp_Buff[j]);
- // }
- ret = data_checksum(p);
- if (ret == 0)
- {
- break;
- }
- printf("%s()%d PM2.5 data checksum error\r\n", __func__, __LINE__);
- break;
- }
- }
- return 0;
- }
复制代码 5、HCHO
甲醛浓度传感器,目前使用的这个模块能采集多种有毒有害气体,根据数据手册实现了采集校验,区分气体类型功能
- int HCHO_read()
- {
- uint8_t hcho_tmp_buff[10];
- memset(hcho_tmp_buff, 0, sizeof(hcho_tmp_buff));
- int ret =0;
- uint8_t str[7] = {0x42, 0x4d, 0x01, 0x00, 0x00, 0x00, 0x90};
- int equivalent = 1;//当量
- if (hcho_only_once_skip)
- {
- hcho_only_once_skip = 0;
- // first data is error, so skip
- HCHO_Write_data(str);
- R_BSP_SoftwareDelay (100, BSP_DELAY_UNITS_MILLISECONDS);
-
- hcho_err = R_SCI_UART_Read (&g_uart2_ctrl, hcho_tmp_buff, 10);
- assert(FSP_SUCCESS == hcho_err);
- memset(hcho_tmp_buff, 0, sizeof(hcho_tmp_buff));
- R_BSP_SoftwareDelay (500, BSP_DELAY_UNITS_MILLISECONDS);
- }
- uint8_t i;
- for (i = 0; i < 1; i++)
- {
- HCHO_Write_data(str);
- R_BSP_SoftwareDelay (100, BSP_DELAY_UNITS_MILLISECONDS);
- hcho_err = R_SCI_UART_Read (&g_uart2_ctrl, hcho_tmp_buff, 10);
- assert(FSP_SUCCESS == hcho_err);
- while ((UART_EVENT_RX_COMPLETE != g_uart2_event) && hcho_timeout_ms > 0)
- {
- R_BSP_SoftwareDelay(1U, BSP_DELAY_UNITS_MILLISECONDS);
- hcho_timeout_ms--;
- }
- if (UART_EVENT_ERR_FRAMING == g_uart2_event)
- {
- __BKPT(0);
- }
- g_uart2_event = UART_EVENT_ERR_FRAMING;
- hcho_timeout_ms = 100000;
- // int j =0;//打印HCHO原始数据
- // for (j =0; j < 10; j++)
- // {
- // printf("num:%d 0x%02x\n",j, hcho_tmp_buff[j]);
- // }
- // printf("\n");
- ret = HCHOCheckSum(hcho_tmp_buff);
- if (ret == 0)
- {
- if (hcho_tmp_buff[3] == 0x14)
- {
- // 数据单位标识
- if (hcho_tmp_buff[4] == 0x01)
- {
- hcho_unit = "ppm";
- }
- else if (hcho_tmp_buff[4] == 0x02)
- {
- hcho_unit = "VOL";
- }
- else if (hcho_tmp_buff[4] == 0x03)
- {
- hcho_unit = "LEL";
- }
- else if (hcho_tmp_buff[4] == 0x04)
- {
- hcho_unit = "Ppb";
- }
- else if (hcho_tmp_buff[4] == 0x05)
- {
- hcho_unit = "Mg/m3";
- }
- else
- {
- hcho_unit = "unknown";
- }
- //当量判断
- if (0x01 == hcho_tmp_buff[5])
- {
- equivalent = 1;
- }
- else if(0x02 == hcho_tmp_buff[5])
- {
- equivalent = 10;
- }
- else if(0x03 == hcho_tmp_buff[5])
- {
- equivalent = 100;
- }
- else if(0x04 == hcho_tmp_buff[5])
- {
- equivalent = 1000;
- }
- else
- {
- printf("%s():%d equivalent read error\r\n", __func__, __LINE__);
- }
- hcho_data = (float)((hcho_tmp_buff[6]<<8) | hcho_tmp_buff[7]);
- hcho_data = hcho_data / (float)equivalent;
- // printf("%s():%d hcho_data:%.2f %s\r\n", __func__, __LINE__, hcho_data, hcho_unit);
- ret = 1;
- break;
- }
- }
- printf("%s():%d HCHO check sum error\r\n", __func__, __LINE__);
- i = 0;//retry only once
- }
- ret = -1;
- return ret;
- }
复制代码 6、RA6M5与ESP8266通信
通过串口回调,实现RA6M5与ESP8266数据的通信传输功能
- void uart9_Write_data(uint8_t *buffer, uint32_t datalen)
- {
- R_BSP_SoftwareDelay(10, BSP_DELAY_UNITS_MILLISECONDS);
- uart9_err = R_SCI_UART_Write(&g_uart9_ctrl, buffer, datalen);
- assert(FSP_SUCCESS == uart9_err);
- while ((UART_EVENT_TX_DATA_EMPTY != g_uart9_event) && uart9_timeout_ms > 0)
- {
- R_BSP_SoftwareDelay(1U, BSP_DELAY_UNITS_MICROSECONDS);
- uart9_timeout_ms--;
- }
- if (UART_EVENT_ERR_FRAMING == g_uart9_event)
- {
- __BKPT(0);
- }
- g_uart9_event = UART_EVENT_ERR_FRAMING;
- uart9_timeout_ms = 100000;
- }
- void uart9_read_data(uint8_t *buffer, uint32_t datalen)
- {
- uart9_err = R_SCI_UART_Read (&g_uart9_ctrl, buffer, datalen);
- assert(FSP_SUCCESS == uart9_err);
- while ((UART_EVENT_RX_COMPLETE != g_uart9_event) && uart9_timeout_ms > 0)
- {
- R_BSP_SoftwareDelay(1U, BSP_DELAY_UNITS_MILLISECONDS);
- uart9_timeout_ms--;
- }
- if (UART_EVENT_ERR_FRAMING == g_uart9_event)
- {
- __BKPT(0);
- }
- g_uart9_event = UART_EVENT_ERR_FRAMING;
- uart9_timeout_ms = 100000;
- }
复制代码
五、界面展示
终端显示画面:
1
2
板子画面:
|
|