RT-Thread实战笔记|语音控制获取心知天气信息

前言

上篇文章介绍了LD3320的用法,小飞哥“灵光一现”,何不做一个语音控制获取天气信息的东东,既然想了,那就干它,来,淦~小飞哥前面说过rt-thread好用,那今天一起来看看到底有多好用...

完整连接:

演示效果

见公众号

硬件环境

ART-PI(其他开发板也可以)

LD3320语音模块

板载wifi(ESP8266也可以)

“一张会说话的嘴”

软件环境

RT-Thread studio 版本2.1.1

  • 软件包

webclient V2.1.2

mbedtls V2.7.10.1

cjson V1.7.14

netutils V1.3.1

fal V0.5.0

本次的知识点还是相当的丰富的,搬好小板凳,泡杯茶,坐一会慢慢看吧...

wifi配置

在LD3320的工程基础之上,来添加wifi,ART-PI上板载的wifi模组是AP6212,是蓝牙于wifi一体的模组,本次我们只使用wifi功能

在setting勾选即可,对应的宏为ART_PI_USING_WIFI_6212_LIB,勾选之后,工程会自动添加相关宏定义控制的代码

完了,CTRL+S保存到我们的工程就可以了...好像啥也没干,来看看效果是怎样的

在控制台可以看到,很多关于网络的配置已经初始化完成了,终端输入wifi,可以看到几个关于wifi的指令,本次用到的是wifi的AP功能,连接家里的wifi

输入wifi scan,来看看附近都有哪些“hot pot”,还是有几个的,也不隐藏了,欢迎过来蹭网~

使用wifi join命令加入网络即可,千万不要跟着教程输入我家的...

wifi join "你家热点名称" "你家无线密码"

网络状况好像不太好,还重连了,顺便把重连功能验证了,连接成功之后,可以看到是自动获取IP地址的,输入ifconfig,来看看获取到的地址相关的,DHCP功能是使能的

接下来,开发板“点灯”,网络经典ping百度...还算比较顺利

就这样,我们的wifi就完成了,对,就这样...一行代码没写,sun le dog,好怀念写代码的日子

这样直接添加wifi功能的方式,掉电是不会保存wifi信息的,需要重新wifi join

https访问组件配置

webclient 软件包

setting->Add->输入webclient->确认找到对应软件包

双击打开可以详细看到关于此软件包的用法

-点击软件包,进入详细配置界面,

  • Enable webclient GET/POST samples :添加示例代码;

  • Select TLS mode :配置开启 HTTPS 支持,选择支持的模式

  • Not support:不支持 TLS 功能

  • SAL TLS support:配置 SAL 组件中 TLS 功能支持,SAL 组件中抽象 TLS 操作,用户还需要手动配置开启使用的 TLS 软件包类型(目前只支持 MbedTLS 软件包)

  • MbedTLS support:配置 MbedTLS 功能支持

  • Version :配置软件包版本

mbedtls软件包

使能mbedtls功能之后,mbedtls软件包自动添加,mbedTLS(前身 PolarSSL)是一个由 ARM 公司开源和维护的 SSL/TLS 算法库。其使用 C 编程语言以最小的编码占用空间实现了 SSL/TLS 功能及各种加密算法,易于理解、使用、集成和扩展,方便开发人员轻松地在嵌入式产品中使用 SSL/TLS 功能

详细配置

  • Select Root Certificate ---> # 选择证书文件

  • mbedtls: An portable and flexible SSL/TLS library # 打开 mbedtls 软件包

  • Store the AES tables in ROM # 将 AES 表存储在 ROM 中

  • Maximum window size used # 用于点乘的最大“窗口”大小(2-7)

    (3584) Maxium fragment length in bytes # 配置数据帧大小

  • Enable a mbedtls client example # 开启 mbedtls 测试例程

  • Enable Debug log output # 开启调试 log 输出

  • version (latest) ---> # 选择软件包版本,默认为最新版本

注意:

在调试的时候,获取不同的信息时,有时候返回的数据量太大,报错-0x7200

不要慌,百度错误码,可能是数据buffer太小了,增大buffer即可解决

关于证书的内容就比较多了,小伙伴可以自行百度或者查看mbedtls软件包的使用教程

netutils

这里汇集了 RT-Thread 可用的全部网络小工具集合,你所需要的小工具都可以在这里找到。

