作者:Spring123
一、开发板简介
准备平头哥RVB2601开发板来制作一款疫情播报系统应用,先来一张开发板的介绍
二、应用开发初步构想
基于官方网络音乐播放器例程 ch2601_webplayer_demo,由于官方LVGL的功能与音乐播放并存之后对开发板的存储较大,已经超过硬件本身已有的容量,这个得到官方技术确认,那只能另找捷径,移植LCD驱动,再移植U2g8图形库,结合在一起来解决硬件的一些局限。当然还要加载一些必备的组件,例如 cjson,httpclient,webclient
最终实现通过网络读取json数据,进行分解,针对数据字符,播放相应的mp3文件,并在OLED屏幕上显示实际对应数据。
三、移植及增加组件
1、U8g2的移植
正好有大佬写了一篇移植U8g2图形库,测试一下可以通不,如果不考虑瘦身精简的话可以,从u8g2的开源地址 https://github.com/olikraus/u8g2/tree/master/csrc 这个文件夹可以直接引入使用。
2、lcd驱动移植
移植官方TFT LCD屏幕的开发演示例程 ch2601_gui_demo中的LCD驱动两个文件
3、加载必备的组件
主要是cjson,httpclient,webclient
4、确保package.yaml项目配置
package.yaml文件正确,要能正常编译,有一个特别注意点,手动改改,CDK会检测到改动,提示重新加载项目,点是就可以了
三、代码相关
1、返回json数据文件
准备一个能返回json数据格式的文件,这里准备了一个index.php文件,上传到在阿里云购买的网站空间里
<? header("Content-Type: application/json;charset=utf-8"); echo json_encode(array('a'=>'a','country'=>'Japan','number'=>'135'); ?>
2、示例声音mp3文件
准备三个声音文件,一个是启动声音,两个是与网站json字符匹配的声音文件,根据精细度,还可以再拆分成字母音和数字音,这里是示例没有具体完全展开。上传到在阿里云购买的网站空间
3、app_main.c主文件调整
增加获取网络上的json数据,并让开机提示音延长6秒之后播放,确保网络正确连接之后正常获得网络音频文件资源
/* * Copyright (C) 2019-2020 Alibaba Group Holding Limited */ #define _DEFAULT_SOURCE /* needed for usleep() */ #include <stdlib.h> #include <string.h> #include <unistd.h> #include <aos/list.h> #include <aos/debug.h> #include <time.h> #include <aos/aos.h> #include "aos/cli.h" #include <uservice/uservice.h> #include <uservice/eventid.h> #include <yoc/sysinfo.h> #include <board.h> #include "player_demo.h" #include "webclient.h" #include "cJSON.h" #include "oled.h" #include "u8g2.h" #include "u8x8.h" #include "app_main.h" #define TAG "APP" static void u8g2_task(void *arg); #define GET_HEADER_BUFSZ_MY 1024 #define GET_RESP_BUFSZ_MY 1024 static volatile int http_task_flag; void test_https(void); static uint32_t free_func(void) { int total = 0,used = 0,mfree = 0,peak = 0; aos_get_mminfo(&total, &used, &mfree, &peak); printf(" total used free peak \r\n"); printf("memory usage: %10d%10d%10d%10d\r\n\r\n", total, used, mfree, peak); return 0; } extern void aos_malloc_show(int mm); static void http_test(void *priv) { // LOGD(TAG, "start http test"); int i = 0; free_func(); LOGD(TAG, "start http test(%d)", i++); char *myurl = "http://www.xxxxxx.com/index.php"; LOGD(TAG, "---URL---: %s",myurl); size_t *mysize = 1024; http_wget(myurl, mysize); free_func(); aos_msleep(10*1000); http_task_flag = 0; } static void network_event(uint32_t event_id, const void *param, void *context) { switch(event_id) { case EVENT_NETMGR_GOT_IP: LOGD(TAG, "net got ip"); if (!http_task_flag) { aos_task_t task; http_task_flag = 1; aos_msleep(9000); aos_task_new_ext(&task, "http", http_test, NULL, 1024*8, 32); } break; case EVENT_NETMGR_NET_DISCON: LOGD(TAG, "net disconnect"); http_task_flag = 0; break; } /*do exception process */ app_exception_event(event_id); } int main(void) { board_yoc_init(); player_init(); //cli_reg_cmd_player(); /* Subscribe */ event_subscribe(EVENT_NETMGR_GOT_IP, network_event, NULL); // 订阅网络连接成功事件 event_subscribe(EVENT_NETMGR_NET_DISCON, network_event, NULL); // 订阅网络连接失败事件 aos_msleep(6000);//不延时6秒,网络没正常,无法播放url的mp3文件 cli_reg_cmd_player(); return 0; }
4、oled.c调整
增加三个函数u8g2Init() ,u8x8_gpio_and_delay() ,draw_show_write()
uint8_t u8x8_gpio_and_delay(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr) { switch (msg) { case U8X8_MSG_GPIO_SPI_DATA: lcd_sdin((uint8_t)arg_int); //SPI - MOSI break; case U8X8_MSG_GPIO_SPI_CLOCK: //SPI - CLK lcd_sclk(arg_int); break; case U8X8_MSG_GPIO_AND_DELAY_INIT: oled_init(); //OLED初始化 Delay(1); break; case U8X8_MSG_DELAY_MILLI: Delay(arg_int); //延时 break; case U8X8_MSG_GPIO_CS: //SPI - CS lcd_cs((uint8_t)arg_int); case U8X8_MSG_GPIO_DC: lcd_dc((uint8_t)arg_int); //SPI - MISO break; case U8X8_MSG_GPIO_RESET: break; } return 1; } void u8g2Init(u8g2_t *u8g2) { u8g2_Setup_ssd1306_128x64_noname_f(u8g2, U8G2_R0, u8x8_byte_4wire_sw_spi, u8x8_gpio_and_delay); // 初始化 u8g2 结构体 u8g2_InitDisplay(u8g2); // 根据所选的芯片进行初始化工作,初始化完成后,显示器处于关闭状态 u8g2_SetPowerSave(u8g2, 0); // 打开显示器 } void draw_show_write(u8g2_t *u8g2, char* a ,char* b) { u8g2_SetFontMode(u8g2, 1); /*字体模式选择*/ u8g2_SetFontDirection(u8g2, 0); /*字体方向选择*/ u8g2_SetFont(u8g2, u8g2_font_ncenB10_tr); u8g2_DrawStr(u8g2, 0,15,"-INFORMATION-"); u8g2_SetFont(u8g2, u8g2_font_ncenB08_tr); u8g2_DrawStr(u8g2, 20,36,a); u8g2_SetFont(u8g2, u8g2_font_ncenB08_tr); u8g2_DrawStr(u8g2, 70,36,b); }
5、player_demo.c声音播放处理
增加两个函数 cli_reg_cmd_player(),cli_reg_cmd_player_sound()
player_t *get_player_demo() { if (!g_player) { ply_conf_t ply_cnf; player_conf_init(&ply_cnf); ply_cnf.vol_en = 1; //改这个地方,可以让启动时的语音声音变小 ply_cnf.vol_index = 120; // 0~255 ply_cnf.event_cb = _player_event; ply_cnf.period_num = 12; // 12 * 5 period_ms = 60ms ply_cnf.cache_size = 32 * 1024; // web cache size g_player = player_new(&ply_cnf); } return g_player; } int cli_reg_cmd_player(void) { char url[128]; static const struct cli_command cmd_info = { "player", "player example", cmd_ipc_func, }; aos_cli_register_command(&cmd_info); //snprintf(url, sizeof(url), "mem://addr=%u&size=%u", (uint32_t)&_welcome_mp3, _welcome_mp3_len); snprintf(url, sizeof(url), "http://www.xxxxxx.com/info.mp3"); LOGD(TAG, "http_url = %s", url); player_play(get_player_demo(), url, 0); aos_msleep(6000); player_stop(get_player_demo()); return 0; } int cli_reg_cmd_player_sound(char* str) { char url[128]; static const struct cli_command cmd_info = { "player", "player example", cmd_ipc_func, }; aos_cli_register_command(&cmd_info); char src1[100], src2[20], src3[20]; strcpy(src1, "http://www.xxxxxx.com/"); strcpy(src2, str); strcpy(src3, ".mp3"); strcat(src1, src2); strcat(src1, src3); LOGD(TAG, "http_url = %s", src1); player_play(get_player_demo(), src1, 0); aos_msleep(6*1000); player_stop(get_player_demo()); return 0; }
6、利用U2g8组件显示内容
\__workspace_pack__\webclient\webclient_http.c修改*http_wget()函数, 并增加u8g2_showtask()函数
void *http_wget(const char *url, size_t *size) { int content_length = 0; int total_read = 0; int resp_status = 0; uint8_t *out_content = NULL; cJSON *json,*json_name,*json_number; struct webclient_session *session = NULL; aos_check_param(url); aos_check_param(size); session = webclient_session_create(HTTP_HEADER_SIZE); if (NULL == session) { LOGE(TAG, "session create fail\n"); goto err; } webclient_set_timeout(session, 500); //set timeout to 500ms and retry /* send GET request by default header */ if ((resp_status = webclient_get(session, url)) != 200) { LOGD(TAG, "webclient GET request failed, response(%d) error.\n", resp_status); goto err; } content_length = webclient_content_length_get(session); if (content_length <= 0) { LOGD(TAG, "HTTP Chuncked Mode"); int cur_read = 0; size_t buf_size = 0; while (total_read < HTTP_RECV_MAX_SIZE) { /* read result */ buf_size += 512; out_content = aos_realloc(out_content, buf_size); cur_read = webclient_read(session, out_content + total_read, buf_size); json = cJSON_Parse(out_content); //解析成json形式 json_name = cJSON_GetObjectItem( json , "country" ); //获取键值内容 json_number = cJSON_GetObjectItem( json , "number" ); u8g2_t u8g2; u8g2Init(&u8g2); //free(out);//不能启用,报错 if (strcmp(json_name->valuestring, "Japan") == 0) { printf("------字符串相同OK 1 !\n"); aos_task_new("u8g2_show", u8g2_showtask, json, 10 * 1024); aos_msleep(3*1000); cli_reg_cmd_player_sound(json_name->valuestring); //aos_msleep(6*1000); cli_reg_cmd_player_sound(json_number->valuestring); } else { printf("------字符串不相同Fail 1 !\n"); } if (cur_read > 0) total_read += cur_read; if (cur_read <= buf_size) break; } if (total_read >= HTTP_RECV_MAX_SIZE) { LOGE(TAG, "total_read is too large: %d\n", total_read); goto err; } } else { if (content_length >= HTTP_RECV_MAX_SIZE) { LOGE(TAG, "content length is too large: %d\n", content_length); goto err; } out_content = aos_malloc(content_length); total_read = webclient_read(session, out_content, content_length); LOGD(TAG, "---%s---", out_content); json = cJSON_Parse(out_content); //解析成json形式 json_name = cJSON_GetObjectItem( json , "country" ); //获取键值内容 json_number = cJSON_GetObjectItem( json , "number" ); u8g2_t u8g2; u8g2Init(&u8g2); //free(out);//不能启用,报错 if (strcmp(json_name->valuestring, "Japan") == 0) { printf("------字符串相同OK 2 !\n"); aos_task_new("u8g2_show", u8g2_showtask, json, 10 * 1024); aos_msleep(3*1000); cli_reg_cmd_player_sound(json_name->valuestring); //aos_msleep(6*1000); cli_reg_cmd_player_sound(json_number->valuestring); } else { printf("------字符串不相同Fail 2 !\n"); } cJSON_Delete(json); //释放内存 if (total_read != content_length) { LOGE(TAG, "not equal, need read = %d, bytes_read = %d\n", content_length, total_read); goto err; } } *size = total_read; webclient_close(session); return out_content; err: if (out_content) free(out_content); webclient_close(session); return NULL; } static void u8g2_showtask(cJSON *c) { u8g2_t u8g2; u8g2Init(&u8g2); cJSON *a,*b; a = cJSON_GetObjectItem( c , "country" ); //获取键值内容 b = cJSON_GetObjectItem( c , "number" ); while (1) { u8g2_FirstPage(&u8g2); do { draw_show_write(&u8g2,a->valuestring,b->valuestring); aos_msleep(2000); } while (u8g2_NextPage(&u8g2)); //aos_msleep(2000); } }
四、视频演示
本文源自:平头哥芯片开放社区
欢迎关注公众号:芯片开放社区(ID:OCC_THEAD),查看更多应用实战文章。