
ES32基于RT-Thread实现HTTP获取网络天气预报
webclient是RT-Thread上的一个开源HTTP/HTTPS协议客户端软件包,利用它可以完成与HTTP/HTTPS服务器的通信。
网上有不少网站提供了JSON格式的实时天气数据,使用的webclient软件包抓取HTTP数据,再用cJSON软件包提取出有效数据就可以实现简单的天气预报功能。
本文将介绍在ES32平台上基于RT-Thread实现HTTP获取网络天气预报。
开始实验前,读者需要首先了解:
☞本实验基于RT-Thread 4.0.4版本,用户可以从GitHub或Gitee获取:
☆从GitHub下载RT-Thread 4.0.4:
https://github.com/RT-Thread/rt-thread/tree/v4.0.4
☆从Gitee下载RT-Thread 4.0.4:
https://gitee.com/rtthread/rt-thread/tree/v4.0.4
基础的软硬件环境配置和ES-CodeMaker使用方法。详细请查看:工程师笔记|ES-CodeMaker for RT-Thread(一)快速上手
☞ ES-CodeMaker for RT-Thread软件的获取方法,在文本的最后给出。
1.硬件配置
需求:ES-PDS-ES32F3696LX开发板、ESP8266 Wi-Fi模块。ESP8266 Wi-Fi模块与开发板的连接如下:
| 模块接口 | 管脚 | 管脚功能 |
|---|---|---|
| RXD | PB6 | UART4_TX |
| TXD | PB7 | UART4_RX |
| IO_0 | VDD | 固定高电平 |
| GND | GND | 电源地 |
| VCC | 5V | 电源5V |
| RST | 浮空或VDD | 固定高电平 |
2.驱动配置
通过CodeMaker可实现可视化的管脚功能配置
-
新建工程, 选择芯片ES32F3696LX,填写工程名称和路径,选择模块 pkg-example-http:

-
开启UART2功能和对应的管脚作为RT-Thread的控制台功能。 -
开启UART4的管脚PB6/PB7,并选择相应的UART功能,可以设置UART设备的名称,设备配置为波特率115200,无校验,1个停止位。


3.RT-Thread配置
接下来配置RT-Thread驱动,开启外设功能并配置参数,以下以Keil+ENV配置为例说明如何进行配置
1. 在bsp的根目录打开ENV工具。
2. 输入menuconfig配置工程。
RT-Thread内核配置
RT-Thread Kernel设置系统的tick。将tick频率调整到1000。

RT-Thread Kernal -> Kernel Device Object进行内核设备对象设置。将控制台的设备名改为“uart2”。

-
rt-thread组件配置
RT-Thread Components -> Device Drivers进行设备驱动设置。
USING Serial device drivers中修改Set RX buffer size增大serial设备的接收缓存,建议增大到4096。因为MCU与ESP8266通信过程中可能收发大量数据。

使用NTP软件包必须使能Using RTC device drivers,否则会报错。

-
rt-thread 软件包 AT DEVICE 配置
RT-Thread online packages -> IoT - internet of things -> AT DEVICE:RT...device开启 AT DEVICE 软件包。AT DEVICE 包含不同 AT 设备的移植文件和示例代码。可通过 AT 命令实现标准 socket 编程接口,完成 socket 通讯的功能。
RT-Thread online packages -> IoT - internet of things -> AT DEVICE:RT...device -> Espressif ESP8266进入esp8266详细的设置界面,可配置wifi账号密码、与esp8266通信的uart的设备名等。

-
rt-thread 软件包 cJSON 配置
RT-Thread online packages -> language packages -> JSON: Java...format -> cJSON:Utra...in ANSI C开启 cJSON 软件包。cJSON 是超轻量级的 C 语言 json 解析库。

-
rt-thread 软件包 netutils 配置
RT-Thread online packages -> IoT - internet of things -> netutils:Net...RT-Thread开启 netutils 软件包。netutils 网络小工具集中的 NTP(时间同步)小工具可以通过网络获取本地时间,并同步板子的 RTC 时间。

在 msh 中输入 ntp_sync 即可从默认的 NTP 服务器 (cn.ntp.org.cn) 获取本地时间,默认时区为东八时区msh />ntp_sync
如果输入 ntp_sync 后提示超时或者连接失败,可以在 ntp_sync 后面输入 NTP 服务器地址,程序将从新的服务器获取时间。
msh />ntp_sync edu.ntp.org.cn

-
rt-thread 软件包 WebClient配置
RT-Thread online packages -> IoT - internet of things -> WebClient: A...RT-Thread

-
HTTP/HTTPS客户端示例代码
RT-Thread online packages -> miscellaneous packages -> samples...samples -> a network...rt-thread

-
UART 配置
Hardware Drivers Config -> On-chip Peripheral Drivers -> UART Drivers 开启uart2(与控制台通信),uart4(与ESP8266 WiFi模块通信)。

-
RTC配置
Hardware Drivers Config -> On-chip Peripheral Drivers -> RTC Drivers 开启rtc,使用rtc组件必须开启rtc。

