www.久久久久|狼友网站av天堂|精品国产无码a片|一级av色欲av|91在线播放视频|亚洲无码主播在线|国产精品草久在线|明星AV网站在线|污污内射久久一区|婷婷综合视频网站

當(dāng)前位置:首頁 > 單片機(jī) > 電子電路開發(fā)學(xué)習(xí)
[導(dǎo)讀]親朋好友,動動小手,一天3票,開發(fā)板誰要? 厚著臉皮插播一條廣告 我在疫情期間做的基于STM32MP1和Qt的新冠肺炎疫情監(jiān)控平臺,這個小項(xiàng)目報(bào)名參加了意法半導(dǎo)體首屆創(chuàng)客大賽——STM32創(chuàng)客秀,最近在投票階段,如果有幸能入圍決賽,ST官方會獎勵開發(fā)板禮包,屆

親朋好友,動動小手,一天3票,開發(fā)板誰要?

厚著臉皮插播一條廣告

我在疫情期間做的基于STM32MP1和Qt的新冠肺炎疫情監(jiān)控平臺,這個小項(xiàng)目報(bào)名參加了意法半導(dǎo)體首屆創(chuàng)客大賽——STM32創(chuàng)客秀,最近在投票階段,如果有幸能入圍決賽,ST官方會獎勵開發(fā)板禮包,屆時我會把開發(fā)板以抽獎的方式回饋給大家


點(diǎn)進(jìn)去文章末尾有投票按鈕,如果你覺得我做得不錯,歡迎投我3票(一天3票),或者直接跳轉(zhuǎn)到文末點(diǎn)擊 閱讀原文 進(jìn)入到投票頁面,投票結(jié)果只是最終結(jié)果的一部分。當(dāng)然,如果你覺得其他創(chuàng)客項(xiàng)目做的不錯,也歡迎多多投票支持。

文章目錄

上周末加班,這周末休息,有時間整理一篇之前做的基于RT-Thread的疫情監(jiān)控平臺。上一篇文章我們使用STM32F103 MCU裸機(jī)開發(fā)的方式實(shí)現(xiàn)了疫情監(jiān)控平臺。這次我們玩點(diǎn)高端的,使用RT-Thread Studio來實(shí)現(xiàn)同樣的功能,一起來看看吧!

  • 文章目錄

  • 使用到的軟件包

  • 0.RT-Thread Studio的下載和安裝

  • 1.硬件準(zhǔn)備

  • 2.新建工程

  • 3.添加LED閃爍功能

  • 4.添加ESP8266軟件包

  • 5.疫情數(shù)據(jù)的獲取

  • 6.疫情數(shù)據(jù)的解析

  • 7.疫情數(shù)據(jù)的顯示

  • 開源地址

最終的顯示效果:

顯示效果

有效文件就這9個,其他的就全是圖形化配置:

有效文件

整個流程下來,如果順利的話,可以在2個小時內(nèi)完成。

使用到的軟件包

  • at device:用于ESP8266配網(wǎng)

  • webclient:用于發(fā)送HTTPS請求

  • mbdetls:用于HTTPS加密

  • cJSON:用于JSON數(shù)據(jù)解析

0.RT-Thread Studio的下載和安裝

一站式的 RT-Thread 開發(fā)工具,通過簡單易用的圖形化配置系統(tǒng)以及豐富的軟件包和組件資源,讓物聯(lián)網(wǎng)開發(fā)變得簡單和高效。

RT-Thread Studio
  • 支持多種芯片,STM32全系列

  • 支持創(chuàng)建裸機(jī)工程、RT-Thread Nano和Master工程

  • 強(qiáng)大的代碼編輯功能,基于Eclipse框架

  • 免費(fèi)無版權(quán)限制,基于開源Eclipse和ARM-GCC編譯器。

  • 支持多種仿真器,J-Link,ST-link等,支持在線調(diào)試,變量觀察。

  • SDK管理器,圖形化配置RT-Thread軟件包,同步RT-Thread最新版本。

  • 集成Putty串口終端工具

更多的使用教程:

https://www.rt-thread.org/page/studio.html

目前最新版本為1.1.3版本,支持3種下載方式,我們選擇最后一個下載方式,從RT-Thread 官網(wǎng)服務(wù)器上下載。

下載地址:

http://117.143.63.254:9012/www/studio/download/RT-Thread%20Studio-v1.1.3-setup-x86_64_20200731-2100.exe

下載鏈接

安裝過程和常用的軟件安裝方法一樣,選擇安裝路徑,然后Next就行了。

1.硬件準(zhǔn)備

