835|1

309

帖子

3

资源

纯净的硅(中级)

【平头哥RVB2601创意应用开发】实践7-U8g2库显示网络天气和时间 [复制链接]

本篇介绍了RVB2601连网获取天气以及RTC功能,将天气和时间显示到OLED屏幕中。

IMG_20220508_184927.jpg

1 RTC时钟功能

参考YOC文档:https://yoc.docs.t-head.cn/yocbook/Chapter3-AliOS/CSI%E8%AE%BE%E5%A4%87%E9%A9%B1%E5%8A%A8%E6%8E%A5%E5%8F%A3/CSI1/RTC.html

RTC(Real_Time Clock)实时时钟为系统提供可靠的时间基准, 一般有独立的晶振和电源,保证主电源掉电时还可以工作。 RTC 一般可以提供日历格式的时间。

虽然RVB2601的RTC没有配置电池,掉电后时间就没了,但RVB2601的连网功能,可以在每次开机时,通过获取网络时间,来为RTC重新校准时间。

1.1 RTC时间结构体

csi_rtc_time_t

成员 类型 说明
tm_sec int 秒 取值范围[0-59]
tm_min int 分 取值范围[0-59]
tm_hour int 小时 取值范围[0-23]
tm_mday int 天 取值范围[1-31]
tm_mon int 月 取值范围[0-11]
tm_year int 年 取值范围[70-199]
tm_wday int 周 取值范围[0-6]
tm_yday int 一年中的第几天 取值范围[0-365]

例:设置2020年1月13日23点59分59秒则如下配置:

rtctime.tm_year = 120; //2020-1900 = 120
rtctime.tm_mon = 0;    //0-11
rtctime.tm_mday = 13;  //1-31
rtctime.tm_hour = 23;  //0-23
rtctime.tm_min = 59;   //0-59
rtctime.tm_sec = 59;   //0-59

1.2 API函数

RTC的CSI接口在用户对接时是否必须适配的说明如下所示:

函数 功能 是否必须适配
csi_rtc_init 初始化 必须
csi_rtc_uninit 反初始化 必须
csi_rtc_set_time 设置时间(需要同步时间) 必须
csi_rtc_set_time_no_wait 设置时间(不需要同步时间) 非必须
csi_rtc_get_time 获取当前时间 必须
csi_rtc_get_alarm_remaining_time 获取距离闹钟剩余时间 非必须
csi_rtc_set_alarm 设置闹钟 非必须
csi_rtc_cancel_alarm 取消闹钟 非必须
csi_rtc_is_running 获取工作状态 非必须

主要函数

参考官方文档,编写RTC时间获取任务。

static void rtc_clock_task(void * arg)
{
    csi_rtc_time_t now_time;
    int last_sec = -1;
    
    rtc_clock_init();
    
    if(rtc_clock_queue_init() != 0)
    {
        LOGD(TAG, "creat queue:rtc_clock_queue failed\r\n ");
    }
    
    LOGD(TAG, "GET weather_update_done_sem \r\n ");
    aos_sem_wait(&weather_update_done_sem, AOS_WAIT_FOREVER);
​
    while(1)
    {   
        if(CSI_OK != csi_rtc_get_time(&g_rtc, &now_time))
        {
            LOGD(TAG, "===%s, %d", __FUNCTION__, __LINE__);
            return ;        
        }
        else
        {
            if (now_time.tm_sec != last_sec)
            {
                now_time.tm_year += 1900;
                now_time.tm_mon += 1;
                LOGD(TAG, "Time: %d-%d-%d  %d:%d:%d\n", now_time.tm_year, now_time.tm_mon,
                        now_time.tm_mday, now_time.tm_hour, now_time.tm_min, now_time.tm_sec);
                
                aos_queue_send(&rtc_clock_queue, &now_time, sizeof(csi_rtc_time_t));
                
                last_sec = now_time.tm_sec;
            }
        }
        aos_msleep(300);    
    }
}

