Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
瑞萨-RTT活动
RT-Thread一般讨论
CPK-RA2L1评估板(5) 室内空气质量监测系统
发布于 2023-03-12 20:59:29 浏览:384
订阅该版
[tocm] # 一、背景 有幸参加RT-Thread的活动,体验RT-Thread Studio 和瑞萨 CPK-RA2L1评估板。本篇结合前面的文章,暂时制作一个空气质量监测系统,主要使用:DHT11、PMS1003, OLED模块, 后续继续扩展甲醛,CO2, IAQ模块 # 二、模块信息 目前使用的三个模块的相关信息,参考:[https://club.rt-thread.org/u/4b47abf4107e49c9/article.html](https://club.rt-thread.org/u/4b47abf4107e49c9/article.html) # 三、新建工程 这里使用的模块,我们需要提前分配好引脚:UART0 采集PMS1003, DHT11 使用P0208 引脚, OLED I2C1通信 使用P0205 P0206, 配置RT-Thread Settings ,添加u8g2 库,配置i2c,具体信息如下图 ![1.png](https://oss-club.rt-thread.org/uploads/20230312/d6468f4982a8ecff1d5b8c67e59af1c2.png.webp) ![2.png](https://oss-club.rt-thread.org/uploads/20230312/0a40d2ba8fb099fde9dec2bc938f177b.png.webp) ![3.png](https://oss-club.rt-thread.org/uploads/20230312/09f99e9105283b058398c8d836c3d319.png.webp) 在 RA Smart Configurator 种添加UART0,配置好引脚和波特率 ![4.png](https://oss-club.rt-thread.org/uploads/20230312/82d2be960d0e22aadcee3c314f5a1f56.png) 在 RA Smart Configurator 种添加I2C1 ![5.png](https://oss-club.rt-thread.org/uploads/20230312/6ec2f2310fa0d391d1355d013cb62864.png) 四、编写代码 hal_entery.c ```c /* * Copyright (c) 2006-2021, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2021-10-10 Sherman first version */ #include
#include "hal_data.h" #include
#include "dht11.h" #include
#include "pms1003.h" #include
#include
#include
//#define DBG_ENABLE //#define DBG_SECTION_NAME "pms_series" //#define DBG_LEVEL DBG_LOG //#define DBG_COLOR //#define DBG_ENABLE #define LED1_PIN "P502" /* Onboard LED pins */ #define USER_INPUT "P004" /******** DHT11 *********/ #define DATA_PIN 0x0208 //P208 dht11 #define THREAD_PRIORITY 5 #define THREAD_STACK_SIZE 1024 #define THREAD_TIMESLICE 10 static rt_thread_t tid_dht11 = RT_NULL; /******** PMS1003 *********/ //tx P101 rx P100 #define PMS_SERIES_UART "uart0" #ifdef PMS_SERIES_SAMPLE_USING_DMA struct rt_messagequeue pms_mq; #else struct rt_semaphore pms_sem; #endif pms_device_t PMS1003; struct rx_msg { rt_device_t dev; rt_size_t size; }; /******** OLED *********/ static rt_thread_t tid_oled = RT_NULL; int temp = 0; int humi = 0; int PM2_5 = 0; int PM10 = 0; static void Dht11ThreadEntry(void *parameter) { dht_device_t sensor = dht_create(DATA_PIN); rt_int32_t temp_; rt_int32_t humi_; while (1) { if(dht_read(sensor)) { temp_ = dht_get_temperature(sensor) / 10; humi_ = dht_get_humidity(sensor) / 10; temp = temp_; humi = humi_; // rt_kprintf("Temp: %d, Humi: %d\n", temp, humi); } else { // rt_kprintf("Read dht sensor failed.\n"); } rt_thread_mdelay(500); } dht_delete(sensor); } int dht11_init() { rt_err_t ret = RT_EOK; tid_dht11 = rt_thread_create("dht11", Dht11ThreadEntry, RT_NULL, THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE); if (tid_dht11 != RT_NULL) { rt_thread_startup(tid_dht11); } else { ret = RT_ERROR; } return ret; } //INIT_APP_EXPORT(dht11_init); void pms_series_debug(pms_device_t dev) { rt_kprintf("*********************************begin***********************************\n"); rt_kprintf("PM1_0_CF1 = %5d\tPM2_5_CF1 = %5d\tPM10_0_CF1 = %5d\n",dev->PM1_0_CF1,dev->PM2_5_CF1,dev->PM10_0_CF1); rt_kprintf("PM1_0_amb = %5d\tPM2_5_amb = %5d\tPM10_0_amb = %5d\n",dev->PM1_0_amb,dev->PM2_5_amb,dev->PM10_0_amb); rt_kprintf("air_0_3um = %5d\tair_0_5um = %5d\tair_1_0um = %5d\n",dev->air_0_3um,dev->air_0_5um,dev->air_1_0um); rt_kprintf("air_2_5um = %5d\t",dev->air_2_5um); rt_kprintf("version = %5d errorCode = %5d\n",dev->version,dev->errorCode); rt_kprintf("********************************over*************************************\n"); } static void serial_thread_entry(void *parameter) { #ifndef PMS_SERIES_SAMPLE_USING_DMA rt_err_t result; char ch; pms_device_t dev = parameter; while (1) { while (rt_device_read(dev->serial, 0, &ch, 1) == 0) { rt_sem_control(&pms_sem, RT_IPC_CMD_RESET, RT_NULL); rt_sem_take(&pms_sem, RT_WAITING_FOREVER); } result = pms_get_byte(dev,ch); if (result == RT_EOK) { // pms_series_debug(dev); // for debug PM2_5 = dev->PM2_5_CF1; PM10 = dev->PM10_0_CF1; // rt_kprintf("air_2_5um = %d\n",PM2_5); } } #endif #ifdef PMS_SERIES_SAMPLE_USING_DMA struct rx_msg msg; rt_err_t result; rt_uint32_t rx_length; static rt_uint8_t rx_buffer[RT_SERIAL_RB_BUFSZ + 1]; pms_device_t dev = parameter; while (1) { rt_memset(&msg, 0, sizeof(msg)); result = rt_mq_recv(&pms_mq, &msg, sizeof(msg), RT_WAITING_FOREVER); if (result == RT_EOK) { rx_length = rt_device_read(msg.dev, 0, rx_buffer, msg.size); rx_buffer[rx_length] = '\0'; result = frame_check(dev,rx_buffer,rx_length); if (result == RT_EOK) { pms_series_debug(dev); rt_kprintf("rx buff success"); } else { rt_kprintf("rx buff error"); } } } #endif } static rt_err_t uart_input(rt_device_t dev, rt_size_t size) { RT_ASSERT(dev); #ifndef PMS_SERIES_SAMPLE_USING_DMA if (size > 0) { rt_sem_release(&pms_sem); } return RT_EOK; #endif #ifdef PMS_SERIES_SAMPLE_USING_DMA rt_err_t result; struct rx_msg msg; msg.dev = dev; msg.size = size; result = rt_mq_send(&pms_mq, &msg, sizeof(msg)); if ( result == -RT_EFULL) { rt_kprintf("message queue full!\n"); } return result; #endif } int PMS1003Init() { static pms_device_t dev = NULL; rt_err_t ret = RT_EOK; dev = pms_init(PMS_SERIES_UART); #ifndef PMS_SERIES_SAMPLE_USING_DMA rt_sem_init(&pms_sem, "pms_sem", 0, RT_IPC_FLAG_FIFO); rt_device_open(dev->serial, RT_DEVICE_FLAG_INT_RX); rt_device_set_rx_indicate(dev->serial, uart_input); #endif #ifdef PMS_SERIES_SAMPLE_USING_DMA static char msg_pool[256]; rt_err_t result; result = rt_mq_init(&pms_mq, "pms_mq", msg_pool, sizeof(struct rx_msg), sizeof(msg_pool), RT_IPC_FLAG_FIFO); if (result != RT_EOK) { rt_kprintf("init message queue failed.\n"); } result = rt_device_open(dev->serial, RT_DEVICE_FLAG_DMA_RX); if (result != RT_EOK) { rt_kprintf("open device failed.\n"); } result = rt_device_set_rx_indicate(dev->serial, uart_input); if (result != RT_EOK) { rt_kprintf("set rx indicate failed.\n"); } #endif rt_thread_t thread = rt_thread_create("pms1003", serial_thread_entry, dev, 1024, 3, 10); if (thread != RT_NULL) { rt_thread_startup(thread); } else { ret = RT_ERROR; } return ret; } //INIT_APP_EXPORT(PMS1003Init); char tmp_buff[18]={'\0'}; char pm_buff[16]={'\0'}; char pm10_buff[16]={'\0'}; static int F_clean = 0; static void OledThreadEntry(void *parameter) { u8g2_t u8g2; u8g2_Setup_ssd1306_i2c_128x64_noname_f( &u8g2, U8G2_R0, u8x8_byte_rtthread_hw_i2c, u8x8_gpio_and_delay_rtthread); u8g2_InitDisplay(&u8g2); u8g2_SetPowerSave(&u8g2, 0);//是否开启省电模式 , 1 表示启用显示器的省电模式,屏幕上看不到任何东西, 0 表示禁用省电模式 u8g2_ClearBuffer(&u8g2); u8g2_SetFont(&u8g2, u8g2_font_unifont_t_arabic); //u8g2_font_ncenB08_tr u8g2_font_unifont_t_symbols while (1) { sprintf(tmp_buff, "Temp:%d\t Humi:%d\t", temp, humi); sprintf(pm_buff, "PM2.5:%d", PM2_5); sprintf(pm10_buff, "PM10:%d", PM10); rt_thread_mdelay(300); if (1 == F_clean) { u8g2_ClearBuffer(&u8g2); } else if (50 == F_clean) { u8g2_ClearBuffer(&u8g2); F_clean = 0; } u8g2_DrawStr(&u8g2, 1, 10, &tmp_buff); u8g2_SendBuffer(&u8g2); u8g2_DrawStr(&u8g2, 1, 30, &pm_buff); u8g2_SendBuffer(&u8g2); u8g2_DrawStr(&u8g2, 1, 50, &pm10_buff); u8g2_SendBuffer(&u8g2); rt_kprintf("F_clean:%d \n",F_clean++); } } int OLED_Init() { rt_err_t ret = RT_EOK; tid_oled = rt_thread_create("oled", OledThreadEntry, RT_NULL, 1024, 2, THREAD_TIMESLICE); if (tid_oled != RT_NULL) { rt_thread_startup(tid_oled); } else { ret = RT_ERROR; } return ret; } //INIT_APP_EXPORT(OLED_Init); void hal_entry(void) { rt_kprintf("\nHello RT-Thread!\n"); rt_uint32_t led1_pin = rt_pin_get(LED1_PIN); dht11_init(); PMS1003Init(); OLED_Init(); while (1) { rt_pin_write(led1_pin, PIN_HIGH); rt_thread_mdelay(500); rt_pin_write(led1_pin, PIN_LOW); rt_thread_mdelay(500); } } void irq_callback_test(void *args) { rt_kprintf("\n IRQ03 triggered \n"); } void icu_sample(void) { /* init */ rt_uint32_t pin = rt_pin_get(USER_INPUT); rt_kprintf("\n pin number : 0x%04X \n", pin); rt_err_t err = rt_pin_attach_irq(pin, PIN_IRQ_MODE_RISING, irq_callback_test, RT_NULL); if (RT_EOK != err) { rt_kprintf("\n attach irq failed. \n"); } err = rt_pin_irq_enable(pin, PIN_IRQ_ENABLE); if (RT_EOK != err) { rt_kprintf("\n enable irq failed. \n"); } } MSH_CMD_EXPORT(icu_sample, icu sample); ``` dht11.c ```c /* * Copyright (c) 2006-2021, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2023-03-08 DYC the first version */ #include "dht11.h" #include
#include "hal_data.h" #include
#define DBG_TAG "sensor.asair.dhtxx" #ifdef PKG_USING_DHTXX_DEBUG #define DBG_LVL DBG_LOG #else #define DBG_LVL DBG_ERROR #endif #include
/* timing */ #define DHT1x_BEGIN_TIME 20 /* ms */ #define DHT2x_BEGIN_TIME 1 /* ms */ #define DHTxx_PULL_TIME 30 /* us */ #define DHTxx_REPLY_TIME 100 /* us */ #define MEASURE_TIME 40 /* us */ RT_WEAK void rt_hw_us_delay(rt_uint32_t us) { rt_uint32_t delta; us = us * (SysTick->LOAD / (1000000 / RT_TICK_PER_SECOND)); delta = SysTick->VAL; while (delta - SysTick->VAL < us) continue; } /** * This function will split a number into two part according to times. * * @param num the number will be split * @param integer the integer part * @param decimal the decimal part * @param times how many times of the real number (you should use 10 in this case) * * @return 0 if num is positive, 1 if num is negative */ int split_int(const int num, int *integer, int *decimal, const rt_uint32_t times) { int flag = 0; if (num < 0) flag = 1; int anum = num<0 ? -num : num; *integer = anum / times; *decimal = anum % times; return flag; } /** * This function will convert temperature in degree Celsius to Kelvin. * * @param c the temperature indicated by degree Celsius * * @return the result */ float convert_c2k(float c) { return c + 273.15; } /** * This function will convert temperature in degree Celsius to Fahrenheit. * * @param c the temperature indicated by degree Celsius * * @return the result */ float convert_c2f(float c) { return c * 1.8 + 32; } /** * This function will convert temperature in degree Fahrenheit to Celsius. * * @param f the temperature indicated by degree Fahrenheit * * @return the result */ float convert_f2c(float f) { return (f - 32) * 0.55555; } /** * This function will read a bit from sensor. * * @param pin the pin of Dout * * @return the bit value */ static uint8_t dht_read_bit(const rt_base_t pin) { uint8_t retry = 0; while(rt_pin_read(pin) && retry < DHTxx_REPLY_TIME) { retry++; rt_hw_us_delay(1); } retry = 0; while(!rt_pin_read(pin) && retry < DHTxx_REPLY_TIME) { retry++; rt_hw_us_delay(1); } rt_hw_us_delay(MEASURE_TIME); return rt_pin_read(pin); } /** * This function will read a byte from sensor. * * @param pin the pin of Dout * * @return the byte */ static uint8_t dht_read_byte(const rt_base_t pin) { uint8_t i, byte = 0; for(i=0; i<8; i++) { byte <<= 1; byte |= dht_read_bit(pin); } return byte; } /** * This function will read and update data array. * * @param dev the device to be operated * * @return RT_TRUE if read successfully, otherwise return RT_FALSE. */ rt_bool_t dht_read(dht_device_t dev) { RT_ASSERT(dev); uint8_t i, retry = 0, sum = 0; #ifdef PKG_USING_DHTXX_INTERRUPT_DISABLE rt_base_t level; #endif /* Reset data buffer */ rt_memset(dev->data, 0, DHT_DATA_SIZE); /* MCU request sampling */ rt_pin_mode(dev->pin, PIN_MODE_OUTPUT); rt_pin_write(dev->pin, PIN_LOW); if (dev->type == DHT11) { rt_thread_mdelay(DHT1x_BEGIN_TIME); /* Tbe */ } else { rt_thread_mdelay(DHT2x_BEGIN_TIME); } #ifdef PKG_USING_DHTXX_INTERRUPT_DISABLE level = rt_hw_interrupt_disable(); #endif rt_pin_mode(dev->pin, PIN_MODE_INPUT_PULLUP); rt_hw_us_delay(DHTxx_PULL_TIME); /* Tgo */ /* Waiting for sensor reply */ while (rt_pin_read(dev->pin) && retry < DHTxx_REPLY_TIME) { retry++; rt_hw_us_delay(1); /* Trel */ } if(retry >= DHTxx_REPLY_TIME) return RT_FALSE; retry = 0; while (!rt_pin_read(dev->pin) && retry < DHTxx_REPLY_TIME) { retry++; rt_hw_us_delay(1); /* Treh */ }; if(retry >= DHTxx_REPLY_TIME) return RT_FALSE; /* Read data */ for(i=0; i
data[i] = dht_read_byte(dev->pin); } #ifdef PKG_USING_DHTXX_INTERRUPT_DISABLE rt_hw_interrupt_enable(level); #endif /* Checksum */ for(i=0; i
data[i]; } if(sum != dev->data[4]) return RT_FALSE; return RT_TRUE; } /** * This function will get the humidity from dhtxx sensor. * * @param dev the device to be operated * * @return the humidity value */ rt_int32_t dht_get_humidity(dht_device_t const dev) { RT_ASSERT(dev); rt_int32_t humi = 0; switch(dev->type) { case DHT11: humi = dev->data[0] * 10 + dev->data[1]; break; default: break; } return humi; } /** * This function will get the temperature from dhtxx sensor. * * @param dev the device to be operated * * @return the temperature value */ rt_int32_t dht_get_temperature(dht_device_t const dev) { RT_ASSERT(dev); rt_int32_t temp = 0; switch(dev->type) { case DHT11: temp = dev->data[2] * 10 + (dev->data[3] & 0x7f); if(dev->data[3] & 0x80) { temp = -temp; } break; default: break; } return temp; } /** * This function will init dhtxx sensor device. * * @param dev the device to init * @param pin the pin of Dout * * @return the device handler */ rt_err_t dht_init(struct dht_device *dev, const rt_base_t pin) { if(dev == NULL) return -RT_ERROR; dev->type = DHT_TYPE; dev->pin = pin; rt_memset(dev->data, 0, DHT_DATA_SIZE); rt_pin_mode(dev->pin, PIN_MODE_INPUT_PULLUP); return RT_EOK; } // 1、初始化类型 dht_device_t dht_create(const rt_base_t pin) { dht_device_t dev; dev = rt_calloc(1, sizeof(struct dht_device)); if (dev == RT_NULL) { LOG_E("Can't allocate memory for dhtxx device"); return RT_NULL; } dev->type = DHT_TYPE; dev->pin = pin; rt_memset(dev->data, 0, DHT_DATA_SIZE); rt_pin_mode(dev->pin, PIN_MODE_INPUT_PULLUP); return dev; } void dht_delete(dht_device_t dev) { if (dev) rt_free(dev); } ``` dht11.h ```c /* * Copyright (c) 2006-2021, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2023-03-08 DYC the first version */ #ifndef SRC_DHT11_H_ #define SRC_DHT11_H_ #include
#include
#include
#include
#include
#define DHTLIB_VERSION "0.9.0" #define DHT_DATA_SIZE 5 /* sensor model type */ #define DHT11 0 #define DHT_TYPE DHT11 struct dht_device { rt_base_t pin; rt_uint8_t type; rt_uint8_t data[DHT_DATA_SIZE]; rt_mutex_t lock; }; typedef struct dht_device *dht_device_t; dht_device_t dht_create(const rt_base_t pin); void dht_delete(dht_device_t dev); rt_err_t dht_init(struct dht_device *dev, const rt_base_t pin); rt_bool_t dht_read(dht_device_t dev); rt_int32_t dht_get_humidity(dht_device_t dev); rt_int32_t dht_get_temperature(dht_device_t dev); float convert_c2k(float c);//将摄氏温度转为开氏温度 float convert_c2f(float c);//将摄氏温度转为华氏温度 float convert_f2c(float f);//将华氏温度转为摄氏温度 rt_int32_t split_int(const rt_int32_t num, rt_int32_t *integer, rt_int32_t *decimal, const rt_uint32_t times); rt_err_t rt_hw_dht_init(const char *name, struct rt_sensor_config *cfg); #endif /* SRC_DHT11_H_ */ ``` pms1003.c ```c /* * Copyright (c) 2006-2021, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2023-03-08 DYC the first version */ //#define DBG_SECTION_NAME "pms_series" //#define DBG_LEVEL DBG_LOG //#define DBG_COLOR #include
#include
#include "pms1003.h" #define RT_SERIAL_RB_BUFSZ 64 #define COMM_START1 0x42 #define COMM_START2 0x4D #define FRAME_HEAD1 0x00 #define FRAME_HEAD2 0x01 #define FRAME_LENH 0x02 #define FRAME_LENL 0x03 #define FRAME_RECEIVE 0x04 #define FRAME_CHECK 0x05 rt_err_t frame_check(pms_device_t dev,rt_uint8_t *buf,rt_uint16_t len) { rt_uint16_t sum=0; RT_ASSERT(dev); for(uint8_t i=0;i<(len-2);i++) { sum += buf[i]; } if((buf[len-1] == (sum&0xFF)) && (buf[len-2] == (sum >> 8))) { dev->PM1_0_CF1 = ((rt_uint16_t)(buf[4])<<8) | buf[5]; dev->PM2_5_CF1 = ((rt_uint16_t)(buf[6])<<8) | buf[7]; dev->PM10_0_CF1 = ((rt_uint16_t)(buf[8])<<8) | buf[9]; dev->PM1_0_amb = ((rt_uint16_t)(buf[10])<<8) | buf[11]; dev->PM2_5_amb = ((rt_uint16_t)(buf[12])<<8) | buf[13]; dev->PM10_0_amb = ((rt_uint16_t)(buf[14])<<8) | buf[15]; dev->air_0_3um = ((rt_uint16_t)(buf[16])<<8) | buf[17]; dev->air_0_5um = ((rt_uint16_t)(buf[18])<<8) | buf[19]; dev->air_1_0um = ((rt_uint16_t)(buf[20])<<8) | buf[21]; dev->air_2_5um = ((rt_uint16_t)(buf[22])<<8) | buf[23]; dev->version = buf[len - 4]; dev->errorCode = buf[len - 3]; return RT_EOK; } return RT_ERROR; } rt_err_t pms_get_byte(pms_device_t dev, char data) { rt_err_t result; static uint8_t state = FRAME_HEAD1; static uint8_t cnt = 0; static rt_uint8_t buf[40] = {0}; RT_ASSERT(dev); if(state == FRAME_HEAD1 && data == COMM_START1) { buf[cnt++] = data; state = FRAME_HEAD2; } else if (state == FRAME_HEAD2 && data == COMM_START2) { buf[cnt++] = data; state = FRAME_LENH; } else if (state == FRAME_LENH) { buf[cnt++] = data; state = FRAME_LENL; } else if (state == FRAME_LENL) { buf[cnt++] = data; state = FRAME_RECEIVE; } else if (state == FRAME_RECEIVE) { buf[cnt++] = data; if(cnt >= COMM_LEN - 1) state = FRAME_CHECK; } else if (state == FRAME_CHECK) { buf[cnt++] = data; state = FRAME_HEAD1; cnt = 0; result = frame_check(dev, buf, COMM_LEN); if (result == RT_EOK) { LOG_D("check success"); return result; } else { LOG_E("check error"); } } else {} return result; } pms_device_t pms_init(const char *uart_name) { pms_device_t dev; RT_ASSERT(uart_name); dev = rt_calloc(1, sizeof(struct pms_device)); if (dev == RT_NULL) { LOG_E("Can't allocate memory for pms device %s",uart_name); return RT_NULL; } dev->serial = rt_device_find(uart_name); if (!dev->serial) { rt_free(dev); rt_kprintf("find %s failed!\n", uart_name); } else { dev->config.baud_rate = BAUD_RATE_9600; dev->config.data_bits = DATA_BITS_8; dev->config.stop_bits = STOP_BITS_1; dev->config.parity = PARITY_NONE; dev->config.bit_order = BIT_ORDER_LSB; dev->config.invert = NRZ_NORMAL; dev->config.rx_bufsz = RT_SERIAL_RB_BUFSZ; dev->config.reserved = 0; rt_device_control(dev->serial, RT_DEVICE_CTRL_CONFIG, &dev->config); } return dev; } void pms_deinit(pms_device_t dev) { RT_ASSERT(dev); rt_free(dev); } ``` pms1003.h ```c /* * Copyright (c) 2006-2021, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2023-03-08 DYC the first version */ #ifndef SRC_PMS1003_H_ #define SRC_PMS1003_H_ #define DBG_TAG "pms_series" #define DBG_LVL DBG_INFO #include
#include
#include
#define COMM_LEN 32 struct pms_device { rt_device_t serial; struct serial_configure config; rt_uint16_t len; rt_uint16_t PM1_0_CF1; rt_uint16_t PM2_5_CF1; rt_uint16_t PM10_0_CF1; rt_uint16_t PM1_0_amb; rt_uint16_t PM2_5_amb; rt_uint16_t PM10_0_amb; rt_uint16_t air_0_3um; rt_uint16_t air_0_5um; rt_uint16_t air_1_0um; rt_uint16_t air_2_5um; rt_uint16_t air_5_0um; rt_uint16_t air_10_0um; rt_uint8_t version; rt_uint8_t errorCode; rt_uint16_t checksum; }; typedef struct pms_device *pms_device_t; pms_device_t pms_init(const char *uart_name); rt_err_t frame_check(pms_device_t dev,rt_uint8_t *buf,rt_uint16_t len); rt_err_t pms_get_byte(pms_device_t dev, char data); void pms_deinit(pms_device_t dev); #endif /* SRC_PMS1003_H_ */ ``` # 五、烧录验证与扩展 基本功能做完了,由于后续买的co2, 甲醛, IAQ模块还在路上,后续到了会继续往该系统中添加,还要与ESP8266 模块通信,完成本地系统数据远程访问,通过blinker实现数据的可视化,随时随地查看室内空气质量。 附上项目工程源码:链接:https://pan.baidu.com/s/1DRrXN8fqZzlDzhmwGR7lfQ 提取码:m651 ![aa.jpg](https://oss-club.rt-thread.org/uploads/20230312/dd34930b09036fde55f1dba81d843422.jpg.webp) ![bb.jpg](https://oss-club.rt-thread.org/uploads/20230312/0278212730a7f76629f7f2c3e73c2f80.jpg.webp) ![cc.jpg](https://oss-club.rt-thread.org/uploads/20230312/d092f05f2e87e8583b2f2e4ae86de2a9.jpg.webp)
0
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
快乐小鸟
这家伙很懒,什么也没写!
文章
5
回答
0
被采纳
0
关注TA
发私信
相关文章
1
有关动态模块加载的一篇论文
2
最近的调程序总结
3
晕掉了,这么久都不见layer2的踪影啊
4
继续K9ii的历程
5
[GUI相关] FreeType 2
6
[GUI相关]嵌入式系统中文输入法的设计
7
20081101 RT-Thread开发者聚会总结
8
嵌入式系统基础
9
linux2.4.19在at91rm9200 上的寄存器设置
10
[转]基于嵌入式Linux的通用触摸屏校准程序
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
I2C_IIC
ESP8266
UART
WIZnet_W5500
ota在线升级
PWM
cubemx
flash
freemodbus
BSP
packages_软件包
潘多拉开发板_Pandora
定时器
ADC
flashDB
GD32
socket
编译报错
中断
Debug
rt_mq_消息队列_msg_queue
SFUD
msh
keil_MDK
ulog
C++_cpp
MicroPython
本月问答贡献
xusiwei1236
5
个答案
2
次被采纳
踩姑娘的小蘑菇
1
个答案
2
次被采纳
用户名由3_15位
7
个答案
1
次被采纳
bernard
4
个答案
1
次被采纳
张世争
1
个答案
1
次被采纳
本月文章贡献
聚散无由
2
篇文章
15
次点赞
catcatbing
2
篇文章
5
次点赞
Wade
2
篇文章
2
次点赞
Ghost_Girls
1
篇文章
6
次点赞
YZRD
1
篇文章
2
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部