開發(fā)板用的是我在大四時自己設(shè)計(jì)的STM32開發(fā)板——NiceDay,基于STM32F103RET主控。 這是我設(shè)計(jì)的第二塊板子(第一塊是畢業(yè)設(shè)計(jì)兩輪平衡車主板),是在大四快畢業(yè)時,畢設(shè)實(shí)物和論文完成之后還有點(diǎn)時間,就設(shè)計(jì)了這款板子,最開始是準(zhǔn)備做桌面天氣時鐘的。

開發(fā)板

2.新建工程

RT-Thread Studio支持創(chuàng)建裸機(jī)工程、包含RT-Thread Nano版本的工程包含Master版本的工程。這里,我們選擇創(chuàng)建RT-Thread 項(xiàng)目,即包含完整版RT-Thread的工程。

新建項(xiàng)目

工程支持基于芯片創(chuàng)建工程,或者基于已有的BSP創(chuàng)建,這里使用的是我自己設(shè)計(jì)的開發(fā)板,所以選擇基于芯片,選擇芯片型號:STM32F103RE,調(diào)試串口選擇串口1,調(diào)試器選擇J-Link,SWD接口。

新建項(xiàng)目

創(chuàng)建完成之后,直接按Ctrl+B編譯整個工程,第一次編譯時間會長一點(diǎn),如果修改很少,下次再進(jìn)行編譯就會很快了,可以看到無警告無錯誤。

編譯結(jié)果

使用SWD接口連接JLink調(diào)試器和開發(fā)板,開發(fā)板上電,直接點(diǎn)擊下載按鈕,也可以使用快捷鍵Ctrl+Alt+D下載

下載程序

底部可以看到下載信息,從LOG來看,下載的程序文件是Bin文件,比較,擦除,編程,驗(yàn)證,復(fù)位整個流程耗時13s左右。

下載LOG

RT-Thread Studio是自帶Putty串口終端的,點(diǎn)擊終端圖標(biāo):

終端按鈕

選擇串口號、波特率、文字編碼方式等。

配置終端

底部切換到終端窗口,可以看到串口終端輸出信息:

串口終端

這樣,不到5分鐘,一個基于STM32F103RET6的工程模板就創(chuàng)建好了,包含RT-Thread完整版操作系統(tǒng),整個過程不需要寫一行代碼,完全圖形化配置。

3.添加LED閃爍功能

作為單片機(jī)點(diǎn)燈小能手,RT-Thread下如何點(diǎn)燈是必須掌握的。打開RT-Thread組件圖形化配置界面,可以看到默認(rèn)開啟了PIN和串口設(shè)備驅(qū)動的。

圖形化配置界面

在main.c文件中添加LED閃爍功能。包含頭文件和添加宏定義

#include  #include  #define LED_RED_PIN     GET_PIN(A, 7) #define LED_BLUE_PIN    GET_PIN(A,6) int main(void) { int count = 1;
    rt_pin_mode(LED_RED_PIN, PIN_MODE_OUTPUT);
    rt_pin_mode(LED_BLUE_PIN, PIN_MODE_OUTPUT); while (count++)
    {
        rt_pin_write(LED_BLUE_PIN, PIN_LOW);
        rt_pin_write(LED_RED_PIN, PIN_LOW);
        rt_thread_mdelay(100);

        rt_pin_write(LED_BLUE_PIN, PIN_HIGH);
        rt_pin_write(LED_RED_PIN, PIN_HIGH);
        rt_thread_mdelay(100);
    } return RT_EOK;
}

重新編譯,下載。可以看到LED閃爍起來了。工程默認(rèn)是使用內(nèi)部RC作為輸入時鐘,所以無論你的板子是8M還是12M,都可以正常閃爍。我的開發(fā)板是8M晶體,這里我們配置使用外部HSE作為輸入時鐘。

打開drivers->stm32f1xx_hal_conf.h文件,修改HSE_VALUE宏定義為8M。

晶體頻率修改

打開drivers->drv_clk.c文件:

時鐘源修改

配置PLL時鐘源為HSE,并設(shè)置倍頻系數(shù)為9。

時鐘源修改 倍頻系數(shù)

這里根據(jù)實(shí)際板子晶體頻率來設(shè)置,如果是12M晶體,倍頻系數(shù)應(yīng)該設(shè)置為6,如果是16M,需要參考時鐘樹,先2倍分頻,然后9倍倍頻。

#include  void system_clock_config(int target_freq_Mhz) {
    RCC_OscInitTypeDef RCC_OscInitStruct = {0}; /** Initializes the CPU, AHB and APB busses clocks
    */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
     ........ //9倍頻 RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9; //8*9=72M ........
}

這樣就修改為外部8M晶體作為PLL時鐘源,再次編譯下載,和之前的現(xiàn)象是一樣的。

4.添加ESP8266軟件包

