国产精品久久久aaaa,日日干夜夜操天天插,亚洲乱熟女香蕉一区二区三区少妇,99精品国产高清一区二区三区,国产成人精品一区二区色戒,久久久国产精品成人免费,亚洲精品毛片久久久久,99久久婷婷国产综合精品电影,国产一区二区三区任你鲁

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

基于RT-Thread和兆易創新GD32F527系列MCU的健康監測站 | 技術集結

RT-Thread官方賬號 ? 2026-01-20 17:37 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

本項目為RT-Thread嵌入式大賽獲獎作品,基于RT-Thread和兆易創新GD32F527I-EVAL的健康監測站。

目錄


項目概述


系統硬件框架結構


基礎驅動程序實現


整體驅動實現


工程效果


演示視頻及代碼


演示視頻鏈接:https://www.bilibili.com/video/BV1WgUoBXE2n/?pop_share=1&vd_source=e1bd226340c8b87027d5dcfc6b0c3344

1 項目概述

1.1 項目背景

血氧、心率監測是人們最常關心的,特別是一些特殊的群體比如老人,患有心血管系統、呼吸系統疾病的人。能方便及時的監測到心率與血氧。本項目主要利用了開發板的大內存、大屏幕,移植LVGL,能夠讓老年人也看得清楚。

1.2 系統功能介紹

基于GD32F527I-EVAL開發板實現如下功能:

使用管方的RTTherad庫,管理整個系統資源。

移植LCD驅動,給LVGL提供顯示基礎

移植觸摸驅動,給LVGL提供用戶輸入基礎

移植USART5,實現與傳感器的交互接口

移植LVGL,設計GUI界面

實現傳感器驅動,實現血氧、心率的監測。

1.3 系統使用的技術要點

整個系統由國產開源操作系統RT-Thead實現驅動的模塊化設計,以及系統調度。

硬件:GD32F527I-EVAL

開發板語言:C、GuiGuider

2 系統硬件框架結構

a40536cc-f5e3-11f0-8ce9-92fbcf53809c.png

2.1 TFT—LCD接口

開發板板載了LCD屏,其原理圖如下:

a41d7ff2-f5e3-11f0-8ce9-92fbcf53809c.png

2.2 SDRAM接口

由于開發板上外擴了RAM,給LVGL驅動提供了大內存空間,原理圖如下:

a42b9312-f5e3-11f0-8ce9-92fbcf53809c.png

2.3 USART5接口

由于開發板的外設非常多,找到攝像頭接口的PC6、PC7作為USART5的接口:

a4499ff6-f5e3-11f0-8ce9-92fbcf53809c.png

3 基礎驅動程序實現

3.1 基礎工程

3.1.1 下載RT-Thread源碼

https://gitee.com/rtthread/rt-thread

下載源碼到本地。

3.1.2 同步并打包

下載好源碼后,進入rt-thread/tree/master/bsp/gd32/arm/gd32527I-eval目錄下面執行pkgs —upgrade-force同步

然后進行pkgs —update

執行scons —target=mdk5

然后進行scons —dist打包單獨的工程。

復制打包好的工程到單獨的目錄下。

現在單獨的工程就創建好了。

3.2 移植LVGL

創建好工程后,首先就需要生成用戶交互界面。我在論壇有單獨的作品:

https://club.rt-thread.org/ask/article/a2dba0eaa063757a.html

3.3 移植觸摸驅動

LVGL需要驅動觸摸屏,我也有單獨的作品:

https://club.rt-thread.org/ask/article/104ea5e6b33e788e.html

3.4 移植mks傳感器串口接口

詳見單獨作品:

https://club.rt-thread.org/ask/article/1074357ba9757cdb.html

4 整體驅動實現

通過上的基工程的實現,接下來就是整合驅動,實整個工程。

4.1 界面設計

4.1.1 GuiGuide設計

我使用開源的GuiGuider設了用戶交互界面:

a456c10e-f5e3-11f0-8ce9-92fbcf53809c.png

控件1:btn_start,實現開始、停止測量的復用功能

控件2:label_heart 用于顯示測量到的心率值