TLS 握手是证书验证需要时间的验证,添加此网络工具用于时间同步

同时要开启RTC功能,否则会报错

RTC详细配置界面

至此,网络功能就配置完成了,接下来跑一下例程,看下效果

web_get我们是获取到一串字符串,看看源码地址什么

浏览器输入此地址,获取到的正是这些字符

TLS例程比较麻烦点,要先进行SSL/TLS 认证,才能连接,这就牵扯到HTTP和HTTPS的区别了,篇幅太大,不易展开...

同样的,看下源地址是什么内容

到这里,我们的HTTPS访问就建立完成了,还没有写一句代码...

心知天气API

大家需要注册一个心知天气账号,注册完之后使用免费的即可

天气API

https://api.seniverse.com/v3/weather/now.json?key=“你的秘钥”&location=“地点”

我们点击一个进去看看,我查看的是北京的天气,数据是json格式的,我们只需要解析json包就可以啦

原始数据

这里教大家一个小技巧,如何查看网址的IP地址,端口号,只需要在网页按F12进入调试界面,宣导网络,重新加载

代码编写

新建文件,或者在上面例程里面修改,首先把网址改为心知天气的API接口

成功获取到天气数据

json解析

static int cJSON_NowWeatherParse(char *JSON)
{
    cJSON *json,*arrayItem,*object,*subobject,*item;
    int size;
    json = cJSON_Parse(JSON);//解析JSON数据包
        if(json == NULL)          //检测JSON数据包是否存在语法上的错误,返回NULL表示数据包无效
        {
            rt_kprintf("Error before: [%s]\r\n",cJSON_GetErrorPtr()); //打印数据包语法错误的位置
            return 1;
        }
        else
        {
            if((arrayItem = cJSON_GetObjectItem(json,"results")) != NULL); //匹配字符串"results",获取数组内容
            {
                size = cJSON_GetArraySize(arrayItem);     //获取数组中对象个数
                rt_kprintf("cJSON_GetArraySize: size=%d\n",size);

                if((object = cJSON_GetArrayItem(arrayItem,0)) != NULL)//获取父对象内容
                {
                    rt_kprintf("--------------------------------Now Weather Data Begin------------------------------\r\n");
                    /* 匹配子对象1 */
                    if((subobject = cJSON_GetObjectItem(object,"location")) != NULL)
                    {

                        rt_kprintf("---------------------------------subobject1-------------------------------\r\n");
                        if((item = cJSON_GetObjectItem(subobject,"id")) != NULL)
                        {
                            rt_kprintf("cJSON_GetObjectItem: %s:%s\r\n",item->string,item->valuestring);
                        }
                        if((item = cJSON_GetObjectItem(subobject,"name")) != NULL) //地名--需要用到的数据
                        {
                            rt_kprintf("cJSON_GetObjectItem: %s:%s\r\n",item->string,item->valuestring);
                        }
                        if((item = cJSON_GetObjectItem(subobject,"country")) != NULL)
                        {
                            rt_kprintf("cJSON_GetObjectItem: %s:%s\r\n",item->string,item->valuestring);
                        }
                        if((item = cJSON_GetObjectItem(subobject,"path")) != NULL)
                        {
                            rt_kprintf("cJSON_GetObjectItem: %s:%s\r\n",item->string,item->valuestring);
                        }
                        if((item = cJSON_GetObjectItem(subobject,"timezone")) != NULL)
                        {
                            rt_kprintf("cJSON_GetObjectItem: %s:%s\r\n",item->string,item->valuestring);
                        }
                        if((item = cJSON_GetObjectItem(subobject,"timezone_offset")) != NULL)
                        {
                            rt_kprintf("cJSON_GetObjectItem: %s:%s\r\n",item->string,item->valuestring);
                        }
                    }
                    /* 匹配子对象2 */
                    if((subobject = cJSON_GetObjectItem(object,"now")) != NULL)
                    {
                        rt_kprintf("---------------------------------subobject2-------------------------------\r\n");
                        if((item = cJSON_GetObjectItem(subobject,"text")) != NULL)//天气预报文字--需要用到的数据
                        {
                            rt_kprintf("cJSON_GetObjectItem: %s:%s\r\n",item->string,item->valuestring);

                        }
                        if((item = cJSON_GetObjectItem(subobject,"code")) != NULL)//天气预报代码--需要用到的数据
                        {
                            rt_kprintf("cJSON_GetObjectItem: %s:%s\r\n",item->string, item->valuestring);

                        }
                        if((item = cJSON_GetObjectItem(subobject,"temperature")) != NULL) //温度--需要用到的数据
                        {
                            rt_kprintf("cJSON_GetObjectItem: %s:%s\r\n",item->string, item->valuestring);
                        }
                    }
                    /* 匹配子对象3 */
                    if((subobject = cJSON_GetObjectItem(object,"last_update")) != NULL)
                    {
                        rt_kprintf("---------------------------------subobject3-------------------------------\r\n");
                        rt_kprintf("cJSON_GetObjectItem: %s:%s\r\n",subobject->string,subobject->valuestring);
                    }
                    rt_kprintf("--------------------------------Now Weather Data End--------------------------------\r\n");
                }
            }
        }
        cJSON_Delete(json); //释放cJSON_Parse()分配出来的内存空间
        return 0;
}