聯(lián)網(wǎng)設(shè)備,我們選擇的是ESP8266-01S,如果看過上一篇疫情監(jiān)控三部曲——在STM32F103 MCU上實(shí)現(xiàn)(裸機(jī)版),里面介紹了如何配置ESP8266 GET HTTPS請求,配置工作模式 > 連接WiFi > 與服務(wù)器建立SSL連接 > 發(fā)送GET請求獲取數(shù)據(jù)等等,整個流程固定而繁瑣,那么能不能封裝成一個模塊,直接拿來使用呢?

esp8266

這里就要介紹RT-Thread的AT Device軟件包了,

AT device 軟件包是由 RT-Thread AT 組件針對不同 AT 設(shè)備的移植文件和示例代碼組成,目前支持的 AT 設(shè)備有:ESP8266、ESP32、M26、MC20、RW007、MW31、SIM800C、W60X 、SIM76XX、A9/A9G、BC26 、AIR720、ME3616、M6315、BC28、EC200X、M5311系列設(shè)備等,目前上述設(shè)備都完成對AT socket功能的移植,及設(shè)備通過 AT 命令實(shí)現(xiàn)標(biāo)準(zhǔn) socket 編程接口,完成 socket 通訊的功能,具體功能介紹可參考 《RT-Thread 編程指南》AT 命令章節(jié) 。
https://www.rt-thread.org/document/site/programming-manual/at/at/

簡單的說,就是我只需要調(diào)用這個軟件包,然后修改WiFi賬號和密碼,就可以直接配置ESP8266聯(lián)網(wǎng)了。

由于AT Device依賴于libc組件,所以在添加AT Device軟件包之前,先開啟libc。

在RT-Thread Settings中點(diǎn)擊libc灰色圖標(biāo),變成彩色說明已經(jīng)開啟。

組件配置

添加AT Device軟件包,點(diǎn)擊立即添加

軟件包

在彈出的軟件包中心,搜索at_device,然后點(diǎn)擊添加,添加到當(dāng)前工程。

軟件包

在at_device軟件包上右鍵,選擇詳細(xì)配置:

軟件包

在彈出的頁面,選擇我們使用的WiFi模塊類型,樂鑫的ESP8266系列,并配置WiFi賬號和密碼,WiFi模塊所連接的串口號。

WiFi配置

點(diǎn)擊保存之后,工程會重新進(jìn)行配置,添加相應(yīng)的軟件包文件到當(dāng)前工程,重新生成Makefile文件,rtconfig文件等等。

雖然我們在at_device配置中選擇了uart2作為at_device設(shè)備連接的串口。但此時串口2并沒有開啟,還需要我們手動使能。

打開drivers->board.h文件,通過宏定義的方式使能串口2。

#define BSP_USING_UART2 #define BSP_UART2_TX_PIN "PA2" #define BSP_UART2_RX_PIN "PA3" 

這樣就開啟了UART2的片上外設(shè),Ctrl + B重新進(jìn)行編譯,時間會有些長,編譯完成之后,可以看到flash文件大小明顯比之前大了。

編譯結(jié)果

Ctrl + Alt + D重新下載運(yùn)行,打開串口終端:

終端

可以看到,UART2初始化成功,WiFi連接成功。說明我們的串口模塊已經(jīng)可以正常工作了。提示[E/at.clnt] execute command (AT+CIPDNS_CUR?) failed!失敗信息,是因?yàn)楫?dāng)前ESP8266的固件版本不支持AT+CIPDNS_CUR?這條命令,把固件升級到最新版本就好了。這個不影響后面的操作,所以就不用在意這個了。

測試一下ifconfig和ping命令,都是正常的。

終端

在RT-Thread Studio中配置ESP8266模塊聯(lián)網(wǎng),整個流程只寫了3行代碼,可以說是非常的快速方便。

5.疫情數(shù)據(jù)的獲取

WiFi模塊連接上互聯(lián)網(wǎng)之后,就可以連接GET疫情數(shù)據(jù)的API接口https://lab.isaaclin.cn/nCoV/api/overall,然后讀取返回的疫情數(shù)據(jù)。在上一篇的裸機(jī)工程中,是通過先和服務(wù)器建立SSL連接,然后發(fā)送GET HTTPS請求,獲取到的返回?cái)?shù)據(jù),那RT-Thread有沒有這樣功能的軟件包呢?這里就需要添加另一個軟件包webclient。

WebClient 軟件包是 RT-Thread 自主研發(fā)的,基于 HTTP 協(xié)議的客戶端的實(shí)現(xiàn),它提供設(shè)備與 HTTP Server 的通訊的基本功能。
WebClient 軟件包功能特點(diǎn)如下:

  • 支持 IPV4/IPV6 地址;

  • 支持 GET/POST 請求方法;

  • 支持文件的上傳和下載功能;

  • 支持 HTTPS 加密傳輸;

  • 完善的頭部數(shù)據(jù)添加和處理方式。

