一、項目名稱:
基于Teensy4.1的車內(nèi)環(huán)境質(zhì)量監(jiān)控器
二、項目概述:
本項目旨在開發(fā)一款智能車內(nèi)環(huán)境質(zhì)量監(jiān)控器,基于高性能的?Teensy 4.1微控制器?,結(jié)合?瑞薩 RRH62000多合一環(huán)境傳感器?,實時監(jiān)測車內(nèi)的?溫濕度?、?顆粒物濃度(PM1/PM2.5/PM10)?、?eCO2(等效二氧化碳濃度)?、TVOC(總揮發(fā)性有機化合物)以及空氣質(zhì)量指數(shù)(AQI)等關(guān)鍵環(huán)境參數(shù)。所有數(shù)據(jù)通過3.5寸LCD觸摸屏顯示,界面基于LVGL圖形庫設(shè)計,提供直觀、美觀的用戶交互體驗。
本項目不僅是一款實用的車內(nèi)環(huán)境監(jiān)控設(shè)備,更是一個可擴展的智能平臺,未來可通過軟硬件升級,滿足更多場景需求。通過實時監(jiān)測和智能提示,幫助用戶打造更健康、更舒適的車內(nèi)環(huán)境。
核心功能
?多參數(shù)環(huán)境監(jiān)測?:
實時采集車內(nèi)溫濕度、顆粒物濃度、eCO2、TVOC及空氣質(zhì)量指數(shù)。
通過RRH62000傳感器的高精度檢測,確保數(shù)據(jù)的準確性和可靠性。
?直觀的GUI界面?:
基于LVGL設(shè)計的圖形用戶界面,支持觸摸操作。
主界面顯示所有參數(shù)的實時數(shù)值,輔以圖標、顏色和動態(tài)效果,提升用戶體驗。
?報警與提示功能?:
當(dāng)某項環(huán)境參數(shù)超出預(yù)設(shè)安全范圍時,系統(tǒng)會通過屏幕信息警告、LED指示燈發(fā)出提示。
?數(shù)據(jù)存儲與導(dǎo)出?:
LCD屏模塊板載TF卡座,可將環(huán)境數(shù)據(jù)存儲至TF卡,便于**分析與導(dǎo)出。
三、作品實物圖
硬件設(shè)計
?主控芯片?:Teensy 4.1
板載NXP的高性能ARM Cortex-M7處理器RT1062,主頻高達600MHz,滿足多任務(wù)處理需求。
豐富的外設(shè)接口(I2C、SPI、UART等),便于連接傳感器和顯示屏。
?環(huán)境傳感器?:瑞薩 RRH62000
集成溫濕度、顆粒物、eCO2、TVOC等多種檢測功能,減少硬件復(fù)雜度。
?顯示模塊?:DFROBOT 的3.5寸LCD觸摸屏
分辨率320x480,支持觸控操作。
使用LVGL庫實現(xiàn)流暢的圖形界面和交互邏輯。
?擴展功能模塊?:
根據(jù)環(huán)境數(shù)據(jù),可主動或自動調(diào)節(jié)車內(nèi)空調(diào)或空氣凈化器。
可控制車內(nèi)燈光。
軟件設(shè)計
1.LVGL圖形界面?:
-設(shè)計簡潔美觀的主界面,實時顯示各項環(huán)境參數(shù)。
-支持多級菜單,用戶可查看歷史數(shù)據(jù)、設(shè)置報警閾值等。
2.?數(shù)據(jù)采集與處理?:
-定時從RRH62000傳感器讀取數(shù)據(jù),并進行濾波和校準。
-通過算法計算空氣質(zhì)量指數(shù)(AQI),提供更直觀的環(huán)境評估。
3.?擴展控制?:
-實時監(jiān)測環(huán)境參數(shù),根據(jù)環(huán)境數(shù)據(jù),可主動調(diào)節(jié)車內(nèi)空調(diào)或空氣凈化器。
-支持用戶控制車內(nèi)照明燈光。
項目亮點
?1.高集成度?:
-采用多合一環(huán)境傳感器,減少硬件復(fù)雜度,降低成本。
-Teensy 4.1強大的處理能力支持多任務(wù)并行處理。
?2.用戶友好?:
-基于LVGL的圖形界面,操作直觀,支持觸摸交互。
-提供實時數(shù)據(jù)和報警提示,滿足用戶多樣化需求。
3.?可擴展性強?:
-支持自動控制等擴展功能。
-模塊化設(shè)計,便于**功能升級和維護。
4.?實用性與環(huán)保?:
-幫助用戶實時了解車內(nèi)環(huán)境質(zhì)量,提升駕駛舒適性和健康保障。
-通過數(shù)據(jù)分析和提示,促進用戶改善車內(nèi)環(huán)境,減少污染。
本項目基于arduino開發(fā)。部分軟件代碼如下:
#include <TimerOne.h>
#include <ILI9488_t3.h>
#include <lvgl.h>
#include "src/gui_guider.h"
#include "src/events_init.h"
#include "src/custom.h"
#include "RRH62000.h"
RRH62000 rrh=RRH62000(&Wire2);
#define SCREEN_WIDTH 480
#define SCREEN_HEIGHT 320
ILI9488_t3 tft = ILI9488_t3(&SPI, 10, 40, 41);
static lv_disp_draw_buf_t disp_buf;
static lv_color_t buff[SCREEN_WIDTH * 10];
static void my_disp_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p)
{
uint32_t w = (area->x2 - area->x1 + 1);
uint32_t h = (area->y2 - area->y1 + 1);
tft.writeRect(area->x1,area->y1,w,h,(const unsigned uint16_t*)&color_p->full);
lv_disp_flush_ready(disp);
}
void timer_callback(void)
{
lv_tick_inc(5);
}
extern "C"
{
float RRH62000_getTemperature()
{
float t = rrh.getTemperature();
Serial.println(String(t));
return t;
}
float RRH62000_getHumidity()
{
float rh =rrh.getHumidity();
Serial.println(String(rh));
return rh;
}
float RRH62000_getPM1()
{
float dat =rrh.getPM1();
Serial.println(String(dat));
return dat;
}
float RRH62000_getPM2_5()
{
float dat =rrh.getPM2_5();
Serial.println(String(dat));
return dat;
}
float RRH62000_getPM10()
{
float dat =rrh.getPM10();
Serial.println(String(dat));
return dat;
}
float RRH62000_getPM1_smoke()
{
float dat =rrh.getPM1_smoke();
Serial.println(String(dat));
return dat;
}
float RRH62000_getPM2_5_smoke()
{
float dat =rrh.getPM2_5_smoke();
Serial.println(String(dat));
return dat;
}
float RRH62000_getPM10_smoke()
{
float dat =rrh.getPM10_smoke();
Serial.println(String(dat));
return dat;
}
float RRH62000_getIAQ()
{
float dat =rrh.getIAQ();
Serial.println(String(dat));
return dat;
}
float RRH62000_getTVOC()
{
float dat =rrh.getTVOC();
Serial.println(String(dat));
return dat;
}
float RRH62000_getECO2()
{
float dat =rrh.getECO2();
Serial.println(String(dat));
return dat;
}
}
lv_ui guider_ui;
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
tft.begin();
tft.setRotation(1); // 180
rrh.begin(); // Start RRH62000
lv_init();
lv_disp_draw_buf_init(&disp_buf, buff, NULL, SCREEN_WIDTH * 10);
/*Initialize the display*/
static lv_disp_drv_t disp_drv; /*Descriptor of a display driver*/
lv_disp_drv_init(&disp_drv); /*Basic initialization*/
/*Set the resolution of the display*/
disp_drv.hor_res = SCREEN_WIDTH;
disp_drv.ver_res = SCREEN_HEIGHT;
/*Used to copy the buffer's content to the display*/
disp_drv.flush_cb = my_disp_flush;
/*Set a display buffer*/
disp_drv.draw_buf = &disp_buf;
/*Finally register the driver*/
lv_disp_drv_register(&disp_drv);
static lv_indev_drv_t indev_drv;
/*Register a touchpad input device*/
lv_indev_drv_init(&indev_drv);
indev_drv.type = LV_INDEV_TYPE_POINTER;
indev_drv.read_cb = my_touchpad_read;
lv_indev_drv_register(&indev_drv);
setup_ui(&guider_ui);
events_init(&guider_ui);
custom_init(&guider_ui);
Timer1.initialize(5000);
Timer1.attachInterrupt(timer_callback); // blinkLED to run every 0.15 seconds
}
void loop() {
// put your main code here, to run repeatedly:
rrh.refreshData(); // collect new data from RRH62000
lv_task_handler(); /* let the GUI do its work */
delay(5);
}
視頻與資料:
參見附件