解析后的数据:

接下来,结合上节我们做的LD3320,实现语音控制获取不同地点的天气信息:

先来定义几个地点:

static char *REQUEST[4] ={

        "GET /v3/weather/now.json?key=SYahiZcoJ587MEA3R&location=beijing HTTP/1.1\r\n"
            "Host: api.seniverse.com\r\n"
            //"User-Agent: rtthread/3.1 rtt\r\n"
            "\r\n",

        "GET /v3/weather/now.json?key=SYahiZcoJ587MEA3R&location=suzhou HTTP/1.1\r\n"
            "Host: api.seniverse.com\r\n"
            //"User-Agent: rtthread/3.1 rtt\r\n"
            "\r\n",

        "GET /v3/weather/now.json?key=SYahiZcoJ587MEA3R&location=shanghai HTTP/1.1\r\n"
            "Host: api.seniverse.com\r\n"
            //"User-Agent: rtthread/3.1 rtt\r\n"
            "\r\n",

        "GET /v3/weather/now.json?key=SYahiZcoJ587MEA3R&location=shenzhen HTTP/1.1\r\n"
            "Host: api.seniverse.com\r\n"
            //"User-Agent: rtthread/3.1 rtt\r\n"
            "\r\n",
};

然后在语音中添加相应的识别信息:

//Identification code (Customer Modification Office)

#define CODE_RUN 1   //commond code for LED waterfall
#define CODE_KEY 2   //commond code for LED flash
#define CODE_FLASH 3 //commond code for LED reversal
#define CODE_PLAY 4  //commond code for PLAY MP3
#define CODE_BEIJING_Weather 5              //北京
#define CODE_SUZHOU_Weather 6               //苏州
#define CODE_SHANGHAI_Weather 7             //上海
#define CODE_SHENZHEN_Weather 8             //深圳


    rt_uint8_t sRecog[DATE_A][DATE_B] = {
        //add commond,use pinying
        "ni hao",
        "ni lai zi na li",
        "bei yi shou shi",
        "shi jie zhe me da",
        "bei jing tian qi",
        "shang hai tian qi",
        "su zhou tian qi",
        "shen zhen tian qi"
    };
    rt_uint8_t pCode[DATE_A] = {
        //add commond code to do the commond
        CODE_RUN,
        CODE_KEY,
        CODE_FLASH,
        CODE_PLAY,
        CODE_BEIJING_Weather,
        CODE_SHANGHAI_Weather,
        CODE_SUZHOU_Weather,
        CODE_SHENZHEN_Weather
    };

函数执行:

rt_uint8_t status =0;
void rt_Board_text(rt_uint8_t Code_Val)
{
    switch (Code_Val)
    {
    case CODE_RUN: //Commond "liu shui deng"
        rt_LED_run();
        break;
    case CODE_KEY: //Commond "an jian"
        rt_LED_key();
        break;
    case CODE_FLASH: //Commond "shan shuo"
        rt_LED_flash();
        break;
    case CODE_PLAY: //Commond "bo fang"
        rt_Play_demo();
        break;
    case CODE_BEIJING_Weather:
        status=0;
        Weather();
        break;
    case CODE_SUZHOU_Weather:
        status=1;
        Weather();
        break;
    case CODE_SHANGHAI_Weather:
        status=2;
        Weather();
        break;
    case CODE_SHENZHEN_Weather:
        status=3;
        Weather();
        break;
    default:
        break;
    }
}

