题目:基于stm32蓝牙智能语音识别分类播报垃圾桶
实现功能如下:
LU-ASR01是一款低成本、低功耗、体积小、高性能的离线语音识别系统。本系统集成了语音识别、语音回复、IO控制(多信号输出)、串口输出、温湿度广播等功能。在10米范围内的语音识别率可达98%,远远超过了LD3320等其他模组。
LU-ASR01基本参数:
模块型号:LU-ASRO1尺寸:36mmx36mm
I0口:有8路IO,分别是“IO1~lO8”。其中I01、I02、I03、I04、IO5、IO6可以输出PWM信号,也可以作为普通IO使用。IO7、IO8为普通IO,可以输出高低电平、脉冲信号、舵机信号。有一路串口输出TX管脚,可输出字符或16进制类型数据。一路DHT传感器管脚,可以接DHT11温湿度传感器或DS18B20温度传感器[6],可实现语音控制播报当时温湿度
待机功耗:10mA
供电范围:3.6-5.8V,一般使用5V供电,供电电流大于500mA
工作温度:-20℃~80°C
喇叭参数:8欧姆,3W功率
#ifndef __Lu_ASR01_H
#define __Lu_ASR01_H
#include "stm32f10x.h"
#include "Def_config.h"
#define ASR01_Buffer_Length 50
#define ASR01_Length 5
typedef struct
{
char ASR01_Rec_Buffer[ASR01_Buffer_Length];
ENUM_JUDGE isGetData; //是否获取到数据
ENUM_JUDGE isParseData; //是否解析完成
char ASR01[ASR01_Length]; //字符串形式存储
ENUM_JUDGE isUsefull; //信息是否有效
} _ASR01Data;
extern _ASR01Data ASR01_Data;
void ASR01_RecHandle(u8 Res);
void ASR01_Clear_Data(void);
void parseASR01Buffer(void);
#endif
#include "Lu_ASR01.h"
#include
#include
#include "SG90.h"
_ASR01Data ASR01_Data;
char ASR01_RX_BUF[ASR01_Buffer_Length]; //接收缓冲,最大ASR01_Buffer_Length个字节.末字节为换行符
u8 point2 = 0;
void ASR01_RecHandle(u8 Res)
{
if(Res == '$')
{
point2 = 0;
}
ASR01_RX_BUF[point2++] = Res;
if(Res == '@' || point2 >2)
{
memset(ASR01_Data.ASR01_Rec_Buffer, 0, ASR01_Buffer_Length); //清空
memcpy(ASR01_Data.ASR01_Rec_Buffer, ASR01_RX_BUF, point2); //保存数据
ASR01_Data.isGetData = TRUE;
point2 = 0;
memset(ASR01_RX_BUF, 0, ASR01_Buffer_Length); //清空
}
if(point2 >= ASR01_Buffer_Length)
{
point2 = ASR01_Buffer_Length;
}
}
u8 ASR01_Find(char *a) // 串口命令识别函数
{
if(strstr(ASR01_Data.ASR01_Rec_Buffer,a)!=NULL)
return 1;
else
return 0;
}
void ASR01_Clear_Data(void)
{
ASR01_Data.isGetData = FALSE;
ASR01_Data.isParseData = FALSE;
ASR01_Data.isUsefull = FALSE;
memset(ASR01_Data.ASR01, 0, ASR01_Length); //清空
memset(ASR01_Data.ASR01_Rec_Buffer, 0, ASR01_Buffer_Length); //清空
}
void parseASR01Buffer(void)
{
if (ASR01_Data.isGetData) //获得语音模块的数据 --- $1@ : $4@
{
ASR01_Data.isGetData = FALSE;
if(ASR01_Find("$1@"))
{
ASR01_Data.isParseData = TRUE;
ASR01_Data.isUsefull = TRUE;
SG90_Control(1,ANGLE_90); //控制舵机1 旋转90°
SG90_Structure.is_num01_open = TRUE;
printf("$O1@"); //OPEN1 --缩写O1 --- 输出--蓝牙模块--手机同步更改舵机状态
}
else if(ASR01_Find("$2@"))
{
ASR01_Data.isParseData = TRUE;
ASR01_Data.isUsefull = TRUE;
SG90_Control(2,ANGLE_90);
SG90_Structure.is_num02_open = TRUE;
printf("$O2@");
}
else if(ASR01_Find("$3@"))
{
ASR01_Data.isParseData = TRUE;
ASR01_Data.isUsefull = TRUE;
SG90_Control(3,ANGLE_90);
SG90_Structure.is_num03_open = TRUE;
printf("$O3@");
}
else if(ASR01_Find("$4@"))
{
ASR01_Data.isParseData = TRUE;
ASR01_Data.isUsefull = TRUE;
SG90_Control(4,ANGLE_90);
SG90_Structure.is_num04_open = TRUE;
printf("$O4@");
}
else
{
ASR01_Clear_Data(); //清空接收到的数据---数据帧无效
}
}
}
本设计使用了4台舵机用来控制垃圾桶的开合,都是SG90型舵机。舵机是一种位置(角度)伺服驱动器,适用于那些需要角度不断变化并可以保持的闭环控制执行模块[13]。舵机主要由电机、电位器、控制电路、减速齿轮组、外壳、以及舵盘组成。
所述舵机的控制信号周期是一个20ms的脉宽调制(PWM)信号,在该PWM信号中,在0.5至2.5ms之间,在0至180°之间具有线性变化。舵机的输入信号为PWM信号,由PWM调制,并根据不同的占空比来控制舵机的转动角度和方向。
本设计选用STM32单片机的PB8-PB11四个引脚为舵机输入PWM信号来控制舵机旋转的角度从而实现控制垃圾桶盖的开关。其工作原理是:STM32单片机的PB8-PB11四个引脚分别连接4个舵机的输入端,通过定时器产生PWM信号控制舵机工作,舵机驱动电路内置基准电压,对信号的要求是20ms周期、0.5ms宽度,通过对比输入的信号与基准电压,可以得到偏差结果,从而控制了外部设备的转动角度。比如:电压差为正时,电机正向旋转,电压差为负时,电机反向旋转,电压差为零时,电机处于静止状态,从而达到带动垃圾桶盖开关的目的。
#ifndef __SG90_H
#define __SG90_H
#include "stm32f10x.h"
#include "Def_config.h"
#define SG90_RCC_APB2Periph_GPIOX RCC_APB2Periph_GPIOB
#define SG90Num01_GPIOX_PinX GPIO_Pin_8
#define SG90Num01_GPIOX GPIOB
#define SG90Num02_GPIOX_PinX GPIO_Pin_9
#define SG90Num02_GPIOX GPIOB
#define SG90Num03_GPIOX_PinX GPIO_Pin_10
#define SG90Num03_GPIOX GPIOB
#define SG90Num04_GPIOX_PinX GPIO_Pin_11
#define SG90Num04_GPIOX GPIOB
//Turn_angle: 1---0度 2---45度 3---90 4--- 135度 5---180度
typedef enum {
ANGLE_0 = 1,
ANGLE_45 = 2,
ANGLE_90 = 3,
ANGLE_135 = 4,
ANGLE_180 = 5
}ENUM_ANGLE;
typedef struct {
ENUM_JUDGE is_num01_start; //启动
ENUM_JUDGE is_num02_start;
ENUM_JUDGE is_num03_start;
ENUM_JUDGE is_num04_start;
ENUM_ANGLE num01_angleX; //转动角度
ENUM_ANGLE num02_angleX;
ENUM_ANGLE num03_angleX;
ENUM_ANGLE num04_angleX;
ENUM_JUDGE is_num01_finish; //到达指定角度
ENUM_JUDGE is_num02_finish;
ENUM_JUDGE is_num03_finish;
ENUM_JUDGE is_num04_finish;
ENUM_JUDGE is_num01_open;
ENUM_JUDGE is_num02_open;
ENUM_JUDGE is_num03_open;
ENUM_JUDGE is_num04_open;
}STRUCT_SG90;
extern STRUCT_SG90 SG90_Structure;
void SG90_Init(void);
void SG90_ControlAngleX(void);
void SG90_Control(u8 numX,ENUM_ANGLE angleX);
#endif
/******************************
SG90 舵机驱动程序
PB8 - PB11 四个舵机
******************************/
#include "SG90.h"
#include "led.h"
#include "bsp_timer3.h"
void SG90_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* GPIOx clock enable */
RCC_APB2PeriphClockCmd(SG90_RCC_APB2Periph_GPIOX, ENABLE);
GPIO_InitStructure.GPIO_Pin = SG90Num01_GPIOX_PinX | SG90Num02_GPIOX_PinX | SG90Num03_GPIOX_PinX | SG90Num04_GPIOX_PinX;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(SG90Num01_GPIOX, &GPIO_InitStructure);
}
void SG90_Init(void)
{
SG90_GPIO_Init();
SG90_Structure.is_num01_start = FALSE;
SG90_Structure.is_num02_start = FALSE;
SG90_Structure.is_num03_start = FALSE;
SG90_Structure.is_num04_start = FALSE;
SG90_Structure.num01_angleX = ANGLE_0;
SG90_Structure.num02_angleX = ANGLE_0;
SG90_Structure.num03_angleX = ANGLE_0;
SG90_Structure.num04_angleX = ANGLE_0;
SG90_Structure.is_num01_open = FALSE;
SG90_Structure.is_num02_open = FALSE;
SG90_Structure.is_num03_open = FALSE;
SG90_Structure.is_num04_open = FALSE;
SG90_Structure.is_num01_finish = FALSE;
SG90_Structure.is_num02_finish = FALSE;
SG90_Structure.is_num03_finish = FALSE;
SG90_Structure.is_num04_finish = FALSE;
SG90_Control(1,ANGLE_0);
SG90_Control(2,ANGLE_0);
SG90_Control(3,ANGLE_0);
SG90_Control(4,ANGLE_0);
}
u8 Counter_01 = 0;
#define PWM_Cycle 40 //40*500us = 20ms
u8 Duoji_WaitTime01=0;
u8 Duoji_WaitTime02=0;
u8 Duoji_WaitTime03=0;
u8 Duoji_WaitTime04=0;
#define Duoji_WaitTime_Max 36 //设置转动等待时间 36个信号周期---500us/1周期
STRUCT_SG90 SG90_Structure;
void SG90_ControlAngleX(void) //uint16_t SG90NumX_GPIOX_PinX,ENUM_ANGLE angle
{
Counter_01++;
if(Counter_01>=PWM_Cycle) //一个周期20ms //LED_Control(REVERSE);
{
Counter_01=0;
if(SG90_Structure.is_num01_start == TRUE)
{
Duoji_WaitTime01++;
if(Duoji_WaitTime01>Duoji_WaitTime_Max)
{
Duoji_WaitTime01=0;
SG90_Structure.is_num01_finish = TRUE;
SG90_Structure.is_num01_start = FALSE;
}
}
else
{
Duoji_WaitTime01=0;
// SG90_Structure.is_num01_finish = FALSE;
}
if(SG90_Structure.is_num02_start == TRUE)
{
Duoji_WaitTime02++;
if(Duoji_WaitTime02>Duoji_WaitTime_Max)
{
Duoji_WaitTime02=0;
SG90_Structure.is_num02_finish = TRUE;
SG90_Structure.is_num02_start = FALSE;
}
}
else
{
Duoji_WaitTime02=0;
// SG90_Structure.is_num02_finish = FALSE;
}
if(SG90_Structure.is_num03_start == TRUE)
{
Duoji_WaitTime03++;
if(Duoji_WaitTime03>Duoji_WaitTime_Max)
{
Duoji_WaitTime03=0;
SG90_Structure.is_num03_finish = TRUE;
SG90_Structure.is_num03_start = FALSE;
}
}
else
{
Duoji_WaitTime03=0;
// SG90_Structure.is_num03_finish = FALSE;
}
if(SG90_Structure.is_num04_start == TRUE)
{
Duoji_WaitTime04++;
if(Duoji_WaitTime04>Duoji_WaitTime_Max)
{
Duoji_WaitTime04=0;
SG90_Structure.is_num04_finish = TRUE;
SG90_Structure.is_num04_start = FALSE;
}
}
else
{
Duoji_WaitTime04=0;
// SG90_Structure.is_num04_finish = FALSE;
}
}
if(SG90_Structure.is_num01_start == TRUE)
{
if(Counter_01 <= SG90_Structure.num01_angleX)
{
GPIO_SetBits(SG90Num01_GPIOX,SG90Num01_GPIOX_PinX);
}
else
{
GPIO_ResetBits(SG90Num01_GPIOX,SG90Num01_GPIOX_PinX);
}
}
if(SG90_Structure.is_num02_start == TRUE)
{
if(Counter_01 <= SG90_Structure.num02_angleX)
{
GPIO_SetBits(SG90Num02_GPIOX,SG90Num02_GPIOX_PinX);
}
else
{
GPIO_ResetBits(SG90Num02_GPIOX,SG90Num02_GPIOX_PinX);
}
}
if(SG90_Structure.is_num03_start == TRUE)
{
if(Counter_01 <= SG90_Structure.num03_angleX)
{
GPIO_SetBits(SG90Num03_GPIOX,SG90Num03_GPIOX_PinX);
}
else
{
GPIO_ResetBits(SG90Num03_GPIOX,SG90Num03_GPIOX_PinX);
}
}
if(SG90_Structure.is_num04_start == TRUE)
{
if(Counter_01 <= SG90_Structure.num04_angleX)
{
GPIO_SetBits(SG90Num04_GPIOX,SG90Num04_GPIOX_PinX);
}
else
{
GPIO_ResetBits(SG90Num04_GPIOX,SG90Num04_GPIOX_PinX);
}
}
}
void SG90_Control(u8 numX,ENUM_ANGLE angleX)
{
switch(numX)
{
case 1:
SG90_Structure.is_num01_start = TRUE;
SG90_Structure.is_num01_finish = FALSE;
SG90_Structure.num01_angleX = angleX;
while(SG90_Structure.is_num01_finish == FALSE);
time3_struct.Counter_01 = 0;
time3_struct.is_5000MS_01Arrive = FALSE;
break;
case 2:
SG90_Structure.is_num02_start = TRUE;
SG90_Structure.is_num02_finish = FALSE;
SG90_Structure.num02_angleX = angleX;
while(SG90_Structure.is_num02_finish == FALSE);
time3_struct.Counter_02 = 0;
time3_struct.is_5000MS_02Arrive = FALSE;
break;
case 3:
SG90_Structure.is_num03_start = TRUE;
SG90_Structure.is_num03_finish = FALSE;
SG90_Structure.num03_angleX = angleX;
while(SG90_Structure.is_num03_finish == FALSE);
time3_struct.Counter_03 = 0;
time3_struct.is_5000MS_03Arrive = FALSE;
break;
case 4:
SG90_Structure.is_num04_start = TRUE;
SG90_Structure.is_num04_finish = FALSE;
SG90_Structure.num04_angleX = angleX;
while(SG90_Structure.is_num04_finish == FALSE);
time3_struct.Counter_04 = 0;
time3_struct.is_5000MS_04Arrive = FALSE;
break;
default:break;
}
}
/*******************************************************************************
\* 文件名称:基于stm32蓝牙智能语音识别分类播报垃圾桶
\* 实验目的:1.
\* 2.
\* 程序说明:完整程序Q:277 227 2579;@: itworkstation@ hotmail.com
\* 日期版本:本项目分享关键细节,熟悉使用单片机的可做参考代码。完整讲解+源代码工程可联系获取,可定制。
*******************************************************************************/
/*******************************************************************************
* 适配工程:最小系统板STM32C8T6镀金板
* 舵机占空比与运行角度的关系
0.5ms--------------0度;
1.0ms------------45度;
1.5ms------------90度;
2.0ms-----------135度;
2.5ms-----------180度;
*******************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "SG90.h"
#include "bsp_timer4.h"
#include "usart1.h"
#include "Lu_ASR01.h"
#include "usart2.h"
#include "bsp_timer3.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
extern const unsigned char BMP1[];
/**
* @说明 主函数
* @参数 None
* @返回值 None
*/
STRUCT_NVICPriority NVICPriority_Structure;
void sysInit(void)
{
/*---------------------初始化中断顺序,0:最优先---------------------*/
NVICPriority_Structure.Tim4 = 1;
NVICPriority_Structure.Usart1 = 2;
NVICPriority_Structure.Usart2 = 3;
NVICPriority_Structure.Tim3 = 0;
/*----------------------外设初始化,配置参数-------------------------------------*/
TIM4_Init();
SG90_Init();
USART1_Init();
USART2_Init();
/*-----------------------舵机控制:归0------------------------------------*/
SG90_Control(1,ANGLE_0);
SG90_Control(2,ANGLE_0);
SG90_Control(3,ANGLE_0);
SG90_Control(4,ANGLE_0);
LED_Init();
/*------------------------屏幕初始,IO等-----------------------------------*/
OLED_Init();
LCD_Display(); //显示---欢迎界面
Delay_ms(5000); //延时5S
LCD_Menu = LCD_SHOWMESSAGE;LCD_refresh = TRUE; //变换界面
// LED_Control(ON);
// Delay_ms(5000);
// LED_Control(OFF);
// Delay_ms(5000);
TIM3_Init();
}
int main(void)
{
sysInit();
while(1){
parseASR01Buffer();
if (ASR01_Data.isUsefull)
{
ASR01_Data.isUsefull = FALSE;
LCD_refresh=TRUE; //屏幕同步刷新状态
}
if(SG90_Structure.is_num01_finish) //舵机转动结束
{
if(time3_struct.is_5000MS_01Arrive) //5s标志位
{
time3_struct.is_5000MS_01Arrive = FALSE;
SG90_Structure.is_num01_finish = FALSE;
if(SG90_Structure.num01_angleX != ANGLE_0) //若舵机角度不等于0°,说明在90°状态--
{
SG90_Control(1,ANGLE_0); //舵机归0
SG90_Structure.is_num01_open = FALSE;
printf("$C1@"); //CLOSE1 -- 缩写C1 同步状态给手机
LCD_refresh=TRUE;
}
}
}
if(SG90_Structure.is_num02_finish)
{
if(time3_struct.is_5000MS_02Arrive)
{
time3_struct.is_5000MS_02Arrive = FALSE;
SG90_Structure.is_num02_finish = FALSE;
if(SG90_Structure.num02_angleX != ANGLE_0)
{
SG90_Control(2,ANGLE_0);
SG90_Structure.is_num02_open = FALSE;
printf("$C2@"); //CLOSE2 -- 缩写C1
LCD_refresh=TRUE;
}
}
}
if(SG90_Structure.is_num03_finish)
{
if(time3_struct.is_5000MS_03Arrive)
{
time3_struct.is_5000MS_03Arrive = FALSE;
SG90_Structure.is_num03_finish = FALSE;
if(SG90_Structure.num03_angleX != ANGLE_0)
{
SG90_Control(3,ANGLE_0);
SG90_Structure.is_num03_open = FALSE;
printf("$C3@"); //CLOSE3 -- 缩写C1
LCD_refresh=TRUE;
}
}
}
if(SG90_Structure.is_num04_finish)
{
if(time3_struct.is_5000MS_04Arrive)
{
time3_struct.is_5000MS_04Arrive = FALSE;
SG90_Structure.is_num04_finish = FALSE;
if(SG90_Structure.num04_angleX != ANGLE_0)
{
SG90_Control(4,ANGLE_0);
SG90_Structure.is_num04_open = FALSE;
printf("$C4@"); //CLOSE4 -- 缩写C1
LCD_refresh=TRUE;
}
}
}
LCD_Display();
}
}