The Tokyo Olympics can be said to be the most special one in the history of the Olympics, postponed for a year, no audience, and an eco-friendly Olympics.
To keep track of the medal standings in real-time, I made a STM32 + ESP8266 desktop decoration for the Tokyo Olympics Medal Standings, and the final effect is as follows:



The principle is to use STM32 to drive ESP8266 to connect to the internet, then use the GET interface to read the returned JSON data, and then perform JSON parsing, and display it on an LCD. Using different interfaces allows for different functionalities.
Unlike before, the above two API interfaces return very short data, only a few hundred bytes, while the medal standings interface returns as much as 20KB of data. STM32 cannot handle such a large amount of data at once, so this article adopts a simple method to truncate the data to reduce the amount.
What content is included?
-
API Interface Acquisition -
JSON Data Preprocessing -
JSON Data Parsing -
Display Effect
API Interface Acquisition
Before development, the first step is to find an API interface, preferably with a GET request method and returning data in JSON format. After searching online, I found that many netizens have implemented functions to get medal standings data, mostly using: Python, Java, PHP. The language doesn’t matter; what’s important is whether the API interface is what we want. Finally, I found two API interfaces.
The first interface is the official Tokyo Olympics special page from CCTV:

The URL is as follows:
http://2020.cctv.com/medal_list/index.shtml
Open the developer mode with F12 to find the API address requested by the page:

This interface returns 11KB of data, which formats to 24KB, in JSON format (part):

As can be seen, the data is quite complete, including ranking, gold, silver, bronze, total medal count, country ID, and country name encoded in UTF-16BE. However, the character library on the development board is GBK encoded, which is a bit challenging to handle. Let’s see if there are any other interfaces.
The second interface is the Olympic medal standings displayed on my Xiaomi phone’s negative one screen, similar to this:

You can open it in a browser:
http://act.e.mi.com/olympic/index.html
Open the developer mode with F12 to find the requested API address:

This interface returns 21KB of data, which formats to 33KB, in JSON format (part):

This interface returns relatively rich data. Compared to CCTV’s data, it is larger and includes not only medal count rankings but also the image addresses of each country’s flag, update time, etc. The country name is UTF-8 encoded, which needs to be converted from UTF-8 to GBK for use on our development board.
In summary, we have obtained information from two API interfaces:
Olympic Medal Standings CCTV API Interface:
TYPE: "TCP"
PORT: "80"
IP : "111.206.176.78"
API : "http://api.cntv.cn/olympic/getOlyMedals?serviceId=pcocean&itemcode=GEN-------------------------------"
Olympic Medal Standings Xiaomi Phone API Interface
TYPE: "TCP"
PORT: "80"
IP : "111.206.101.253"
API : "http://act.e.mi.com/olympic/medal_rank"
To facilitate direct display of country names on the development board, we use the Xiaomi phone’s API interface.
JSON Data Preprocessing
By analyzing the data returned by the API interface, it includes medal data for the top 90 countries, with a data length of 21KB:

However, we only need the data for the top 10 countries. The serial port interface buffer length is set to 2500 bytes, meaning that for the returned 21KB of data, we only receive the first 2500 bytes and then process it into standard JSON format.
The processing method is to reverse search for the position of the last }
character, discard the data after {
, and then add ]}
, thus modifying the truncated 2500 bytes of data into standard JSON format data:

JSON Data Parsing
As can be seen from the above image, JSON format is quite simple, and using cJSON makes parsing very convenient. For usage, you can refer to the following article:
-
Using cJSON Library to Parse and Construct JSON Strings
Define a structure:
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;
The parsing function reads only the medal data for the top 7 countries:
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()); //Output JSON format error information
}
USART2_RX_STA = 0;
memset(USART2_RX_BUF, 0, sizeof(USART2_RX_BUF));
cJSON_Delete(root);
return 0;
}
If parsing fails, it may be necessary to adjust the stack size in the startup file:
//startup_stm32f10x_hd.s
Stack_Size EQU 0x00000C00
Heap_Size EQU 0x00000200
Final Effect




Open Source Address
My development board has already been preloaded with a Chinese character library, so boards without a character library may not be applicable.
All code has been open-sourced on Gitee:
https://gitee.com/whik/stm32_olympic_medals
-END-
Hello everyone, I am Zhang Qiaolong, a university teacher teaching electronics. Welcome to follow me!