3. 输入pkgs --update命令更新软件包。然后根据 “5.程序修改说明” 优化软件包的部分接口。
4. 输入scons --target=mdk5命令生成Keil5工程。(使用IAR等其他平台指定--target=xxx即可)
5. 使用Keil5打开工程,编译并下载。在Keil5里必须勾选Use MicroLIB。

4.实验现象
在程序运行后RT-Thread控制台输出如下信息:

如图,Wi-Fi模块会先连接无线无线网络,连上网络后会尝试从NTP服务器获取当前时间。
在控制台输入weather并回车,控制台会输出天气信息。
5.程序修改说明
src\kservice.c里添加如下代码,否则编译会报错。/**
* This function will copy string.
*
* @param dst points to the address used to store the copied content.
*
* @param src is the string to be copied.
*
* @return The address where the copied content is stored.
*/
char *rt_strcpy(char *dst, const char *src)
{
char *dest = dst;
while (*src != '\0')
{
*dst = *src;
dst++;
src++;
}
*dst = '\0';
return dest;
}
RTM_EXPORT(rt_strcpy);
另外需要修改文件include\rtthread.h,增加下面两句话:char *rt_strcpy(char *dst, const char *src); #define rt_strcpy(dest, src) strcpy(dest, src)
由于RT-Thread官方例程里原来使用的天气API网站已经失效,需要修改文件packages\network_samples-v0.3.0\httpclient_sample.c里的网址,并相应修改weather_data_parse函数。
修改前:
#define GET_HEADER_BUFSZ 1024 //头部大小
#define GET_RESP_BUFSZ 1024 //响应缓冲区大小
#define GET_URL_LEN_MAX 256 //网址最大长度
#define GET_URI "http://mobile.weather.com.cn/data/sk/%s.html" //获取天气的 API
#define AREA_ID "101021200" //上海徐汇 ID
/* 天气数据解析 */
void weather_data_parse(rt_uint8_t *data)
{
cJSON *root = RT_NULL, *object = RT_NULL, *item = RT_NULL;
root = cJSON_Parse((const char *)data);
if (!root)
{
rt_kprintf("No memory for cJSON root!\n");
return;
}
object = cJSON_GetObjectItem(root, "sk_info");
item = cJSON_GetObjectItem(object, "cityName");
rt_kprintf("\ncityName:%s ", item->valuestring);
item = cJSON_GetObjectItem(object, "temp");
rt_kprintf("\ntemp :%s ", item->valuestring);
item = cJSON_GetObjectItem(object, "wd");
rt_kprintf("\nwd :%s ", item->valuestring);
item = cJSON_GetObjectItem(object, "ws");
rt_kprintf("\nws :%s ", item->valuestring);
item = cJSON_GetObjectItem(object, "sd");
rt_kprintf("\nsd :%s ", item->valuestring);
item = cJSON_GetObjectItem(object, "date");
rt_kprintf("\ndate :%s", item->valuestring);
item = cJSON_GetObjectItem(object, "time");
rt_kprintf("\ntime :%s \n", item->valuestring);
if (root != RT_NULL)
cJSON_Delete(root);
}
修改后:
#define GET_HEADER_BUFSZ 1024 //头部大小
#define GET_RESP_BUFSZ 1024 //响应缓冲区大小
#define GET_URL_LEN_MAX 256 //网址最大长度
#define GET_URI "http://api.k780.com:88/?app=weather.today&weaid=%s&appkey=10003&sign=b59bc3ef6191eb9f747dd4e83c99f2a4&format=json" //获取天气的 API
//备份网址:" http://t.weather.itboy.net/api/weather/city/101021200"
#define AREA_ID "101021200" //上海徐汇 ID
/* 天气数据解析 */
void weather_data_parse(rt_uint8_t *data)
{
cJSON *root = RT_NULL, *object = RT_NULL, *item = RT_NULL;
root = cJSON_Parse((const char *)data);
if (!root)
{
rt_kprintf("No memory for cJSON root!\n");
return;
}
object = cJSON_GetObjectItem(root, "result");
item = cJSON_GetObjectItem(object, "citynm");
rt_kprintf("\n城市:%s ", item->valuestring);
item = cJSON_GetObjectItem(object, "temperature");
rt_kprintf("\n温度 :%s ", item->valuestring);
item = cJSON_GetObjectItem(object, "temperature_curr");
rt_kprintf("\n当前温度 :%s ", item->valuestring);
item = cJSON_GetObjectItem(object, "weather_curr");
rt_kprintf("\n当前天气 :%s ", item->valuestring);
item = cJSON_GetObjectItem(object, "wind");
rt_kprintf("\n风向 :%s ", item->valuestring);
item = cJSON_GetObjectItem(object, "winp");
rt_kprintf("\n风速 :%s ", item->valuestring);
item = cJSON_GetObjectItem(object, "humidity");
rt_kprintf("\n湿度 :%s ", item->valuestring);
item = cJSON_GetObjectItem(object, "days");
rt_kprintf("\n日期 :%s \n", item->valuestring);
if (root != RT_NULL)
cJSON_Delete(root);
}
6.如何获取 ES-CodeMaker for RT-Thread?
扫描下方二维码关注“东软载波微电子”微信公众号,发送口令 CodeMaker 即可获取下载链接。


