[秀作品] 為奧運健兒加油——使用STM32獲取東京奧運獎牌榜

okhxyyo 樓主
2021-8-11 09:44

作者:wcc149

來源:https://mp.weixin.qq.com/s/gtuy3ad_iutFqlhmIeNjuQ 

 

東京奧運會可以說是奧運會歷史上最特殊的一屆,推遲一年、沒有觀眾、環保奧運等。從7月23日開幕至今,已經過去了16天,截至8月7日下午17點,中國以38金,29銀,17銅的成績位居榜首,緊隨其后的是美國和日本。

明天(8月8日)將是本節奧運會最后一天,希望中國能保持住第一的位置,為奧運健兒加油!

為了能實時關注獎牌榜,也為了發(shui)一篇文章,周末在家使用STM32+ESP8266做了一個東京奧運會獎牌榜桌面小擺件,最終效果如下:

640?wx_fmt=jpeg
桌面效果1
640?wx_fmt=jpeg
桌面效果2

可能很多朋友都是從STM32疫情監控、STM32疫苗監控這兩個項目開始關注我的,其實獎牌榜獲取和這兩個是一樣的原理,都是通過STM32驅動ESP8266連接網絡,然后GET接口,讀取到接口返回的JSON數據,然后進行JSON解析,LCD顯示,使用不同的接口就是不同的功能。

和之前不同的是,以上兩個API接口返回的數據都非常簡短,只有幾百字節,而獎牌榜接口返回的數據有20KB之多,使用STM32不能一次處理這么多的數據量,本文采用了一種簡單的方法來進行數據截取,從而減少數據量。

都有哪些內容?

  • API接口獲取

  • JSON數據預處理

  • JSON數據解析

  • 顯示效果

  • 開源地址

API接口獲取

在進行開發之前,首先要找到一個API接口,請求方式最好是GET,返回數據格式JSON格式的。先上網搜一下,發現已經有很多網友實現獎牌榜數據獲取的功能,使用的大多是:Python、Java、PHP,使用的語言無所謂,重要的是API接口是否是我們想要的,最終找到了兩個API接口。

第一個接口是央視網官方的東京奧運專題頁面:

640?wx_fmt=jpeg
圖:2020.cctv.com

網址如下:

http://2020.cctv.com/medal_list/index.shtml

F12打開開發者模式,可以找到頁面請求的API地址:

640?wx_fmt=jpeg
cntv_api

這個接口返回的數據量有11KB,格式化后有24KB,JSON數據格式(部分):

640?wx_fmt=jpeg
cntv_json

可以看到數據比較齊全,包括排名,金、銀、銅、合計獎牌總數,國家ID,國家名稱為UTF-16BE編碼方式,而開發板上的字庫為GBK編碼,這一點不好處理。看看還有沒有其他的接口。

第二個接口是我的小米手機負一屏界面呈現的奧運獎牌榜,類似于這種:

640?wx_fmt=jpeg
手機界面2

可以跳轉到瀏覽器打開:

http://act.e.mi.com/olympic/index.html

F12打開開發者模式,可以找到請求的API地址:

640?wx_fmt=jpeg
mi_api

這個接口返回的數據有21KB,格式化后有33KB,JSON數據格式(部分):

640?wx_fmt=jpeg
mi_json

這個接口返回數據比較豐富,同樣數據量相比于央視網的要大一些,除了獎牌數量排名等信息,還包括每個國家的國旗圖片地址,更新時間等。國家名稱為UTF-8編碼,要在我們的開發板上進行使用需要進行UTF8-GBK的轉換。

綜上,我們就獲取到了兩個API接口的信息:

奧運獎牌榜央視API接口:

TYPE: "TCP"
PORT: "80"
IP  : "111.206.176.78"
API : "http://api.cntv.cn/olympic/getOlyMedals?serviceId=pcocean&itemcode=GEN-------------------------------"

奧運獎牌榜小米手機API接口

TYPE: "TCP"
PORT: "80"
IP  : "111.206.101.253"
API : "http://act.e.mi.com/olympic/medal_rank"

為了方便在開發板上直接顯示國家名稱,我們采用小米手機的API接口。

JSON數據預處理

通過分析API接口返回的數據,共包括前90名的獎牌數據,數據長度為21KB:

mi_json

但是我們只需要前10名的數據即可。串口接口緩存長度設置為2500個字節,即返回的21KB字節數據,只接收前2500個字節,然后處理成JSON標準格式就可以了。

處理方法為,倒序查找最后一個}號的位置,將{之后的數據丟棄掉,然后添加上]},這樣就將截取的2500字節數據修改為了標準JSON格式數據:

640?wx_fmt=jpeg
mi_json_deal

JSON數據解析

從上圖也可以看出,JSON格式比較簡單,使用cJSON可以很方便的進行解析,使用方法可以查看以下文章:

定義一個結構體:

typedef struct medal{
    char rank[5];
    char countryname[50];
    char count[5];
    char gold[5];
    char silver[5];
    char bronze[5];
    char update_time[50];
    char countryid[10];
}medalObj;

解析函數,只讀取前7名的獎牌數據:

