手把手教你实现基于RT-Thread的百度语音识别(六)完结

前言

本篇是整个百度语音识别连载的第六篇,也是最后一篇了。这一次我们要把前面实现的各部分功能用线程串接起来,形成一个完整的项目,效果是这样的:

按下按键,开始录音,录音结束后自动将音频发送到百度服务器端,返回识别结果,进行数据解析,显示结果(控制外设)。

那么我们大致可以将以上功能划分为三个线程,分别是:按键线程,录音线程以及识别线程。下面开始对这三个线程进行分析:

实现详解

首先我把各部分功能拆分成了多个源文件,这样使整个工程看起来更加简洁:

main.c

语音识别 bd_speech_rcg.c

录音 wav_record.c

按键只是简单的读IO状态,就放在main.c就好了

bd_speech_rcg.c和wav_record.c里都是前面已经实现的功能函数,这里我就不做讲解,主要来看看main.c:

/* main.c */

#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>
#include <dfs_posix.h>
#include <string.h>
#include <fal.h>
#include <drv_lcd.h>
#include <cn_font.h>

/* 函数声明 */	
extern int wavrecord_sample();
extern void bd();

/* 线程参数 */
#define THREAD_PRIORITY			25      //优先级
#define THREAD_STACK_SIZE		1024    //线程栈大小
#define THREAD_TIMESLICE		10      //时间片

/* 线程句柄 */
static rt_thread_t tid1 = RT_NULL;
static rt_thread_t tid2 = RT_NULL;
static rt_thread_t tid3 = RT_NULL;

/* 指向信号量的指针 */
static rt_sem_t dynamic_sem = RT_NULL;

/* 邮箱控制块 */
static struct rt_mailbox mb;
/* 用于放邮件的内存池 */
static char mb_pool[128];

/* 录音线程 tid1 入口函数 */
static void thread1_entry(void *parameter)
{
	static rt_err_t result;
    while(1)
    {
        result = rt_sem_take(dynamic_sem, RT_WAITING_FOREVER);
        if (result != RT_EOK)
        {
            rt_kprintf("take a dynamic semaphore, failed.\n");
            rt_sem_delete(dynamic_sem);
            return;
        }
        else
        {
			rt_kprintf("take a dynamic semaphore, success.\n");
            wavrecord_sample();         //获取到信号量,开始录音
			rt_mb_send(&mb, NULL);      //录音结束,发送邮件
        }
		rt_thread_mdelay(100);
    }		
}

/* 语音识别线程 tid2 入口函数 */
static void thread2_entry(void *parameter)
{
    while (1)
    {
        rt_kprintf("try to recv a mail\n");
        /* 从邮箱中收取邮件 */
        if (rt_mb_recv(&mb, NULL, RT_WAITING_FOREVER) == RT_EOK)
        {
			show_str(20, 40, 200, 32, (rt_uint8_t *)"百度语音识别", 32);
			show_str(20, 100, 200, 32, (rt_uint8_t *)"识别结果:", 32);
            rt_kprintf("get a mail from mailbox!");
            bd();       //收到邮件,进行语音识别
            rt_thread_mdelay(100);
        }
    }
    /* 执行邮箱对象脱离 */
    rt_mb_detach(&mb);
}

/* 按键线程 tid3 入口函数 */
static void thread3_entry(void *parameter)
{
		unsigned int count = 1;
		while(count > 0)
		{
			if(rt_pin_read(KEY0) == 0)
			{
				rt_kprintf("release a dynamic semaphore.\n");
                rt_sem_release(dynamic_sem);        //当按键被按下,释放一个信号量
			}
		rt_thread_mdelay(100);
		}
}

int main(void)
{
	
		fal_init();
		rt_pin_mode(KEY0, PIN_MODE_INPUT);
		rt_pin_mode(PIN_LED_R, PIN_MODE_OUTPUT);
		rt_pin_mode(PIN_LED_G, PIN_MODE_OUTPUT);
		rt_pin_mode(PIN_LED_B, PIN_MODE_OUTPUT);
		rt_pin_write(PIN_LED_R,1);
		rt_pin_write(PIN_LED_G,1);
		rt_pin_write(PIN_LED_B,1);
		
    /* 清屏 */
    lcd_clear(WHITE);

    /* 设置背景色和前景色 */
    lcd_set_color(WHITE,BLACK);

    /* 在LCD 上显示字符 */
    lcd_show_string(55, 5, 24, "RT-Thread");
		
	show_str(120, 220, 200, 16, (rt_uint8_t *)"By 霹雳大乌龙", 16);
	
    /* 创建一个动态信号量,初始值是 0 */
	dynamic_sem = rt_sem_create("dsem", 0, RT_IPC_FLAG_FIFO);
    if (dynamic_sem == RT_NULL)
    {
        rt_kprintf("create dynamic semaphore failed.\n");
        return -1;
    }
    else
    {
        rt_kprintf("create done. dynamic semaphore value = 0.\n");
    }
	
	rt_err_t result;

    /* 初始化一个 mailbox */
    result = rt_mb_init(&mb,
                        "mbt",                      /* 名称是 mbt */
                        &mb_pool[0],                /* 邮箱用到的内存池是 mb_pool */
                        sizeof(mb_pool) / 4,        /* 邮箱中的邮件数目,因为一封邮件占 4 字节 */
                        RT_IPC_FLAG_FIFO);          /* 采用 FIFO 方式进行线程等待 */
    if (result != RT_EOK)
    {
        rt_kprintf("init mailbox failed.\n");
        return -1;
    }

    /* 创建线程 */	
		tid1 = rt_thread_create("thread1",
                            thread1_entry, RT_NULL,
                            THREAD_STACK_SIZE,
                            THREAD_PRIORITY, THREAD_TIMESLICE);
    if (tid1 != RT_NULL)
        rt_thread_startup(tid1);
		
		
		tid2 = rt_thread_create("thread2",
                            thread2_entry, RT_NULL,
                            THREAD_STACK_SIZE,
                            THREAD_PRIORITY, THREAD_TIMESLICE);
    if (tid2 != RT_NULL)
        rt_thread_startup(tid2);
		
		tid3 = rt_thread_create("thread3",
                            thread3_entry, RT_NULL,
                            THREAD_STACK_SIZE,
                            THREAD_PRIORITY, THREAD_TIMESLICE);
    if (tid3 != RT_NULL)
        rt_thread_startup(tid3);
	
    return 0;
}

通过上面的源码可以看到,我采用了信号量+邮箱的通讯机制;按键线程不断读取IO状态,当按键被按下时,释放一个信号量;录音线程处于永久等待信号量的状态,当接收到一个信号量时开始录音,录音结束后发送一封邮件到邮箱中;识别线程不停尝试获取邮件,当接收到邮件时,进行语音识别,后续的解析,显示。。。都是我们之前讲过的了。

但是上面的功能实现并不是完美的,可能存在着一些问题,但大致流程是没问题的(效果亲测OK),因为整个工程也是第一次完整实现,我也还没进行优化啥的,所以有不足之处,请多多包涵。

总结

那么本系列的分享到此也就告一段落了,因为我学习RT-Thread的时间也并不算长,所以可能有些理解并不到位,再加上此次项目是第一次实现,并不完美,但是我会把完整工程放到我的GitHub上,后续我有一些优化,功能拓展啥的,大家可以在GitHub上看到,
项目地址:https://github.com/lxzzzzzxl/Baidu_Speech_base_on_RT-Thread

谢谢搭嘎~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值