和添加at_device一樣,在軟件包中心中搜索webclient,

軟件包

然后添加到當(dāng)前工程,右鍵進(jìn)行配置,由于我們的https://lab.isaaclin.cn/nCoV/api/overall這個疫情數(shù)據(jù)接口是HTTPS類型的,根據(jù)軟件包使用手冊,我們需要選擇TLS模式中的 MbedTLS。勾選添加GET和POST示例。

軟件包配置

保存配置,看一下當(dāng)前已經(jīng)添加了哪些功能,可以看到有一些組件我們并沒有去打開,但是已經(jīng)被開啟了,這是因?yàn)橛行┸浖菚蕾囈恍┙M件的,當(dāng)使能軟件包時,一些依賴的組件也被同時使能。

軟件包

Ctrl + B編譯,Ctrl + Alt + D下載運(yùn)行。在終端輸入web_get_test測試GET請求功能。

GET示例

可以看到,執(zhí)行g(shù)et命令之后,會返回一個字符串,那么GET的是哪個地址呢?打開packages->webclient-v2.1.2->samples->webclient_get_sample.c文件,

示例代碼

可以看到GET的是這個地址:http://www.rt-thread.com/service/rt-thread.txt,我們用電腦上的瀏覽器訪問一下:

瀏覽器訪問

經(jīng)過實(shí)際測試發(fā)現(xiàn),GET HTTPS請求,還需要使能軟件模擬RTC這個組件,否則會報(bào)assertion failed at function:gettimeofday, line number:19錯誤。

使能RTC

我們重新寫一個獲取疫情數(shù)據(jù)的函數(shù),并導(dǎo)出到MSH。

usr_ncov.c文件內(nèi)容

//usr_ncov.c #include "usr_ncov.h" int get_NCOV_Data(void) { char *uri = RT_NULL; struct webclient_session* session = RT_NULL; uint8_t *buffer = RT_NULL; int index, ret = 0; int bytes_read, resp_status; int content_length = -1; int buffer_size = 1600;
    uri = web_strdup(API_NCOV);
    rt_kprintf("start get api: %s\r\n", API_NCOV); if(uri != RT_NULL)
    {
        buffer = (unsigned char *) web_malloc(buffer_size); if (buffer == RT_NULL)
        {
            rt_kprintf("no memory for receive buffer.\n");
            ret = -RT_ENOMEM; goto __exit;
        } /* create webclient session and set header response size */ session = webclient_session_create(buffer_size); if (session == RT_NULL)
        {
            ret = -RT_ENOMEM; goto __exit;
        } /* send GET request by default header */ if ((resp_status = webclient_get(session, uri)) != 200)
        {
            rt_kprintf("webclient GET request failed, response(%d) error.\n", resp_status);
            ret = -RT_ERROR; goto __exit;
        }

        rt_kprintf("webclient get response data: \n");

        content_length = webclient_content_length_get(session); if (content_length < 0)
        {
            rt_kprintf("webclient GET request type is chunked.\n"); do {
                bytes_read = webclient_read(session, buffer, buffer_size); if (bytes_read <= 0) break; for (index = 0; index < bytes_read; index++) { rt_kprintf("%c", buffer[index]);
                }
            } while (1);

            rt_kprintf("\n");
        } else { /* 讀取服務(wù)器響應(yīng)的數(shù)據(jù) */ bytes_read = webclient_read(session, buffer, content_length);
            rt_kprintf("data length:%d\n", bytes_read);

            buffer[bytes_read] = '\0';
            rt_kprintf("\n\n %s \n\n", buffer); //            rt_kprintf("parse data\r\n"); // parseData(buffer);        //解析函數(shù) rt_kprintf("\n");
        }

        __exit: if (session)
            webclient_close(session); if (buffer)
            web_free(buffer);
    } else rt_kprintf("api error: %s\n", API_NCOV); return ret;
}
MSH_CMD_EXPORT(get_NCOV_Data, get api ncov);

usr_ncov.h文件內(nèi)容

#ifndef APPLICATIONS_USR_NCOV_H_ #define APPLICATIONS_USR_NCOV_H_ #include  #include  #include  #define API_NCOV "https://lab.isaaclin.cn/nCoV/api/overall" int get_NCOV_Data(void); #endif /* APPLICATIONS_USR_NCOV_H_ 

重新編譯,下載,運(yùn)行。在終端運(yùn)行這個命令:

命令獲取疫情數(shù)據(jù)

可以看到獲取到了返回的數(shù)據(jù),長度1366個字節(jié)。下一步就是對這個JSON數(shù)據(jù)進(jìn)行解析,獲取到我們想要的疫情數(shù)據(jù)。

6.疫情數(shù)據(jù)的解析

