B44 - 基于stm32蓝牙智能语音识别分类播报垃圾桶

任务

题目:基于stm32蓝牙智能语音识别分类播报垃圾桶
实现功能如下:

  1. 语音识别根据使用者发出的指令自动对垃圾进行分类
  2. 根据垃圾的种类实时播报垃圾的类型
  3. 根据垃圾种类驱动对应的舵机进行转动(模拟垃圾桶打开,并在十秒钟自动复位,模拟垃圾桶关闭)
  4. OLED显示屏实时显示四种垃圾桶的状态
  5. 蓝牙app可以控制垃圾桶开关,同时显示四种垃圾桶状态

效果

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

原理图

在这里插入图片描述
在这里插入图片描述

指令编码

在这里插入图片描述
在这里插入图片描述

语音识别模块

简介

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 <string.h>
#include <stdio.h>
#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();
    }     
}





猜你喜欢

转载自blog.csdn.net/qq_20467929/article/details/126137039