STM32-心知天气项目

news/2025/2/23 10:42:35

一、项目需求

使用 ESP8266 通过 HTTP 获取天气数据(心知天气),并显示在 OLED 屏幕上。
按键 1 :循环切换今天 / 明天 / 后天天气数据;
按键 2 :更新天气。

二、项目框图

三、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)//判断返回值是否是ok
        return ESP8266_EOK;
    else
        return 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;
        }
    }


http://www.niftyadmin.cn/n/5863335.html

相关文章

人工智能三剑客:符号主义、连接主义与行为主义的较量与融合

文章目录 1. 符号主义人工智能&#xff1a;逻辑与规则的智慧1.1 核心思想1.2 示例&#xff1a;专家系统配图说明&#xff08;PlantUML&#xff09;&#xff1a; 1.3 存在的问题1.4 训练方法 2. 连接主义人工智能&#xff1a;神经网络的崛起2.1 核心思想2.2 示例&#xff1a;深度…

java如何排查线上问题

在Java线上环境中排查故障需要系统化的方法和合适的工具&#xff0c;以下是详细的排查步骤及常用工具&#xff1a; 快速确认问题现象 明确症状&#xff1a;确认是CPU飙升、内存泄漏、线程阻塞、响应超时&#xff0c;还是频繁Full GC。 查看监控&#xff1a;使用Prometheus、Gr…

C/C++跳动的爱心

系列文章 序号直达链接1C/C李峋同款跳动的爱心2C/C跳动的爱心3C/C经典爱心4C/C满屏飘字5C/C大雪纷飞6C/C炫酷烟花7C/C黑客帝国同款字母雨8C/C樱花树9C/C奥特曼10C/C精美圣诞树11C/C俄罗斯方块小游戏12C/C贪吃蛇小游戏13C/C孤单又灿烂的神14C/C闪烁的爱心15C/C哆啦A梦16C/C简单…

MySQL要点总结一

大纲 一.InnoDB的内存结构和更新机制 二.InnoDB的存储模型 三.并发事务原理 四.索引原理和索引优化 一.InnoDB的内存模型 1.SQL的执行流程 2.InnoDB的内存模型 3.Buffer Pool中的空闲缓存页与free链表 4.Buffer Pool中的脏页和flush链表 5.Buffer Pool通过LRU链表来淘…

antv G6绘制流程图

效果图&#xff08;优点&#xff1a;可以自定义每一条折线的颜色&#xff0c;可以自定义节点的颜色&#xff0c;以及折线的计算样式等&#xff09;&#xff1a; 代码&#xff1a; <!-- 流程图组件 --> <template><div id"container"></div>…

前端面试-JavaScript 数据类型详解

目录 一、数据类型分类 二、核心区别对比 1. 存储方式 2. 比较方式 3. 类型检测方法 三、特殊类型详解 1. Symbol 2. BigInt 3. null vs undefined 四、常见面试扩展问题 五、总结 一、数据类型分类 JavaScript 数据类型分为 基本数据类型&#xff08;原始类型&…

hot100_74. 搜索二维矩阵

hot100_74. 搜索二维矩阵 思路 给你一个满足下述两条属性的 m x n 整数矩阵&#xff1a; 每行中的整数从左到右按非严格递增顺序排列。 每行的第一个整数大于前一行的最后一个整数。 给你一个整数 target &#xff0c;如果 target 在矩阵中&#xff0c;返回 true &#xff1b;否…

网络空间安全(2)应用程序安全

前言 应用程序安全&#xff08;Application Security&#xff0c;简称AppSec&#xff09;是一个综合性的概念&#xff0c;它涵盖了应用程序从开发到部署&#xff0c;再到后续维护的整个过程中的安全措施。 一、定义与重要性 定义&#xff1a;应用程序安全是指识别和修复应用程序…