API返回的數(shù)據(jù)是JSON格式的,關(guān)于JSON的介紹和解析,可以查看使用cJSON庫解析和構(gòu)建JSON字符串。數(shù)據(jù)的解析使用的開源小巧的cJSON解析庫,我們可以在軟件包管理中心直接添加:

添加cJSON

在進(jìn)行解析之前,先來分析一下JSON原始數(shù)據(jù)的格式:results鍵的值是一個數(shù)組,數(shù)組只有一個JSON對象,獲取這個對象對應(yīng)鍵的值可以獲取到國內(nèi)現(xiàn)存和新增確診人數(shù)、累計(jì)和新增死亡人數(shù),累計(jì)和新增治愈人數(shù)等數(shù)據(jù)。

全球疫情數(shù)據(jù)保存在globalStatistics鍵里,它的值是一個JSON對象,對象僅包含簡單的鍵值對,這些鍵的值,就是全球疫情數(shù)據(jù),其中updateTime鍵的值是更新時間,這是毫秒級UNIX時間戳,可以轉(zhuǎn)換為標(biāo)準(zhǔn)北京時間。

{ "results": [{ "currentConfirmedCount": 509, "currentConfirmedIncr": 16, "confirmedCount": 85172, "confirmedIncr": 24, "suspectedCount": 1899, "suspectedIncr": 4, "curedCount": 80015, "curedIncr": 8, "deadCount": 4648, "deadIncr": 0, "seriousCount": 106, "seriousIncr": 9, "globalStatistics": { "currentConfirmedCount": 4589839, "confirmedCount": 9746927, "curedCount": 4663778, "deadCount": 493310, "currentConfirmedIncr": 281, "confirmedIncr": 711, "curedIncr": 424, "deadIncr": 6 }, "updateTime": 1593227489355 }], "success": true }

先定義了結(jié)構(gòu)體NCOV_DATA,用于存儲國內(nèi)和全球疫情數(shù)據(jù):

struct NCOV_DATA{ int currentConfirmedCount; int currentConfirmedIncr; int confirmedCount; int confirmedIncr; int curedCount; int curedIncr; int deadCount; int deadIncr; int seriousCount; int seriousIncr; char updateTime[20];
};

對應(yīng)的解析函數(shù):

#include  struct NCOV_DATA dataChina = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "06-13 16:22"};; struct NCOV_DATA dataGlobal = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL}; int parseData(uint8_t *str) { int ret = 0;
    cJSON *root, *result_arr;
    cJSON *result, *global; time_t updateTime; struct tm *time; root = cJSON_Parse((const char *)str); //創(chuàng)建JSON解析對象,返回JSON格式是否正確 if (root != 0)
    {
        rt_kprintf("JSON format ok, start parse!!!\n");
        result_arr = cJSON_GetObjectItem(root, "results"); if(result_arr->type == cJSON_Array)
        { //            rt_kprintf("result is array\n"); result = cJSON_GetArrayItem(result_arr, 0); if(result->type == cJSON_Object)
            { //                rt_kprintf("result_arr[0] is object\n"); /* china data parse */ dataChina.currentConfirmedCount = cJSON_GetObjectItem(result, "currentConfirmedCount")->valueint;
                dataChina.currentConfirmedIncr = cJSON_GetObjectItem(result, "currentConfirmedIncr")->valueint;
                dataChina.confirmedCount = cJSON_GetObjectItem(result, "confirmedCount")->valueint;
                dataChina.confirmedIncr = cJSON_GetObjectItem(result, "confirmedIncr")->valueint;
                dataChina.curedCount = cJSON_GetObjectItem(result, "curedCount")->valueint;
                dataChina.curedIncr = cJSON_GetObjectItem(result, "curedIncr")->valueint;
                dataChina.deadCount = cJSON_GetObjectItem(result, "deadCount")->valueint;
                dataChina.deadIncr = cJSON_GetObjectItem(result, "deadIncr")->valueint;

                rt_kprintf("**********china ncov data**********\n");
                rt_kprintf("%-23s: %8d, %-23s: %8d\n", "currentConfirmedCount", dataChina.currentConfirmedCount, "currentConfirmedIncr", dataChina.currentConfirmedIncr);
                rt_kprintf("%-23s: %8d, %-23s: %8d\n", "confirmedCount", dataChina.confirmedCount, "confirmedIncr", dataChina.confirmedIncr);
                rt_kprintf("%-23s: %8d, %-23s: %8d\n", "curedCount", dataChina.curedCount, "curedIncr", dataChina.curedIncr);
                rt_kprintf("%-23s: %8d, %-23s: %8d\n", "deadCount", dataChina.deadCount, "deadIncr", dataChina.deadIncr); /* global data parse */ global = cJSON_GetObjectItem(result, "globalStatistics"); if(global->type == cJSON_Object)
                {
                    dataGlobal.currentConfirmedCount = cJSON_GetObjectItem(global, "currentConfirmedCount")->valueint;
                    dataGlobal.currentConfirmedIncr = cJSON_GetObjectItem(global, "currentConfirmedIncr")->valueint;
                    dataGlobal.confirmedCount = cJSON_GetObjectItem(global, "confirmedCount")->valueint;
                    dataGlobal.confirmedIncr = cJSON_GetObjectItem(global, "confirmedIncr")->valueint;
                    dataGlobal.curedCount = cJSON_GetObjectItem(global, "curedCount")->valueint;
                    dataGlobal.curedIncr = cJSON_GetObjectItem(global, "curedIncr")->valueint;
                    dataGlobal.deadCount = cJSON_GetObjectItem(global, "deadCount")->valueint;
                    dataGlobal.deadIncr = cJSON_GetObjectItem(global, "deadIncr")->valueint;

                    rt_kprintf("\n**********global ncov data**********\n");
                    rt_kprintf("%-23s: %8d, %-23s: %8d\n", "currentConfirmedCount", dataGlobal.currentConfirmedCount, "currentConfirmedIncr", dataGlobal.currentConfirmedIncr);
                    rt_kprintf("%-23s: %8d, %-23s: %8d\n", "confirmedCount", dataGlobal.confirmedCount, "confirmedIncr", dataGlobal.confirmedIncr);
                    rt_kprintf("%-23s: %8d, %-23s: %8d\n", "curedCount", dataGlobal.curedCount, "curedIncr", dataGlobal.curedIncr);
                    rt_kprintf("%-23s: %8d, %-23s: %8d\n", "deadCount", dataGlobal.deadCount, "deadIncr", dataGlobal.deadIncr);

                } else return 1; /* 毫秒級時間戳轉(zhuǎn)字符串 */ updateTime = (time_t )(cJSON_GetObjectItem(result, "updateTime")->valuedouble / 1000);
                updateTime += 8 * 60 * 60; /* UTC8校正 */ time = localtime(&updateTime); /* 格式化時間 */ strftime(dataChina.updateTime, 20, "%m-%d %H:%M", time);
                rt_kprintf("update: %s\r\n", dataChina.updateTime);/* 06-24 11:21 */ //數(shù)據(jù)在LCD顯示 //gui_show_ncov_data(dataChina, dataGlobal); } else return 1;
        } else return 1;
        rt_kprintf("\nparse complete \n");
    } else {
        rt_kprintf("JSON format error:%s\n", cJSON_GetErrorPtr()); //輸出json格式錯誤信息 return 1;
    }
    cJSON_Delete(root); return ret;
}