控件3:label_spo2 用于顯示測量到的心率值

控件4:bar 用于顯示測量的進度條

其余控件為固定標簽

4.1.2 事件添加

為btn_start 添加clicked事件

a46c1f2c-f5e3-11f0-8ce9-92fbcf53809c.png

最后生成C語言的工程。

4.2 LVGL工程移植

4.2.1 復制guiguider工程

在生成工程的目錄中,我復制generated文件夾到基礎工程下的LVGL目錄下面,替換掉原來的generated文件夾。

4.2.2 添加文件到工程

在mdk中,將generated下面的所有.c/h添加到mdk工程中:

a476daca-f5e3-11f0-8ce9-92fbcf53809c.png

4.2.3 添加bnt事件代碼

根據傳感器的手冊,我們開始測量時,是向串口發送數據0x8A,停止是向串口發送0x88。

添加按鍵的的驅動代碼如下:

externlv_ui guider_ui;externintmks_cmd(intargc,char*argv[]);// 全局/靜態變量:控制進度條和定時器(確保回調中可訪問)staticlv_timer_t*progress_timer =NULL; // 進度條定時器staticint current_progress =0; // 當前進度值(0-100)// 進度條定時器回調函數(每隔 200ms 觸發一次)staticvoidprogress_timer_cb(lv_timer_t*timer){ current_progress++; // 每次進度 +1%(200ms × 100 = 20 秒) // 更新進度條值(關閉動畫,避免和定時器沖突) lv_bar_set_value(guider_ui.screen_bar, current_progress, LV_ANIM_OFF); // 進度達到 100%,停止定時器并重置狀態 if(current_progress >=100) { lv_timer_del(progress_timer); // 刪除定時器(釋放資源) progress_timer =NULL; // 重置定時器指針 current_progress =0; // 重置進度值 char*argv[] = {"mks_cmd","stop",NULL}; intargc =2; mks_cmd(argc, argv); // 可選:進度完成后,自動將按鈕切回「開始」 lv_label_set_text(guider_ui.screen_btn_start_label,"Start"); lv_bar_set_value(guider_ui.screen_bar,0, LV_ANIM_OFF); }}staticvoidscreen_btn_start_event_handler(lv_event_t*e){ lv_event_code_tcode =lv_event_get_code(e); switch(code) { caseLV_EVENT_CLICKED: { constchar *btn_text =lv_label_get_text(guider_ui.screen_btn_start_label);; if(btn_text !=NULL&&strcmp(btn_text,"Start") ==0) { rt_kprintf("start test\n"); // 停止已存在的定時器(避免重復啟動,防止進度加速) if(progress_timer !=NULL) { lv_timer_del(progress_timer); progress_timer =NULL; } // 初始化進度狀態 current_progress =0; lv_bar_set_range(guider_ui.screen_bar,0,100); // 設置進度條范圍:0-100(百分比) lv_bar_set_value(guider_ui.screen_bar,0, LV_ANIM_OFF); // 進度條歸零 // 創建并啟動定時器:周期 200ms,觸發回調函數 progress_timer =lv_timer_create(progress_timer_cb,200,NULL); lv_timer_resume(progress_timer); // 啟動定時器(LVGL 定時器默認創建后啟動,保險起見手動調用) // 構造參數并調用 char*argv[] = {"mks_cmd","start",NULL}; intargc =2; mks_cmd(argc, argv); lv_label_set_text(guider_ui.screen_btn_start_label,"Stop"); } elseif(btn_text !=NULL&&strcmp(btn_text,"Stop") ==0) { // 停止并刪除定時器 if(progress_timer !=NULL) { lv_timer_del(progress_timer); progress_timer =NULL; } // 進度條歸零,狀態重置 current_progress =0; lv_bar_set_value(guider_ui.screen_bar,0, LV_ANIM_OFF); char*argv[] = {"mks_cmd","stop",NULL}; intargc =2; mks_cmd(argc, argv); lv_label_set_text(guider_ui.screen_btn_start_label,"Start"); lv_obj_center(guider_ui.screen_btn_start_label); } break; } default: break; }}

