目录:
1.使用RTThread和TouchGFX实现DIY数字仪表(一)——使用STM32CUBMX5.6移植touchGFX4.13
2.使用RTThread和TouchGFX实现DIY数字仪表(二)——把TouchGFX移植到RTThread系统
3.使用RTThread和TouchGFX实现DIY数字仪表(三)——获取温湿度传感器数据
4.使用RTThread和TouchGFX实现DIY数字仪表(四)——同步网络时间
5.使用RTThread和TouchGFX实现DIY数字仪表(五)——同步天气信息
6.使用RTThread和TouchGFX实现DIY数字仪表(六)——链接阿里云物联网平台
7.使用RTThread和TouchGFX实现DIY数字仪表(七)——使用MQTT.fx模拟手机设备进行M2M设备间通信
8.使用RTThread和TouchGFX实现DIY数字仪表(八)——开发微信小程序
9.使用RTThread和TouchGFX实现DIY数字仪表(九)——TouchGFX控件使用教程
实验平台:
硬件: 野火挑战者STM32F767 V1开发版和ESP8266模块
软件: TouchGFXDesigner v4.13和 STM32CubeMX v5.6.0,MDK v5.29,RT-Thread env 工具
实验前准备工作:
1.准备一套 野火挑战者STM32F767 开发版或其他核心板
2.安装 TouchGFXDesigner v4.13
3.安装STM32CubeMX v5.6.0和X_CUBE_TOUCHGFX软件包
4.安装 MDK v5.27以上版本
5.下载 RTThread源码包https://gitee.com/rtthread/rt-thread
6.注册心知天气
下载:
代码持续更新中:github代码下载地址https://gitee.com/Aladdin-Wang/hellotouchGFX.git
联系作者:
加微信备注touchgfx,拉入touchgfx-rtthread技术交流群共同学习
1.注册心知天气获取私钥
2.添加WebClient软件包
由于我们获取天气信息是通过访问心知天气的网络API,所以我们需要开启本地Web客户端。
3.添加CJSON软件包
查看心知天气的API返回数据可知,所使用的数据格式是JSON,所以需要开启CJSON软件包用于解析数据。
4.添加使用代码
weather_httpclient.c
#include <rtthread.h>
#include <webclient.h>
#include <url_code.h>
#include <string.h>
#include "cJSON_util.h"
#include <board.h>
#include <arpa/inet.h>
#include <netdev.h>
#include <ntp.h>
#include <weather_httpclient.h>
#define LOG_TAG "weather"
#define LOG_LVL LOG_LVL_INFO
#include <ulog.h>
#define THREAD_PRIORITY 12
#define THREAD_STACK_SIZE 1024
#define THREAD_TIMESLICE 5
static rt_thread_t tid1 = RT_NULL;
static struct rt_mailbox weather_mb;
static char mb_pool[16];
char *gfxvalue;
#define GET_HEADER_BUFSZ 2048
#define GET_RESP_BUFSZ 2048
#define GET_RESP_CONTENTSZ 4096
#define URL_LEN_MAX 2048
#define GET_LOCAL_URI "http://api.seniverse.com/v3/weather/daily.json?key=S97hL3kj6EbnjEmyC&location=%s&language=zh-Hans&unit=c&start=0&days=5"
#define LOCAL_CITY "beijing"
static weather_t gfx_weather[3];
static void weather_data_parse(char* data)
{
cJSON *root = RT_NULL, *arrayItem = RT_NULL,*object = RT_NULL, *object2 = RT_NULL,*list = RT_NULL, *item = RT_NULL, *weatheritem = RT_NULL;
int index, list_size = 0;
root = cJSON_Parse((const char *)data);
if (!root)
{
rt_kprintf("No memory for cJSON root!\n");
return;
}
arrayItem = cJSON_GetObjectItem(root, "results");
if (arrayItem == RT_NULL)
{
rt_kprintf("cJSON get results failed.");
goto __EXIT;
}
object = cJSON_GetArrayItem(arrayItem, 0);
if (object == RT_NULL)
{
rt_kprintf("cJSON get object failed.");
goto __EXIT;
}
item = cJSON_GetObjectItem(object, "location"); /* 匹配子对象1 */
if (item == RT_NULL)
{
rt_kprintf("cJSON get location failed.");
goto __EXIT;
}
if((list = cJSON_GetObjectItem(item,"name")) != NULL)
{
rt_kprintf("city: %s\r\n",list->valuestring);
}
object2 = cJSON_GetObjectItem(object, "daily"); /* 匹配子对象2 */
if (object2 == RT_NULL)
{
rt_kprintf("cJSON get object2 failed.");
goto __EXIT;
}
int size = cJSON_GetArraySize(object2); //获取数组中对象个数
rt_kprintf("\n");
for(int i = 0 ;i<size;i++ )
{
item = cJSON_GetArrayItem(object2, i);
if (item == RT_NULL)
{
rt_kprintf("cJSON get daily failed.");
goto __EXIT;
}
if((list = cJSON_GetObjectItem(item,"date")) != NULL)
{
rt_kprintf("date: %s\r\n",list->valuestring);
strncpy(gfx_weather[i].date, list->valuestring,strlen(list->valuestring));
}
if((list = cJSON_GetObjectItem(item,"text_day")) != NULL)
{
rt_kprintf("text_day: %s\r\n",list->valuestring);
strncpy(gfx_weather[i].text_day, list->valuestring,strlen(list->valuestring));
}
if((list = cJSON_GetObjectItem(item,"code_day")) != NULL)
{
rt_kprintf("code_day: %s\r\n",list->valuestring);
strncpy(gfx_weather[i].code_day, list->valuestring,strlen(list->valuestring));
}
if((list = cJSON_GetObjectItem(item,"text_night")) != NULL)
{
rt_kprintf("text_night: %s\r\n",list->valuestring);
strncpy(gfx_weather[i].text_night, list->valuestring,strlen(list->valuestring));
}
if((list = cJSON_GetObjectItem(item,"high")) != NULL)
{
rt_kprintf("high: %s\r\n",list->valuestring);
strncpy(gfx_weather[i].high, list->valuestring,strlen(list->valuestring));
}
if((list = cJSON_GetObjectItem(item,"low")) != NULL)
{
rt_kprintf("low: %s\r\n",list->valuestring);
strncpy(gfx_weather[i].low, list->valuestring,strlen(list->valuestring));
}
if((list = cJSON_GetObjectItem(item,"wind_direction")) != NULL)
{
rt_kprintf("wind_direction: %s\r\n",list->valuestring);
strncpy(gfx_weather[i].wind_direction, list->valuestring,strlen(list->valuestring));
}
if((list = cJSON_GetObjectItem(item,"wind_speed")) != NULL)
{
rt_kprintf("wind_speed: %s\r\n",list->valuestring);
strncpy(gfx_weather[i].wind_speed, list->valuestring,strlen(list->valuestring));
}
if((list = cJSON_GetObjectItem(item,"rainfall")) != NULL)
{
rt_kprintf("rainfall: %s\r\n",list->valuestring);
strncpy(gfx_weather[i].rainfall, list->valuestring,strlen(list->valuestring));
}
if((list = cJSON_GetObjectItem(item,"humidity")) != NULL)
{
rt_kprintf("humidity: %s\r\n",list->valuestring);
strncpy(gfx_weather[i].humidity, list->valuestring,strlen(list->valuestring));
}
rt_kprintf("\n");
}
__EXIT:
if (root != RT_NULL)
cJSON_Delete(root);
}
int get_weather(int argc, char **argv)
{
struct webclient_session* session = RT_NULL;
unsigned char *buffer = RT_NULL;
char *URI = RT_NULL;
int index, ret = 0;
int bytes_read, resp_status;
int content_length = -1;
char *city_name = rt_calloc(1,255);
if(argc == 1)
{
strcpy(city_name, LOCAL_CITY);
}
else if (argc == 2)
{
strcpy(city_name, argv[1]);
urlencode(city_name);//对中文编码
}
else if(argc > 2)
{
rt_kprintf("wt [CityName] - webclient GET request test.\n");
return -1;
}
URI = rt_calloc(1, URL_LEN_MAX);
rt_snprintf(URI, URL_LEN_MAX, GET_LOCAL_URI, city_name);
buffer = (unsigned char *) web_malloc(GET_RESP_CONTENTSZ);
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(GET_HEADER_BUFSZ);
if (session == RT_NULL)
{
ret = -RT_ENOMEM;
goto __exit;
}
/* send GET request by default header */
rt_kprintf("send GET request to %s\n", URI);
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;
}
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, GET_RESP_BUFSZ);
if (bytes_read <= 0)
{
break;
}
for (index = 0; index < bytes_read; index++)
{
rt_kprintf("%c", buffer[index]);
}
} while (1);
rt_kprintf("\n");
}
else
{
int content_pos = 0;
do
{
bytes_read = webclient_read(session, buffer+content_pos, GET_RESP_BUFSZ);
if (bytes_read <= 0)
{
break;
}
content_pos += bytes_read;
} while (content_pos < content_length);
weather_data_parse((char*)buffer);
}
__exit:
if (session)
{
webclient_close(session);
}
if (buffer)
{
web_free(buffer);
}
if (URI)
{
web_free(URI);
}
return ret;
}
weather_t *gfxget_weather_date(void)
{
if (rt_mb_recv(&weather_mb, (rt_ubase_t *)&gfx_weather, RT_WAITING_NO) == RT_EOK)
{
return gfx_weather;
}
else
{
return RT_NULL;
}
}
/* 入口函数 */
static void weather_collect_thread_entry(void *parameter)
{
//获取网卡对象
struct netdev* net = netdev_get_by_name("esp0");
//阻塞判断当前网络是否正常连接
while(netdev_is_internet_up(net) != 1)
{
rt_thread_mdelay(200);
}
if(0== get_weather(1,0))
{
rt_mb_send(&weather_mb, (rt_uint32_t)gfx_weather);
}
while(1)
{
rt_thread_mdelay(5000);
rt_mb_send(&weather_mb, (rt_uint32_t)gfx_weather);
}
}
/* 创建线程 */
int weather_collect(void)
{
rt_err_t result = RT_EOK;
/* 初始化mailbox */
result = rt_mb_init(&weather_mb,
"weather_mbt", /* 名称是 sht30_mbt */
&mb_pool[0], /* 邮箱用到的内存池是 mb_pool */
sizeof(mb_pool) / 4, /* 邮箱中的邮件数目,因为一封邮件占 4 字节 */
RT_IPC_FLAG_FIFO); /* 采用 FIFO 方式进行线程等待 */
if (result != RT_EOK)
{
LOG_D("init mailbox failed.\n");
return -1;
}
/* 创建线程*/
tid1 = rt_thread_create("weather",
weather_collect_thread_entry, RT_NULL,
THREAD_STACK_SIZE,
THREAD_PRIORITY, THREAD_TIMESLICE);
/* 如果获得线程控制块,启动这个线程 */
if (tid1 != RT_NULL)
rt_thread_startup(tid1);
return 0;
}
INIT_APP_EXPORT(weather_collect);
#ifdef FINSH_USING_MSH
#include <finsh.h>
MSH_CMD_EXPORT_ALIAS(get_weather, wt, wt [CityName] webclient GET request test);
#endif /* FINSH_USING_MSH */
weather_httpclient.h
#ifndef __WEATHER_H_
#define __WEATHER_H_
#include <rtthread.h>
typedef struct weather {
char date[8];
char text_day[8];
char code_day[8];
char text_night[8];
char high[8];
char low[8];
char wind_direction[8];
char wind_speed[8];
char rainfall[8];
char humidity[8];
} weather_t;
#endif
5. 添加URL转码文件
因中文地名需要URL转码
url_code.c
#include <url_code.h>
//#include <stdio.h>
#include <string.h>
#include <rtthread.h>
#define BURSIZE 1024
static int hex2dec(char c)
{
if ('0' <= c && c <= '9') {
return c - '0';
} else if ('a' <= c && c <= 'f') {
return c - 'a' + 10;
} else if ('A' <= c && c <= 'F') {
return c - 'A' + 10;
} else {
return -1;
}
}
static char dec2hex(short int c)
{
if (0 <= c && c <= 9) {
return c + '0';
} else if (10 <= c && c <= 15) {
return c + 'A' - 10;
} else {
return (char)-1;
}
}
/*
* 编码一个url
*/
void urlencode(char *url)
{
int i = 0;
int len = strlen(url);
int res_len = 0;
char *res = rt_calloc(1, BURSIZE);
for (i = 0; i < len; ++i) {
char c = url[i];
if (('0' <= c && c <= '9') ||
('a' <= c && c <= 'z') ||
('A' <= c && c <= 'Z') || c == '/' || c == '.') {
res[res_len++] = c;
} else {
int j = (short int)c;
if (j < 0)
j += 256;
int i1, i0;
i1 = j / 16;
i0 = j - i1 * 16;
res[res_len++] = '%';
res[res_len++] = dec2hex(i1);
res[res_len++] = dec2hex(i0);
}
}
res[res_len] = '\0';
strcpy(url, res);
rt_free(res);
}
/*
* 解码url
*/
void urldecode(char *url)
{
int i = 0;
int len = strlen(url);
int res_len = 0;
char *res = rt_calloc(1, BURSIZE);
for (i = 0; i < len; ++i) {
char c = url[i];
if (c != '%') {
res[res_len++] = c;
} else {
char c1 = url[++i];
char c0 = url[++i];
int num = 0;
num = hex2dec(c1) * 16 + hex2dec(c0);
res[res_len++] = num;
}
}
res[res_len] = '\0';
strcpy(url, res);
rt_free(res);
}
url_code.h
#ifndef __URL_CODE_H__
#define __URL_CODE_H__
void urlencode(char *url);
void urldecode(char *url);
#endif
6. 实验
来源:oschina
链接:https://my.oschina.net/u/4266314/blog/4262246