然后改一下例程里面的请求函数,根据识别到的语音置相应的状态,调用不同的API:

  while ((ret = mbedtls_client_write(tls_session, (const unsigned char *) REQUEST[status], rt_strlen(REQUEST[status]))) <= 0)
    {
        if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE)
        {
            rt_kprintf("mbedtls_ssl_write returned -0x%x\n", -ret);
            goto __exit;
        }
    }
  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
RT-Thread作品秀】智能家居的语音控制方案。作者:xqyjlj 概述智能家居是现在一个很火热的方向,随着人们生活水平的提高,我们都逐渐开始希望身边的电器都可以不用手来控制,本作品就是基于这种需求,开发出来了一个基于语音控制的智能家居方案。本智能家居方案,分为联网与不联网两种版本。其中,无论是联网与不联网,语音识别功能均能正常使用。在本作品没有连上网的情况下,可以进行语音对开关的控制,进行MP3等常用音频文件的播放,以及具有拍照功能,可以将拍下来的照片储存在SD卡内,在本作品连上网的情况下,还附加了以下功能,可以将一些数据上报到云平台(onenet),并且将一些工作日志通过邮件发送给用户。 开发环境硬件:ART_PI(主控) LD3320(语音识别芯片) VS1053(音频解码芯片) OV2640(摄像头) RT-Thread版本:RT-Thread V 4.0.3 开发工具及版本:RT-Thread Studio 2.0.0 RT-Thread使用情况概述内核:调度器,信号量。 组件:UART,DFS,SPI,IIC,PIN。 软件包:smtp_client,btstack,netuils,fal,easyflash,littlefs,onenet。 硬件框架主控:ART-PI ART-Pi 是 RT-Thread 团队为嵌入式软件工程师、开源创客设计的一款极具扩展功能的 DIY 开源硬件。致力打造一个开源的软硬件平台。 语音识别芯片:LD3320 LD3320是非特定人(不用针对指定人)语音识别芯片,即语音声控芯片。最多可以识别50条预先内置的指令。 音频解码芯片:VS1053 VS1053是一款利用SPI通讯的音频解码模块,支持大部分的音频文件的解码播放和编码保存 摄像头:OV2640 OV2640是OmniVision公司生产的一颗1/4寸的CMOSUXGA(1632*1232)图像传感器;支持自动曝光控制、自动增益控制、自动白平衡、自动消除灯光条纹等自动控制功能。 软件框架说明本项目采用的是多级联控模式。将多个模块的任务分为多个级别,以语音识别为主体,摄像头和语音播报为从体,在语音识别到关键字的时候,会出发相对应的函数,实现不同的效果,而onenet是与语音识别互相独立的,会源源不断的把数据实时发送到云端。 软件模块说明smtp_thread_entry:邮件线程,用于发送邮件。 ld3320_asr_thread:语音识别线程,用于语音识别,调用其他程序。 onenet_upload_entry:onenet线程,用于向云端发送数据。 语音识别过程: 首先初始化LD3320芯片,在对其写入需要识别的关键字数据,之后启动LD3320,之后等待其信号引脚拉低,在其信号引脚拉低后,通过读取其寄存器,我们便能知道LD3320获取到了什么样的关键字。之后便从关键字调取我们的相对应的函数。使之工作于不同的功能。 演示效果演示视频: 比赛感悟在报名这个比赛之后,我的目标其实是比现在的功能多得多的,这一点可以从我的Gitee上面的进度表可以看出,奈何原本打算三个人做的项目,到最后,也是我一个人来完成。自己之前画的板子,也是因为自己画板功力不足,还有焊接能力不足,导致本来拥有更多功能的拓展板也没完成。 不过比赛嘛,重要的不是结果,而是过程。通过这次比赛,我最起码收货到了以下知识: 安卓开发,微信小程序设计,web开发(以上由于个人能力问题,其实并未实现),音频处理,STM32H750的众多DMA的设置,以及bootloader,同时也知道了STM32还能片外运行的神奇事情,也学会了RT-Thread Studio的使用。最重要的事情就是明白了不要过分依赖别人,自己想的计划,就要自己去实现,不要总是把任务布置给其他人。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小飞哥玩嵌入式

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值