注意这里我没300ms获取一次RTC时间,当发现“秒”数据变化时,通过消息队列发送给OLED模块使其更新时间,这样,OLED只需1s更新一次即可,避免不必要的循环刷新OLED显示。

2 NTP网络授时

参考YOC文档:https://yoc.docs.t-head.cn/yocbook/Chapter5-%E7%BB%84%E4%BB%B6/%E7%BD%91%E7%BB%9C%E7%BB%84%E4%BB%B6/NTP.html

文档里关于此部分的介绍较少,并且已有网友分享使用NTP时有许多坑,本篇暂不使用NTP功能。

那想要获取实际的时间,怎么办呢?在使用下面的连网获取天气的过程中,发现在获取天气时,同时会获取到一个天气更新的时间(实测发现,网上的天气信息差不多是每隔十多分钟更新一次),所以,可以使用这个时间作为RTC的校准时间(虽然会有几分钟的偏差,但作为测试使用还是可以的)。

3 连网获取天气

3.1 获取天气信息

获取网络天气,已经有许多网友尝试过了,我参考这篇:【平头哥RVB2601创意应用开发】RVB2601之获取天气小工具

需要在高德开发平台上注册开发者账号,通过自己Key,以及通过http协议获取网络天气,并通过json数据解析获取具体的天气和温度以及更新时间等信息。

按照网友的做法,通过连上网时获取一起天气,以及后续的按键发送信号量,触发一次网络天气获取,然后对json格式的天气数据进行解析。

static void parse_http_data(char *http_data)
{
    app_weather_t app_weather_data;
​
    cJSON *root;
    cJSON *status;
    cJSON *lives;
    cJSON *tmp_obj; 
    cJSON *live_obj;
    char *str_tmp;
    int size;
​
    root = cJSON_Parse(http_data);
    if(root)
    {
        LOGD(TAG, "========>JSON_data:\n%s\n", cJSON_Print(root));
        status = cJSON_GetObjectItem(root, STATUS);
        if(status)
        {
            LOGD(TAG, "status:%d,%s\r\n",atoi(status->valuestring), status->valuestring);
            lives = cJSON_GetObjectItem(root, LIVES);
            if(lives)
            { 
                size = cJSON_GetArraySize(lives);
                LOGD(TAG, "!!size:%d\r\n",size);
                for(int i=0;i<size;i++)
                {
                    live_obj = cJSON_GetArrayItem(lives, i);
                    if(live_obj)
                    {
                        tmp_obj = cJSON_GetObjectItem(live_obj, WEATHER);
                        str_tmp = translate_weather_type_in_ascii(tmp_obj->valuestring);
                        sprintf(app_weather_data.info, "%s", str_tmp); 
                        free(str_tmp);
                        LOGD(TAG, "weather: %s\r\n",app_weather_data.info);
​
                        tmp_obj = cJSON_GetObjectItem(live_obj, TIME);
                        sprintf(app_weather_data.time, "%s", tmp_obj->valuestring); 
                        LOGD(TAG, "data: %s\r\n",app_weather_data.time);
                        
                        int year, mon, day, h, m, s;
                        sscanf(tmp_obj->valuestring, "%d-%d-%d %d:%d:%d", &year, &mon, &day, &h, &m, &s); 
                        LOGD(TAG, "year:%d mon:%d day:%d h:%d m:%d s:%d\r\n", year, mon, day, h, m, s);
                        rtc_update_time(year, mon, day, h, m, s); //更新RTC时间
                        aos_sem_signal(&weather_update_done_sem); //通知RTC时间已被同步
                                                
                        tmp_obj = cJSON_GetObjectItem(live_obj, TEMP);
                        app_weather_data.temperature = atoi(tmp_obj->valuestring); 
                        LOGD(TAG, "temperature: %d\r\n",app_weather_data.temperature);
                    }
                }
            }
        }
    }
    cJSON_Delete(root); 
    event_publish(EVENT_WEATHER_UPDATE, &app_weather_data); //发布天气更新的时间
}