uint8_t parse_mi_data(void)
{
    cJSON *root, *data_obj, *list_obj;
    char *str;
    char dest[USART2_MAX_RECV_LEN];
    char *loc;
    char gbk[50];
    char utf8[50];

    medalObj *pobj;
    medalObj obj;
    int idx;

    pobj = &obj;

    str = (char *)USART2_RX_BUF;
    memset(dest, '\0', USART2_MAX_RECV_LEN);
    loc = strrchr(str, '}');
    strncpy(dest, str, loc-str+1);
    strcat(dest, "]}");
    printf("json data size: %d bytes\r\n", strlen(dest));

    root = cJSON_Parse((const char*)dest);

    if(root != 0)
    {
        printf("JSON format ok, start parse!!!\r\n");
        data_obj = cJSON_GetObjectItem(root, "data");
        if(data_obj->type == cJSON_Array)
        {
            int size = cJSON_GetArraySize(data_obj);
            for(idx = 0; idx < size; idx++)
            {
                if(size >= 7 && idx <= 7)
                {
                    list_obj = cJSON_GetArrayItem(data_obj, idx);

                    strcpy(obj.bronze, cJSON_GetObjectItem(list_obj, "medal_bronze_count")->valuestring);
                    strcpy(obj.rank, cJSON_GetObjectItem(list_obj, "rank")->valuestring);
                    strcpy(obj.count, cJSON_GetObjectItem(list_obj, "medal_sum_count")->valuestring);
                    strcpy(obj.silver, cJSON_GetObjectItem(list_obj, "medal_silver_count")->valuestring);
                    //utf8->gbk
                    memset(utf8, '\0', sizeof(utf8));
                    memset(gbk, '\0', sizeof(gbk));
                    strcpy(utf8, cJSON_GetObjectItem(list_obj, "country_name")->valuestring);
                    SwitchToGbk(utf8, gbk);

                    strcpy(obj.countryname, gbk);

                    strcpy(obj.gold, cJSON_GetObjectItem(list_obj, "medal_gold_count")->valuestring);
                    strcpy(obj.update_time, cJSON_GetObjectItem(list_obj, "update_time")->valuestring);
                    printf("%s: %s %10s %s:%s-%s-%s\r\n",
                           pobj->rank, pobj->update_time, pobj->countryname,
                           pobj->count, pobj->gold, pobj->silver, pobj->bronze);
                        gui_show_data(48+idx*20, pobj);
                }
            }
            Show_Str_Mid(200, 225, (u8 *)pobj->update_time, 12, 120);
        } 
    }    
    else
    {
        printf("JSON format error:%s\r\n", cJSON_GetErrorPtr()); //輸出json格式錯誤信息
    }

    USART2_RX_STA = 0;
    memset(USART2_RX_BUF, 0, sizeof(USART2_RX_BUF));

    cJSON_Delete(root);

    return 0;
}

如果出現解析失敗的情況,可能需要調整啟動文件中的堆棧大小:

//startup_stm32f10x_hd.s

Stack_Size      EQU     0x00000C00

Heap_Size       EQU     0x00000200

最終效果

最終效果:

640?wx_fmt=jpeg
BMP顯示效果
640?wx_fmt=jpeg
桌面效果3
640?wx_fmt=jpeg
桌面效果5

和手機端數據完全一致:

640?wx_fmt=jpeg
手機界面1

開源地址

我的開發板已經預先寫入了中文字庫,沒有字庫的開發板可能不適用。

全部代碼已經開源在Gitee碼云:

https://gitee.com/whik/stm32_olympic_medals

或者在后臺回復【奧運】,獲取工程壓縮包下載鏈接。

0?wx_fmt=png

電子電路開發學習

精通各種單片機、DSP、FPGA實現流水燈,程序擦除與下載😝,IDE環境安裝與卸載😊,非著名公司攻城獅😏,bug制造者😜。分享開源項目、板卡評測、學習筆記相關文章。可能不會經常更新,但每一篇都是精心編寫。

115篇原創內容

公眾號

總結

北京時間2021年8月8日晚,17天的2020東京奧運會將落下帷幕,19:00閉幕式將如期舉行。本屆奧運會閉幕式理念為“Worlds we share”(我們共享的世界),蘊含“銘記與不同性格、不同文化背景的人們共享的感動,攜手共創未來”之意,同時也包含了人類共同抵抗新冠疫情的團結之意,雖然東京奧運會將要和觀眾說再見,但即將到來的2022北京冬奧會將持續點燃廣大體育迷的熱情。

640?wx_fmt=jpeg

桌面效果4

玩板看這里:

http://bbs.eeworld.com.cn/elecplay.html

EEWorld測評頻道眾多好板等你來玩,還可以來頻道許愿樹許愿說說你想要玩的板子,我們都在努力為大家實現!

回復評論 (4)

沙發 lilipo

2021-8-11 09:58

add oil 加油

板凳 w494143467

2021-8-11 10:07

做的還不錯。

4樓 懶貓愛飛

2021-8-11 14:36

棒棒噠

專注智能產品的研究與開發,專注于電子電路的生產與制造……QQ:2912615383,電子愛好者群: void

5樓 freebsder

2021-8-11 16:48

有點意思,那幾個藝術字模型不錯!

默認摸魚

電子工程世界版權所有 京B2-20211791 京ICP備10001474號-1 京公網安備 11010802033920號
    我也要說兩句
    發送
    評論
    萝卜大香蕉