一、项目需求

二、项目框图
三、cjson作用
https://github.com/DaveGamble/cJSON/releases/tag/v1.7.18
cjson可以把json代码来回解析和打包
cjson的移植
1、把cjson拷贝到项目文件中
2、#include添加cjson头文件
3、根据自己的需求修改堆栈
四、项目实现
4.1 项目前期准备
加载文件
在主函数中写入头文件和初始化函数
4.2 修改oled文件
先从oled开始修改
取字模
在心知天气平台中可以看到有39种天气
这里只取晴、多云、阴、雨,雪五种天气,也可以按需求自己取天气
生成字模,放到font.h文件中
修改oled中显示汉字的代码
别忘了修改.h文件
编译之后--无错误
接下来将oled的排版排一下
重新定义一个函数
别忘了在oled.h文件中加入函数
主函数中调用一下函数名,就可以显示(可以先把esp8266的初始化函数先注释掉,太浪费时间)
显示结果如下:
4.3 修改esp8266文件
剩下的信息就要从json包中获取了
日期、天气状态、温度
需要修改esp8266代码,通过http协议访问心知天气平台,利用cjosn包解析想要的信息
esp8266是通过串口2来传递信息的,所以在uart1.c文件中需要加入串口2的应用
打开项目文件36-编程实现ESP8266连接TCP服务器
复制这段代码到本项目中的uart1.c
如何获取心知天气的天气呢?
在心知天气中,可以获取一个关于天气的api
将这个api丢到浏览器上,就可以看到关于天气的json包
这个过程就是http请求。
那么esp8266如何发起一个http的请求呢?
直接通过esp8266把api给发送(send)出去
代码如下:
//获取天气的信息,从天这个单位来获取,某一天day
uint8_t esp8266_get_weather(uint8_t day)
{//4、定义一个变量判断返回值是否是正确的uint8_t ret = ESP8266_ERROR;//默认返回值为error//1、构建HTTP请求的数据包,存放api的char http_request[200] = {0};//2、使用sprintf将api丢到数据包数组中,前面加一个GET,获取这个API包sprintf(http_request,"GET https://api.seniverse.com/v3/weather/daily.json?key=S35Rrryu2DExg-Hku&location=beijing&language=zh-Hans&unit=c&start=%d&days=3\r\n",day);//3、如何判断发给服务器的数据发送成功?//进入到获取数据这部分了,通过串口将数据发送到服务器上,ret = esp8266_send_command(http_request,"results");//同时期待返回值results//打印出来结果printf("%s\r\n",esp8266_rx_buf);if(ret == ESP8266_EOK)//判断返回值是否是okreturn ESP8266_EOK;elsereturn ESP8266_ERROR;}//复制RX引脚接收到的信息--目的是避免使用了extern
uint16_t esp8266_copy_rxdata(char *data)
{//将数据复制到data中memcpy(data, esp8266_rx_buf, esp8266_cntPre);return esp8266_cntPre;
}
要修改心知天气的地址和端口号
主函数
扩大长度
结果如下所示:
4.4 解析提取JSON数据包中需要的信息
根据自己的需求修改堆栈
新建文件weather
加载项目文件
头文件
新建的weather是用来书写天气的信息的
代码如下:
void get_3days_weather(void)
{uint8_t i = 0;for(i = 0; i < 3; i++){memset(weather_data, 0, sizeof(weather_data));esp8266_get_weather(i);esp8266_copy_rxdata(weather_data);//1. 将JSON字符串转换成JSON结构体cJSON *cjson = cJSON_Parse((const char *)weather_data);//2. 解析JSON各个字段//2.1 获取根对象里的results字段的值(数组1)cJSON *results = cJSON_GetObjectItem(cjson, "results");//2.2 获取数组1的第一个元素(对象1)cJSON *first_result = cJSON_GetArrayItem(results, 0);//2.3 获取对象1中的daily字段的值(数组2)cJSON *daily = cJSON_GetObjectItem(first_result, "daily");//2.4 获取数组2中的第一个元素(对象2)cJSON *first_daily = cJSON_GetArrayItem(daily, 0);//2.5 获取对象2中的data字段的值cJSON *date = cJSON_GetObjectItem(first_daily, "date");const char *date_str = date->valuestring;printf("date: %s\r\n", date_str);strcpy(three_day_weather[i].date, date_str);//2.6 获取对象2中的code_day字段的值cJSON *code_day = cJSON_GetObjectItem(first_daily, "code_day");const char *code_day_str = code_day->valuestring;printf("code_day: %s\r\n", code_day_str);strcpy(three_day_weather[i].code_day, code_day_str);//2.7 获取对象2中的high字段的值cJSON *high = cJSON_GetObjectItem(first_daily, "high");const char *high_str = high->valuestring;printf("high: %s\r\n", high_str);strcpy(three_day_weather[i].high, high_str);//2.8 获取对象2中的low字段的值cJSON *low = cJSON_GetObjectItem(first_daily, "low");const char *low_str = low->valuestring;printf("low: %s\r\n\r\n", low_str);strcpy(three_day_weather[i].low, low_str);//3. 清除JSON结构体cJSON_Delete(cjson);delay_ms(1000);}
}
在主函数中和.h文件中调用一下,应该会产生的结果是:
这里注意,如果产生的结果全部是乱码,或者部分信息是乱码,如下图所示:
这就有可能是你的堆栈没有设置足够
详情见下面链接
CSDN
扩大堆的空间只后,即可正确显示数据
最后我这里堆增加到了0x00001C00
4.5 显示天气
接下来就是显示天气,在主函数的while循环中判断按下的key键
代码如下:
void show_weather(uint8_t day)
{oled_show_init();oled_show_string(10,0,three_day_weather[day].date,16);//将字符串的”11“转变成数字的”11 “uint8_t code_day = atoi(three_day_weather[day].code_day);switch(code_day){case 0:case 1:case 2:case 3:oled_show_chinese(77, 2, 8); //晴break;case 4:case 5:case 6:case 7:case 8:oled_show_chinese(77, 2, 9); //多oled_show_chinese(90, 2, 10); //云break;case 9:oled_show_chinese(77, 2, 11); //阴break;case 10:case 11:case 12:case 13:case 14:case 15:case 16:case 17:case 18:case 19:case 20:oled_show_chinese(77, 2, 12); //雨break;case 21:case 22:case 23:case 24:case 25:oled_show_chinese(77, 2, 13); //雪break;default:break; }oled_show_string(77,4,three_day_weather[day].high,16);oled_show_string(77,6,three_day_weather[day].low,16);
}
主函数代码如下:
uint8_t key_num = 0;uint8_t day = 0;while(1){ key_num = key_scan();if(key_num == 1)//切换天气{day++;day %= 3;show_weather(day);}else if(key_num == 2)//更新天气{printf("更新天气\r\n");get_3days_weather();show_weather(0);day = 0;}}
心知天气项目