4.2.4 添加初始化gui代碼

在main.c中添加用于lvgl 心跳包的任務,與初始化lvgl的代碼:

#defineLED1_PIN GET_PIN(E, 3)#defineLVGL_TASK_PERIOD 10 // ms#defineLVGL_TICK_PERIOD 5 // mslv_ui guider_ui;staticrt_thread_tlvgl_task_thread = RT_NULL;staticrt_thread_tlvgl_tick_thread = RT_NULL;staticvoidlvgl_tick_thread_entry(void*parameter){ while(1) { lv_tick_inc(5); rt_thread_delay(5); }}staticvoidlvgl_task_thread_entry(void*parameter){ lv_init(); lcd_init(); lv_port_disp_init(); lv_port_indev_init(); setup_ui(&guider_ui); setup_ui(&guider_ui); events_init(&guider_ui); while(1) { lv_task_handler(); rt_thread_delay(10); }}intmain(void){ /* set LED1 pin mode to output */ rt_pin_mode(LED1_PIN, PIN_MODE_OUTPUT); exmc_synchronous_dynamic_ram_init(EXMC_SDRAM_DEVICE0); //在這里啟用兩個任務 lvgl_task_thread =rt_thread_create("lvgl_task", lvgl_task_thread_entry, RT_NULL,4096,25,10); if(lvgl_task_thread != RT_NULL) rt_thread_startup(lvgl_task_thread); lvgl_tick_thread =rt_thread_create("lvgl_tick", lvgl_tick_thread_entry, RT_NULL,512,25,10); if(lvgl_tick_thread != RT_NULL) rt_thread_startup(lvgl_tick_thread); while(1) { rt_thread_mdelay(1000);// 主線程可以做其他事情 } returnRT_EOK;}

將程序下載到開發板后,按下按鍵,能在USART5上面看到的0x8A、0x88輸出,說明程序運轉正常。

4.3 mks傳感器驅動

4.3.1 mks傳感器通信協議:

a486f8c4-f5e3-11f0-8ce9-92fbcf53809c.png

根據通信協議進行串口的代碼實現。

4.3.2 mks串口添加:

在menuconfig中,打開usart5,保存工程并重新生成工程。

4.3.3 mks串口驅動實現

在驅動中,按照rtthead srial的標準驅動。

由于mkd傳感器的波特率為38400,因此需要在初始化后,重新配置serial的驅動結構體,并進行配置。

定義他為uart5 實現中斷接收功能,詳見驅動代碼如下:

接收傳感器并實現解碼,并實時將接收到的數據通過LVGL顯示到界面中。