在數(shù)據(jù)接收完成之后,對JSON數(shù)據(jù)進(jìn)行解析。

解析結(jié)果

7.疫情數(shù)據(jù)的顯示

數(shù)據(jù)解析出來之后,剩下的就簡單了,把上一篇文章中9341的驅(qū)動文件移植過來就好了。

液晶屏使用的是3.2寸 LCD,IL9341驅(qū)動芯片,320*240分辨率,16位并口。由于屏幕分辨率比較低,可顯示的內(nèi)容有限,所以只是顯示了最基本的幾個疫情數(shù)據(jù)。為了減小程序大小,GUI只實(shí)現(xiàn)了基本的畫點(diǎn),畫線函數(shù),字符的顯示,采用的是部分字符取模,只對程序中用到的漢字和字符進(jìn)行取模。為了增強(qiáng)可移植性,程序中并沒有使用外置SPI Flash存儲整個字庫。

由于RT-Thread Studio使用的HAL庫,所以LCD的GPIO初始化函數(shù)需要修改一下:

void lcd_gpio_init(void) {
    GPIO_InitTypeDef GPIO_InitStructure;

    __HAL_RCC_GPIOA_CLK_ENABLE();
    __HAL_RCC_GPIOC_CLK_ENABLE();
    __HAL_RCC_GPIOB_CLK_ENABLE();
    __HAL_RCC_AFIO_CLK_ENABLE();
    __HAL_AFIO_REMAP_SWJ_NOJTAG();

    GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStructure.Pull = GPIO_PULLUP;
    GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStructure.Pin = GPIO_PIN_9 | GPIO_PIN_8 | GPIO_PIN_7 | GPIO_PIN_6;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStructure); //GPIOC GPIO_InitStructure.Pin = GPIO_PIN_8; //背光引腳PA8 HAL_GPIO_Init(GPIOA, &GPIO_InitStructure); //GPIOC GPIO_InitStructure.Pin = GPIO_PIN_All;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);

    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_9 | GPIO_PIN_8 | GPIO_PIN_7 | GPIO_PIN_6, GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_All, GPIO_PIN_SET);
}

延時函數(shù)換成:

rt_thread_mdelay(nms);

