摘要
- 这个桌面小盒子是之前的东西,一直放着没有整理好。最近有空了就把他整理整理。
- 小盒子主要用来显示时间和天气预报,功能比较简单,其实还有很多可以玩的,懒得弄,所以就把最简单的整理出来。
- 软件是基于rt-thread, UI采用lvgl。
功能主要分为两个部分
第一部分--功能
功能部分主要分为两个部分,一个是NTP获取实时时间,一个是天气等信息。
- NTP比较简单,RTT提供了相关API。代码如下:
代码语言:javascript
复制void get_local_time(void)
{
time_t now;
now = time(RT_NULL);
tab_info.cur_tm = localtime(&now);
rt_kprintf("time: -:-", tab_info.cur_tm->tm_hour, tab_info.cur_tm->tm_min);
}
- 获取天气信息,这个也比较简单,通过调用tianqiapi既可以获得。代码如下:
代码语言:javascript
复制#define GET_WEATHER_URI "http://www.tianqiapi.com/api/?version=v6&cityid=101280601&appid=65251531&appsecret=Yl2bzCYb"
struct weather_info
{
char *response;
cJSON *root;
cJSON *date;
cJSON *cur_temp;
cJSON *humidity;
cJSON *wea_img;
};
int rp_weather_info_get(void)
{
char *uri = RT_NULL;
uri = web_strdup(GET_WEATHER_URI);
if (webclient_request(uri, RT_NULL, RT_NULL, (unsigned char **)&info.response) < 0)
{
rt_kprintf("get weather fail!n");
return -RT_ERROR;
}
info.root = cJSON_Parse(info.response);
if(info.root != RT_NULL)
{
info.date = cJSON_GetObjectItem(info.root, "date");
info.cur_temp = cJSON_GetObjectItem(info.root, "tem");
info.humidity = cJSON_GetObjectItem(info.root, "humidity");
info.wea_img = cJSON_GetObjectItem(info.root, "wea_img");
rt_kprintf("date : %s, cur_temp : %s, humidity : %s, wea_img : %sn",
info.date->valuestring, info.cur_temp->valuestring,
info.humidity->valuestring, info.wea_img->valuestring);
}
return RT_EOK;
}
void rp_weather_info_free(void)
{
if (info.response != RT_NULL)
{
web_free(info.response);
}
if(info.root != RT_NULL)
{
cJSON_Delete(info.root);
info.root = RT_NULL;
}
}
第二部分--UI
- UI方面我使用了LVGL,这个开始比较方便的UI框架,可移植性搞。网上的教程也比较多。
- 由于rt-thread的LVGL软件包比较旧,而且有些东西没有移植好,所以我自己根据我的平台重新移植一份。
- 根据LVGL移植流程,需要对接porting下源文件的API回调。主要包含,disp(显示)、indev(输入设备,如触摸,按键)、fs(文件系统)。而本项目只对接disp(显示)、fs(文件系统, 读取SD卡的图片资源)
- 其中fs的代码,文件系统我对接的dfs_posix的接口,因为我只使用读文件操作,所以直接对接部分接口,代码如下:
代码语言:javascript
复制static lv_fs_res_t fs_open(lv_fs_drv_t * drv, void * file_p, const char * path, lv_fs_mode_t mode)
{
lv_fs_res_t res = LV_FS_RES_NOT_IMP;
int fd = 0;
if(mode == LV_FS_MODE_RD)
{
if((fd = open(path, O_RDONLY)) > 0)
{
*(file_t *)file_p = fd;
res = LV_FS_RES_OK;
}
else
{
res = LV_FS_RES_NOT_EX;
}
}
return res;
}
static lv_fs_res_t fs_close (lv_fs_drv_t * drv, void * file_p)
{
lv_fs_res_t res = LV_FS_RES_UNKNOWN;
int fd = *(file_t *)file_p;
if (close(fd) == 0)
{
res = LV_FS_RES_OK;
}
return res;
}
static lv_fs_res_t fs_read (lv_fs_drv_t * drv, void * file_p, void * buf, uint32_t btr, uint32_t * br)
{
lv_fs_res_t res = LV_FS_RES_UNKNOWN;
int fd = *(file_t *)file_p;
int read_bytes = read(fd, buf, btr);
if (read_bytes >= 0)
{
*br = read_bytes;
res = LV_FS_RES_OK;
}
return res;
}
static lv_fs_res_t fs_seek (lv_fs_drv_t * drv, void * file_p, uint32_t pos)
{
lv_fs_res_t res = LV_FS_RES_UNKNOWN;
int fd = *(file_t *)file_p;
if (lseek(fd, pos, SEEK_SET) >= 0)
{
res = LV_FS_RES_OK;
}
return res;
}
static lv_fs_res_t fs_tell (lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p)
{
lv_fs_res_t res = LV_FS_RES_UNKNOWN;
int fd = *(file_t *)file_p;
off_t pos = lseek(fd, 0, SEEK_CUR);
if (pos >= 0)
{
*pos_p = pos;
res = LV_FS_RES_OK;
}
return res;
}
void lv_port_fs_init(void)
{
lv_fs_drv_t fs_drv;
fs_init();
lv_fs_drv_init(&fs_drv);
fs_drv.file_size = sizeof(file_t);
fs_drv.letter = 'S';
fs_drv.open_cb = fs_open;
fs_drv.close_cb = fs_close;
fs_drv.read_cb = fs_read;
fs_drv.seek_cb = fs_seek;
fs_drv.tell_cb = fs_tell;
lv_fs_drv_register(&fs_drv);
}
- disp代码,因为是软件SPI,所以我采用的是整屏刷新。
代码语言:javascript
复制static void disp_init(void)
{
}
static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
int32_t x;
int32_t y;
rt_uint8_t *frame_buffer = (rt_uint8_t *)psram_malloc(240 * 240 * 2);
if(frame_buffer !=RT_NULL)
{
for(y = area->y1; y <= area->y2; y )
{
for(x = area->x1; x <= area->x2; x )
{
frame_buffer[(y * 240 * 2) (x * 2)] = color_p->full >> 8;
frame_buffer[(y * 240 * 2) (x * 2 1)] = color_p->full;
color_p ;
}
}
lcd_show_page((rt_uint8_t *)frame_buffer);
psram_free(frame_buffer);
frame_buffer = RT_NULL;
}
lv_disp_flush_ready(disp_drv);
}
void lv_port_disp_init(void)
{
lv_disp_drv_t disp_drv;
disp_init();
static lv_disp_buf_t draw_buf_dsc;
static lv_color_t draw_buf[LV_HOR_RES_MAX * LV_VER_RES_MAX];
lv_disp_buf_init(&draw_buf_dsc, draw_buf, NULL, LV_HOR_RES_MAX * LV_VER_RES_MAX);
lv_disp_drv_init(&disp_drv);
disp_drv.hor_res = LV_HOR_RES_MAX;
disp_drv.ver_res = LV_VER_RES_MAX;
disp_drv.flush_cb = disp_flush;
disp_drv.buffer = &draw_buf_dsc;
lv_disp_drv_register(&disp_drv);
}
- 这个盒子的UI设计比较简单,主要实现在main_tab_hander中实现,会先调用同步一下时间和天气信息。然后创建了一个task,来更新页面信息。
代码语言:javascript
复制void get_main_tab_info(void)
{
char hour_h[2] = {'0', '