#include"app.h"#include"string.h"#include#include#include#include"lvgl.h"#include"gui_guider.h"#defineMAX_BUFFSIZE 128#defineRECEIVE_LENGTH 88#definePACKET_HEADER 0xFF#defineSAMPLE_UART_NAME "uart5"/* 用于接收消息的信號量 */staticstructrt_semaphorerx_sem;staticrt_device_tserial;// --- 全局變量定義 ---int8_tmks_waveform_data[MKS_WAVEFORM_SAMPLES];uint8_tmks_heart_rate =0;uint8_tmks_spo2 =0;volatileuint8_tmks_new_data_flag =0; // Use volatile as it might be checked in timer/ISR context later// --- 內部接收緩沖區 ---staticuint8_tmks_rx_buffer[MKS_PACKET_SIZE];staticuint8_tmks_bytes_received =0;// lvglexternlv_ui guider_ui;staticchar buf[4];/* 接收數據回調函數 */staticrt_err_tuart_input(rt_device_tdev,rt_size_tsize){ /* 串口接收到數據后產生中斷,調用此回調函數,然后發送接收信號量 */ rt_sem_release(&rx_sem); returnRT_EOK;}/*** 串口接受線程* @param parameter*/staticvoidserial_thread_entry(void*parameter){ charch; mks_bytes_received =0; // Reset buffer state mks_new_data_flag =0; // 初始無新數據 // 初始化數據為0 memset(mks_rx_buffer,0, RECEIVE_LENGTH); mks_heart_rate =0; mks_spo2 =0; while(1) { /* 從串口讀取一個字節的數據,沒有讀取到則等待接收信號量 */ while(rt_device_read(serial,-1, &ch,1) !=1) { /* 阻塞等待接收信號量,等到信號量后再次讀取數據 */ rt_sem_take(&rx_sem, RT_WAITING_FOREVER); } if(ch == PACKET_HEADER) { mks_bytes_received =1; mks_new_data_flag =0; mks_rx_buffer[0] = (uint8_t)ch; } else { if(mks_bytes_received>0) { //mks_bytes_received++; mks_rx_buffer[mks_bytes_received++] = (uint8_t)ch; if(mks_bytes_received >= RECEIVE_LENGTH) { mks_new_data_flag =1; mks_bytes_received =0; sprintf(buf, "%d", mks_rx_buffer[65]); lv_label_set_text(guider_ui.screen_label_heart, buf);//更新到LVGL sprintf(buf, "%d", mks_rx_buffer[66]); lv_label_set_text(guider_ui.screen_label_spo2, buf);//更新到LVGL memset(mks_rx_buffer,0, RECEIVE_LENGTH); mks_new_data_flag =0; } } } }}staticintuart_sample(intargc,char*argv[]){ rt_err_tret = RT_EOK; struct serial_configurecfg; // 配置結構體 charuart_name[RT_NAME_MAX]; charstr[] ="hello RT-Thread!\r\n"; if(argc ==2) { rt_strncpy(uart_name, argv[1], RT_NAME_MAX); } else { rt_strncpy(uart_name, SAMPLE_UART_NAME, RT_NAME_MAX); } /* 查找系統中的串口設備 */ serial =rt_device_find(uart_name); if(!serial) { rt_kprintf("find %s failed!\n", uart_name); returnRT_ERROR; } cfg.baud_rate = BAUD_RATE_38400; // 目標波特率(可改為 38400、19200 等) cfg.data_bits = DATA_BITS_8; // 8 數據位 cfg.stop_bits = STOP_BITS_1; // 1 停止位 cfg.parity = PARITY_NONE; // 無校驗 cfg.bit_order = BIT_ORDER_LSB; // 低位優先(默認) cfg.invert = NRZ_NORMAL; cfg.bufsz = RT_SERIAL_RB_BUFSZ; cfg.flowcontrol = RT_SERIAL_FLOWCONTROL_NONE; cfg.reserved =0; rt_device_control(serial, RT_DEVICE_CTRL_CONFIG, &cfg); /* 初始化信號量 */ rt_sem_init(&rx_sem,"rx_sem",0, RT_IPC_FLAG_FIFO); /* 以中斷接收及輪詢發送模式打開串口設備 */ rt_device_open(serial, RT_DEVICE_FLAG_INT_RX); /* 設置接收回調函數 */ rt_device_set_rx_indicate(serial, uart_input); /* 發送字符串 */ rt_device_write(serial,0, str, (sizeof(str) -1)); /* 創建 serial 線程 */ rt_thread_tthread =rt_thread_create("serial", serial_thread_entry, RT_NULL,1024,25,10); /* 創建成功則啟動線程 */ if(thread != RT_NULL) { rt_thread_startup(thread); } else { ret = RT_ERROR; } returnret;}intmks_cmd(intargc,char*argv[]){ rt_err_tret = RT_EOK; uint8_tsend_data =0; // 要發送的字節數據 // 第一步:檢查串口設備是否已初始化(首次使用時查找并打開) if(serial == RT_NULL) { // 查找串口設備 serial =rt_device_find(SAMPLE_UART_NAME); if(serial == RT_NULL) { rt_kprintf("錯誤:未找到串口設備 %s!\n", SAMPLE_UART_NAME); returnRT_ERROR; } // 打開串口(RT_DEVICE_OFLAG_RDWR:讀寫模式) if(rt_device_open(serial, RT_DEVICE_OFLAG_RDWR) != RT_EOK) { rt_kprintf("錯誤:打開串口設備 %s 失敗!\n", SAMPLE_UART_NAME); serial = RT_NULL; // 打開失敗,重置句柄 returnRT_ERROR; } } // 第二步:解析命令參數 if(argc ==2) // 僅支持 "mks start" 或 "mks stop"(2個參數) { // 比較第二個參數(argv[1]) if(strcmp(argv[1],"start") ==0) { send_data =0x8A; // start 對應發送 0x8A rt_kprintf("執行 mks start,發送數據:0x%02X\n", send_data); } elseif(strcmp(argv[1],"stop") ==0) { send_data =0x88; // stop 對應發送 0x88 rt_kprintf("執行 mks stop,發送數據:0x%02X\n", send_data); } else { // 無效參數:提示正確用法 rt_kprintf("錯誤:無效命令參數!\n"); rt_kprintf("正確用法:\n"); rt_kprintf(" mks start - 發送 0x8A\n"); rt_kprintf(" mks stop - 發送 0x88\n"); return-RT_EINVAL; } // 第三步:通過串口發送數據(發送1個字節) ret =rt_device_write(serial,0, &send_data,1); if(ret !=1) // rt_device_write 返回實際發送的字節數,成功應為 1 { rt_kprintf("錯誤:串口發送失敗!返回值:%d\n", ret); return-RT_ERROR; } } else { // 參數個數錯誤:提示正確用法 rt_kprintf("錯誤:命令格式錯誤!\n"); rt_kprintf("正確用法:\n"); rt_kprintf(" mks start - 發送 0x8A\n"); rt_kprintf(" mks stop - 發送 0x88\n"); return-RT_EINVAL; } returnret;}// 3. 導出命令到 FinSH 終端(支持在終端直接輸入 mks 命令)MSH_CMD_EXPORT(mks_cmd, mks command: mks start/stop);/* 導出到 msh 命令列表中 */MSH_CMD_EXPORT(uart_sample, uart device sample);

