【平头哥RVB2601创意应用开发】疫情播报系统应用

简介: 实现通过网络读取json数据,进行分解,针对数据字符,播放相应的mp3音频文件,并在OLED屏幕上显示实际对应数据的疫情播报系统。

作者:Spring123


一、开发板简介

准备平头哥RVB2601开发板来制作一款疫情播报系统应用,先来一张开发板的介绍

1.png

2.png

3.png


二、应用开发初步构想

基于官方网络音乐播放器例程 ch2601_webplayer_demo,由于官方LVGL的功能与音乐播放并存之后对开发板的存储较大,已经超过硬件本身已有的容量,这个得到官方技术确认,那只能另找捷径,移植LCD驱动,再移植U2g8图形库,结合在一起来解决硬件的一些局限。当然还要加载一些必备的组件,例如 cjson,httpclient,webclient


最终实现通过网络读取json数据,进行分解,针对数据字符,播放相应的mp3文件,并在OLED屏幕上显示实际对应数据。


三、移植及增加组件

1、U8g2的移植

正好有大佬写了一篇移植U8g2图形库,测试一下可以通不,如果不考虑瘦身精简的话可以,从u8g2的开源地址 https://github.com/olikraus/u8g2/tree/master/csrc 这个文件夹可以直接引入使用。

4.png


2、lcd驱动移植

移植官方TFT LCD屏幕的开发演示例程 ch2601_gui_demo中的LCD驱动两个文件

5.png


3、加载必备的组件

主要是cjson,httpclient,webclient

6.png


4、确保package.yaml项目配置

package.yaml文件正确,要能正常编译,有一个特别注意点,手动改改,CDK会检测到改动,提示重新加载项目,点是就可以了

7.png


三、代码相关

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字符匹配的声音文件,根据精细度,还可以再拆分成字母音和数字音,这里是示例没有具体完全展开。上传到在阿里云购买的网站空间

8.png

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),查看更多应用实战文章。

相关文章
|
网络协议 数据安全/隐私保护 芯片
|
存储 API 开发工具
【平头哥RVB2601创意应用开发】使用体验02 -- KV存储
使用KV组件在RVB2601进行项目参数的本地持久化。
554 0
【平头哥RVB2601创意应用开发】使用体验02 -- KV存储
|
C语言 芯片
平头哥RVB2601板子上手——GPIO
CH2601的GPIO的操作方法,以及OLED图像的显示
393 0
平头哥RVB2601板子上手——GPIO
|
网络协议 物联网 数据处理
【平头哥RVB2601开发板试用体验】AT 解析器和通过w800 AT命令接入阿里云生活物联网平台
RISC-V RVB2601 Yoc 实现和测试验证阿里云平台接入的等相关功能,同时去了解YoC中网络设备和AT解析器框架。
648 0
【平头哥RVB2601开发板试用体验】AT 解析器和通过w800 AT命令接入阿里云生活物联网平台
|
芯片
【平头哥RVB2601开发板试用 】GPIO控制的流水灯
对于芯片来说,其实经常用到的就是IO口了,其实其所有功能的实现都是通过IO口的复用实现的,那么今天咱们就简单对IO口控制流水灯进行讲解分析
351 0
【平头哥RVB2601开发板试用 】GPIO控制的流水灯
|
存储 编解码 监控
【平头哥RVB2601开发板试用体验】基于 HTTPClient 的云语音识别 3
在本文中,我们将手动实现“multipart/form-data”类型内容的 POST 请求,并且最终完成整个云语音识别功能。
222 0
【平头哥RVB2601开发板试用体验】基于 HTTPClient 的云语音识别 3
|
存储 编解码 物联网
|
网络协议 物联网 数据处理
【平头哥RVB2601开发板试用体验】AT解析器和通过w800 AT命令接入阿里云生活物联网平台
RISC-V RVB2601 Yoc 实现和测试验证阿里云平台接入的等相关功能,同时去了解YoC中网络设备和AT解析器框架。
531 0
【平头哥RVB2601开发板试用体验】AT解析器和通过w800 AT命令接入阿里云生活物联网平台

热门文章

最新文章