還有一點(diǎn),在Keil中,文字編碼選擇GBK編碼,1個漢字占用2個字節(jié),而RT-Thread Studio為UTF-8編碼,1個漢字占用3個字節(jié),漢字顯示函數(shù)需要調(diào)整:

void gui_show_chn(uint16_t x0, uint16_t y0, char *chn) { uint8_t idx = 0; uint8_t* code[3]; //UTF-8:國=E59BBD uint8_t size = sizeof(FONT_16X16_TABLE) / sizeof(FONT_16X16_TABLE[0]); /* 遍歷漢字,獲取索引 */ for(idx = 0; idx < size; idx++) { code[0] = FONT_16X16_TABLE[idx].chn;
        code[1] = FONT_16X16_TABLE[idx].chn + 1;
        code[2] = FONT_16X16_TABLE[idx].chn + 2; //漢字內(nèi)碼一致 if(!(strcmp(code[0], chn) || strcmp(code[1], chn+1) || strcmp(code[2], chn+2)))
        {
            gui_show_F16X16_Char(x0, y0, idx, WHITE); return; //            break; }
    }
}

疫情數(shù)據(jù)顯示函數(shù):

void gui_show_ncov_data(struct NCOV_DATA china, struct NCOV_DATA global) { uint8_t y0 = 20;

    lcd_clear(BLACK);
    gui_show_bar();

    gui_drawLine(0, 18, 320, DIR_X, WHITE);
    gui_drawLine(0, 38, 320, DIR_X, WHITE);
    gui_drawLine(0, 138, 320, DIR_X, WHITE);
    gui_drawLine(0, 158, 320, DIR_X, WHITE);
    gui_drawLine(0, 220, 320, DIR_X, WHITE); /* "國內(nèi)疫情" */ gui_show_chn_string(128, y0, "國內(nèi)疫情");
    gui_show_line_data(40, "現(xiàn)存確診:", china.currentConfirmedCount, "較昨日:", china.currentConfirmedIncr);
    gui_show_line_data(60, "累計(jì)確診:", china.confirmedCount, "較昨日:", china.confirmedIncr);
    gui_show_line_data(80, "累計(jì)治愈:", china.curedCount, "較昨日:", china.curedIncr);
    gui_show_line_data(100, "現(xiàn)存重癥:", china.seriousCount, "較昨日:", china.seriousIncr);
    gui_show_line_data(120, "累計(jì)死亡:", china.deadCount, "較昨日:", china.deadIncr); /* 全球疫情 */ gui_show_chn_string(128, 140, "全球疫情");
    gui_show_line_data(160, "現(xiàn)存確診:", global.currentConfirmedCount, "較昨日:", global.currentConfirmedIncr);
    gui_show_line_data(180, "累計(jì)治愈:", global.curedCount, "較昨日:", global.curedIncr);
    gui_show_line_data(200, "累計(jì)死亡:", global.deadCount, "較昨日:", global.deadIncr);

    gui_show_chn_string(160, 222, "更新于:");
    gui_show_F8X16_String(230, 222, china.updateTime, GREEN);
}

最終顯示效果

最終效果

開源地址

代碼已經(jīng)開源,地址在文末,歡迎大家參與,豐富這個小項(xiàng)目的功能!

  • 基于STM32+RT-Thread的疫情監(jiān)控平臺
    https://github.com/whik/rtt_2019_ncov

  • 基于STM32F103的疫情監(jiān)控平臺(裸機(jī)版)
    https://github.com/whik/stm32_2019_ncov

如果GitHub下載速度太慢,可以關(guān)注我的公眾號,電子電路開發(fā)學(xué)習(xí)(ID: MCU149),在后臺回復(fù)【RTT疫情監(jiān)控】獲取基于RT-Thread的工程源碼,或者回復(fù)【STM32疫情監(jiān)控】獲取裸機(jī)版本的工程源碼,我會把下載鏈接發(fā)給你。

推薦閱讀

  • 疫情監(jiān)控三部曲——在STM32F103 MCU上實(shí)現(xiàn)(裸機(jī)版)

  • [開源]基于桌面版Qt的肺炎疫情監(jiān)控平臺

  • [開源]基于STM32MP1+Qt的疫情監(jiān)控平臺

  • 使用cJSON庫解析和構(gòu)建JSON字符串

文末再厚著臉皮插播一條廣告

我在疫情期間做的基于STM32MP1和Qt的新冠肺炎疫情監(jiān)控平臺,這個小項(xiàng)目報(bào)名參加了意法半導(dǎo)體首屆創(chuàng)客大賽——STM32創(chuàng)客秀,最近在投票階段,如果有幸能入圍決賽,ST官方會獎勵開發(fā)板禮包,屆時我會把開發(fā)板以抽獎的方式回饋給大家。