接收傳感器并實現解碼,并實時將接收到的數據通過LVGL顯示到界面中。

5 工程效果

a48f5c44-f5e3-11f0-8ce9-92fbcf53809c.jpg

6 演示視頻及代碼

演示視頻鏈接:https://www.bilibili.com/video/BV1WgUoBXE2n/?pop_share=1&vd_source=e1bd226340c8b87027d5dcfc6b0c3344

源代碼:https://club.rt-thread.org/file_download/a6fe3781d8bcf12d


聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • mcu
    mcu
    +關注

    關注

    147

    文章

    18924

    瀏覽量

    398072
  • RT-Thread
    +關注

    關注

    32

    文章

    1613

    瀏覽量

    44871
  • 兆易創新
    +關注

    關注

    24

    文章

    713

    瀏覽量

    83700
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關推薦
    熱點推薦

    基于創新GD32F527系列MCU的多媒體門禁系統解決方案

    基于GD32F527系列MCU的多媒體門禁系統,主控GD32F527系列MCU,具備攝像頭采集圖
    的頭像 發表于 10-29 11:37 ?7133次閱讀
    基于<b class='flag-5'>兆</b><b class='flag-5'>易</b><b class='flag-5'>創新</b><b class='flag-5'>GD32F527</b><b class='flag-5'>系列</b><b class='flag-5'>MCU</b>的多媒體門禁系統解決方案

    創新加入RT-Thread高級會員合作伙伴計劃 | 戰略新篇

    全球領先的半導體供應商創新(GigaDevice)正式加入RT-Thread高級會員合作伙伴計劃,標志著雙方在嵌入式領域的合作邁入全新階段。未來,
    的頭像 發表于 07-14 09:04 ?2200次閱讀
    <b class='flag-5'>兆</b><b class='flag-5'>易</b><b class='flag-5'>創新</b>加入<b class='flag-5'>RT-Thread</b>高級會員合作伙伴計劃 | 戰略新篇

    基于RT-Thread創新GD32F527的工業級網絡-CAN透傳網關設計與實現 | 技術集結

    目錄系統概述RT-Thread使用情況硬件框架軟件架構軟件模塊詳解功能展示鏈接地址1系統概述本系統是一個基于GD32F527I_EVAL和RT-Thread實時操作系統開發的工業級網絡-CAN總線透
    的頭像 發表于 02-10 16:05 ?1.6w次閱讀
    基于<b class='flag-5'>RT-Thread</b>與<b class='flag-5'>兆</b><b class='flag-5'>易</b><b class='flag-5'>創新</b><b class='flag-5'>GD32F527</b>的工業級網絡-CAN透傳網關設計與實現 | <b class='flag-5'>技術</b><b class='flag-5'>集結</b>

    RT-Thread移植到GD32F150系列MCU

    RT-Thread移植到GD32F150系列MCU
    發表于 12-07 19:36 ?8次下載
    <b class='flag-5'>RT-Thread</b>移植到<b class='flag-5'>GD32F</b>150<b class='flag-5'>系列</b><b class='flag-5'>MCU</b>

    創新GD32F4xx系列MCU固件庫使用指南

    創新GD32F4xx系列MCU固件庫使用指南GD32F
    發表于 10-19 17:26 ?41次下載

    創新GD32F3x0系列MCU用戶手冊

    創新GD32F3x0系列MCU用戶手冊GD32F
    發表于 10-19 17:26 ?1次下載

    創新GD32F4xx系列MCU用戶手冊

    創新GD32F4xx系列MCU用戶手冊GD32F
    發表于 10-19 17:26 ?26次下載

    創新GD32F10x系列MCU用戶手冊

    創新GD32F10x系列MCU用戶手冊GD32F
    發表于 10-19 17:26 ?1次下載

    創新GD32F20x系列MCU用戶手冊

    創新GD32F20x系列MCU用戶手冊GD32F
    發表于 10-19 17:26 ?1次下載

    創新GD32F30x系列MCU用戶手冊

    創新GD32F30x系列MCU用戶手冊GD32F
    發表于 10-19 17:26 ?7次下載

    GD32F527的設備限制

    電子發燒友網站提供《GD32F527的設備限制.pdf》資料免費下載
    發表于 01-17 15:54 ?1次下載
    <b class='flag-5'>GD32F527</b>的設備限制

    【直播預告】GD32F527高性能MCU全方位解析,與RT-Thread的全棧開發實戰 | 博觀講堂

    10月10日晚20:00,RT-Thread攜手創新專家團隊,帶來GD32F527芯片深度解讀。在工業控制、能源電力等應用領域,工程師面
    的頭像 發表于 10-07 10:03 ?798次閱讀
    【直播預告】<b class='flag-5'>GD32F527</b>高性能<b class='flag-5'>MCU</b>全方位解析,與<b class='flag-5'>RT-Thread</b>的全棧開發實戰 | 博觀講堂

    基于RT-ThreadGD32F527I-EVAL的多媒體門禁系統 | 技術集結

    創新本月正式推出GD32F503/505高性能系列32位通用微控制器,新品將全面支持RT-Threa
    的頭像 發表于 11-25 18:31 ?1092次閱讀
    基于<b class='flag-5'>RT-Thread</b>與<b class='flag-5'>GD32F527</b>I-EVAL的多媒體門禁系統 | <b class='flag-5'>技術</b><b class='flag-5'>集結</b>

    創新RT-Thread MCU技術路演圓滿收官

    近日,創新(GigaDevice)與RT-Thread攜手舉辦的MCU技術路演圓滿收官。本次
    的頭像 發表于 12-01 10:14 ?1475次閱讀

    基于 RT-Thread創新GD32F527的CAN總線監視器 | 技術集結

    【適配新進展】創新RT-Thread的適配大家庭又添新成員啦!GD32VW553現已正式完成適配,并在社區開發者的協作下完成了電子書《
    的頭像 發表于 03-05 10:04 ?33次閱讀
    基于 <b class='flag-5'>RT-Thread</b> 和<b class='flag-5'>兆</b><b class='flag-5'>易</b><b class='flag-5'>創新</b><b class='flag-5'>GD32F527</b>的CAN總線監視器 | <b class='flag-5'>技術</b><b class='flag-5'>集結</b>