这里我增加了一些功能:

  • 在每次触发天气更新后,解析到时间数据后,更新一下RTC的校准时间,这样每次连网更新天气时,时间也被更新了

  • 在每次触发天气更新后,更新完RTC的校准时间后,再触发一个信号量,表示RTC时间已被同步,这个的作用是用来在刚开始的时候,还没连上网之前,因为时间没同步,没法显示正确的时间,这时OLED屏幕上就可以先显示等待WIFI连接之类的提示,等RTC时间校准之后,再显示时间和天气

  • 在每次触发天气更新后,解析到天气数据后,改为主题推送的方式来让OLED模块来更新天气数据(这位网友之前使用的是消息队列的方式)

3.2 OLED显示时间和天气

参考网上的一篇天气时间的UI设计:https://www.arduino.cn/thread-98403-1-1.html

利用U8g2库来显示不同大小的字体,以及天气图标(U8g2的字体库中自带了一些天气图标,可以直接用),另外,U8g2库也是有汉字库的,只是汉字库占用的空间比较大,使用之后就编译出错了,那就先不显示汉字吧。

UI界面的主要显示函数:

void testShowTimeAndWeather(u8g2_t *u8g2, csi_rtc_time_t *now_time)
{
    u8g2_ClearBuffer(u8g2);
    
    int year = now_time->tm_year;
    int month = now_time->tm_mon;
    int day = now_time->tm_mday;
    int hour = now_time->tm_hour;
    int minute = now_time->tm_min;
    int sec = now_time->tm_sec;
    
    //时分
    char str_big_time[] = "";
    my_strcat(str_big_time, hour);
    strcat(str_big_time,":");
    my_strcat(str_big_time, minute);
    u8g2_SetFont(u8g2, u8g2_font_logisoso24_tf ); 
    u8g2_DrawStr(u8g2, 0, 34, str_big_time);
​
    //秒
    char str_small_sec[] = "";
    my_strcat(str_small_sec, sec);
    u8g2_SetFont(u8g2, u8g2_font_wqy12_t_chinese1 ); 
    u8g2_DrawStr(u8g2, 72, 34, str_small_sec);
​
    //日期
    char str_date[] = "";
    char str_temp[6];
    itoa(year,str_temp,10);
    strcat(str_date,str_temp);
    strcat(str_date,"-");
    my_strcat(str_date, month);
    strcat(str_date,"-");
    my_strcat(str_date, day);
    u8g2_SetFont(u8g2,u8g2_font_wqy12_t_chinese1);
    u8g2_DrawStr(u8g2, 0, 54, str_date);
​
    //分割线
    u8g2_DrawLine(u8g2, 88, 2, 88, 61);
    
    //天气
    u8g2_SetFont(u8g2, u8g2_font_open_iconic_weather_4x_t );
    u8g2_DrawStr(u8g2, 96, 34, icon_index[g_iWeatherIconIdx]);
    u8g2_SetFont(u8g2, u8g2_font_wqy16_t_chinese1);
    char b_b_tmp[25];
    itoa(g_iTemperature, b_b_tmp, 10);
    strcat(b_b_tmp," C");
    u8g2_DrawStr(u8g2, 96, 55, b_b_tmp);
  
    u8g2_SendBuffer(u8g2);
    aos_msleep(1000);
}

4 测试效果


 

5 总结

本篇介绍了RVB2601连网获取天气,并更新RTC时间,以及最终将天气图形,温度数据和时间日期显示到OLED屏幕上。

 


回复

2601

帖子

3

资源

版主

辛苦了,这帖子写得工整,让人看了有特舒服的感觉,知识面介绍也非常丰富,感谢分享。


回复
您需要登录后才可以回帖 登录 | 注册

相关帖子
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
    关闭
    站长推荐上一条 1/7 下一条

    About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

    站点相关: 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

    北京市海淀区知春路23号集成电路设计园量子银座1305 电话:(010)82350740 邮编:100191

    电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2022 EEWORLD.com.cn, Inc. All rights reserved
    快速回复 返回顶部 返回列表