大家可以長按下面的二維碼查看項(xiàng)目詳情:

投票二維碼

文末有投票按鈕,如果你覺得我做得不錯,歡迎投我3票(一天3票),或者直接跳轉(zhuǎn)到文末點(diǎn)擊 閱讀原文 進(jìn)入到投票頁面,投票結(jié)果只是最終結(jié)果的一部分。當(dāng)然,如果你覺得其他創(chuàng)客項(xiàng)目做的不錯,也歡迎多多投票支持。

https://www.stmcu.com.cn/Vote/Itemsdetails/20

免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺僅提供信息存儲服務(wù)。文章僅代表作者個人觀點(diǎn),不代表本平臺立場,如有問題,請聯(lián)系我們,謝謝!

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時聯(lián)系本站刪除。
換一批
延伸閱讀

LED驅(qū)動電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關(guān)鍵字: 驅(qū)動電源

在工業(yè)自動化蓬勃發(fā)展的當(dāng)下,工業(yè)電機(jī)作為核心動力設(shè)備,其驅(qū)動電源的性能直接關(guān)系到整個系統(tǒng)的穩(wěn)定性和可靠性。其中,反電動勢抑制與過流保護(hù)是驅(qū)動電源設(shè)計(jì)中至關(guān)重要的兩個環(huán)節(jié),集成化方案的設(shè)計(jì)成為提升電機(jī)驅(qū)動性能的關(guān)鍵。

關(guān)鍵字: 工業(yè)電機(jī) 驅(qū)動電源

LED 驅(qū)動電源作為 LED 照明系統(tǒng)的 “心臟”,其穩(wěn)定性直接決定了整個照明設(shè)備的使用壽命。然而,在實(shí)際應(yīng)用中,LED 驅(qū)動電源易損壞的問題卻十分常見,不僅增加了維護(hù)成本,還影響了用戶體驗(yàn)。要解決這一問題,需從設(shè)計(jì)、生...

關(guān)鍵字: 驅(qū)動電源 照明系統(tǒng) 散熱

根據(jù)LED驅(qū)動電源的公式,電感內(nèi)電流波動大小和電感值成反比,輸出紋波和輸出電容值成反比。所以加大電感值和輸出電容值可以減小紋波。

關(guān)鍵字: LED 設(shè)計(jì) 驅(qū)動電源

電動汽車(EV)作為新能源汽車的重要代表,正逐漸成為全球汽車產(chǎn)業(yè)的重要發(fā)展方向。電動汽車的核心技術(shù)之一是電機(jī)驅(qū)動控制系統(tǒng),而絕緣柵雙極型晶體管(IGBT)作為電機(jī)驅(qū)動系統(tǒng)中的關(guān)鍵元件,其性能直接影響到電動汽車的動力性能和...

關(guān)鍵字: 電動汽車 新能源 驅(qū)動電源

在現(xiàn)代城市建設(shè)中,街道及停車場照明作為基礎(chǔ)設(shè)施的重要組成部分,其質(zhì)量和效率直接關(guān)系到城市的公共安全、居民生活質(zhì)量和能源利用效率。隨著科技的進(jìn)步,高亮度白光發(fā)光二極管(LED)因其獨(dú)特的優(yōu)勢逐漸取代傳統(tǒng)光源,成為大功率區(qū)域...

關(guān)鍵字: 發(fā)光二極管 驅(qū)動電源 LED

LED通用照明設(shè)計(jì)工程師會遇到許多挑戰(zhàn),如功率密度、功率因數(shù)校正(PFC)、空間受限和可靠性等。

關(guān)鍵字: LED 驅(qū)動電源 功率因數(shù)校正

在LED照明技術(shù)日益普及的今天,LED驅(qū)動電源的電磁干擾(EMI)問題成為了一個不可忽視的挑戰(zhàn)。電磁干擾不僅會影響LED燈具的正常工作,還可能對周圍電子設(shè)備造成不利影響,甚至引發(fā)系統(tǒng)故障。因此,采取有效的硬件措施來解決L...

關(guān)鍵字: LED照明技術(shù) 電磁干擾 驅(qū)動電源

開關(guān)電源具有效率高的特性,而且開關(guān)電源的變壓器體積比串聯(lián)穩(wěn)壓型電源的要小得多,電源電路比較整潔,整機(jī)重量也有所下降,所以,現(xiàn)在的LED驅(qū)動電源

關(guān)鍵字: LED 驅(qū)動電源 開關(guān)電源

LED驅(qū)動電源是把電源供應(yīng)轉(zhuǎn)換為特定的電壓電流以驅(qū)動LED發(fā)光的電壓轉(zhuǎn)換器,通常情況下:LED驅(qū)動電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關(guān)鍵字: LED 隧道燈 驅(qū)動電源
關(guān)閉