基于stm32的智能门铃-课程设计
介绍
本人的处理器项目课程设计,设计简易,仅为记录学习所用。
代码还未优化,例如全局变量应使用消息队列替换、功能简单可无需使用操作系统等等。
课设题目要求#
实现功能#
- 按键控制蜂鸣器发声
- 语音控制
- 手机蓝牙控制
- 乐曲选择
硬件部分
主控
STM32F103C8T6
离线语音识别模块
ASR PRO
蓝牙模块
大夏龙雀 BT24 低功耗蓝牙模块
PCB原理图
软件部分
ASR PRO#
中文编程,实现简单的离线语音识别。
与STM32串口通信,收发数据简单,无需使用数据包
手机端蓝牙#
蓝牙调试助手app
STM32#
CubeMX+CLion/CubeIDE/Keil
CubeMX配置
-
时钟
-
debug与滴答时钟
-
I2C(OLED)
-
ASR PRO串口与蓝牙串口
ASR PRO串口
蓝牙串口
-
按键与led灯
-
PWM
呼吸灯
蜂鸣器
-
FreeRTOS
基本设置
任务与消息队列
主要代码
OLED库:波特律动驱动库
DMA实现:FreeRTOS 消息队列 DMA串口空闲中断接收消息
全局变量
int request=0,overTM=0;//按下请求、播放次数
char countTM[32]={0};
int musicc=0;//曲谱切换标志位
const uint16_t notes1[] = {0, 261, 294, 329, 349, 392, 440, 493};
const uint8_t melody1[] = {1, 1, 5, 5, 6, 6, 5, 0, 4, 4, 3, 3, 2, 2, 1, 0};
const uint16_t notes2[] = {0,523,587,659,698,784,880,988,1046,1175,1318,1397,1568,1760,1976};
const uint8_t melody2[] = {0,0,9,9,6,7,6,5,3,5,2,2,2,2,0,0,9,10,6,7,6,5,3,5,6,6,6,6,9,9,6,7,6,6,6,5,6,6,6,5,3,3,3,3,3,3,3,6,6,6,5,3,2,2,2,2,0,0,2,2,3,3,5,5,3,3,6,6,6,6,0,0,7,7,7,6,5,5,6,5,3,3,3,3,3,3,3,3,3,3,3,5,5,6,6,6,7,6,6,5,5,3,3,3,5,6,5,5,3,2,2,2,2,2};
static uint8_t send_data[] = {0xA5, 0x00, 0x00, 0x5A};
uint8_t rx_data[2];// 串口接收缓冲区
uint8_t blu=0,spe=0;
LED呼吸灯任务
void vmainTask(void const * argument)
{
/* USER CODE BEGIN vmainTask */
// 开启串口中断接收
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);
HAL_UART_Receive_IT(&huart2, rx_data, 2);
/* Infinite loop */
for(;;)
{
if(request==1){
for (int period = 0; period < 100; period++){
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, period);
osDelay(10);
if(request==0)
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, 0);
}
}
if(request==1){
for (int period = 99; period >= 0; period--){
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, period);
osDelay(10);
if(request==0)
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, 0);
}
}
if(request==0)
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, 0);
osDelay(1);
}
/* USER CODE END vmainTask */
}
音频播放任务与功能函数
void vPlayTask(void const * argument)
{
/* USER CODE BEGIN vPlayTask */
/* Infinite loop */
for(;;)
{
if(request==1&&musicc==0)
{
for(overTM=0;overTM<8;overTM++)
{
for (int j = 0; j < sizeof(melody1)/sizeof(melody1[0]); j++)
{
PlayNote(notes1[melody1[j]]);
if(request==0){
HAL_TIM_PWM_Stop(&htim4, TIM_CHANNEL_4);
break;
}
osDelay(500); // 每拍0.5秒
}
if(request==0)
break;
}
request=0;
}
if(request==1&&musicc==1)
{
for(overTM=0;overTM<8;overTM++)
{
for (int j = 0; j < sizeof(melody2)/sizeof(melody2[0]); j++)
{
PlayNote(notes2[melody2[j]]);
if(request==0){
HAL_TIM_PWM_Stop(&htim4, TIM_CHANNEL_4);
break;
}
osDelay(250); // 每拍0.25秒
}
if(request==0)
break;
}
request=0;
}
osDelay(1);
}
/* USER CODE END vPlayTask */
}
void PlayNote(uint16_t frequency)
{
HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_4);//打开蜂鸣器pwm输出
if(frequency>0)
{
htim4.Instance->ARR = 1000000/frequency;
__HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_4, htim4.Instance->ARR / 5);
}
else
{
__HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_4, 0);
}
}
OLED显示任务
void vOLEDTask(void const * argument)
{
/* USER CODE BEGIN vOLEDTask */
osDelay(20);
OLED_Init(); // 初始化OLED
OLED_NewFrame();
/* Infinite loop */
for(;;)
{
OLED_NewFrame();
OLED_PrintString(0, 0, "播放次数:", &font16x16, OLED_COLOR_NORMAL);
OLED_PrintString(0, 17, "语音识别:", &font16x16, OLED_COLOR_NORMAL);
OLED_PrintString(0, 33, "蓝牙:", &font16x16, OLED_COLOR_NORMAL);
OLED_PrintString(0, 49, "乐曲:", &font16x16, OLED_COLOR_NORMAL);
sprintf(countTM, "%d", overTM);
OLED_PrintString(81, 0,countTM, &font16x16, OLED_COLOR_NORMAL);
if(blu==1)
OLED_PrintString(81, 33, "已连接", &font16x16, OLED_COLOR_NORMAL);
else
OLED_PrintString(81, 33, "未连接", &font16x16, OLED_COLOR_NORMAL);
if(spe==1)
OLED_PrintString(81, 17, "已连接", &font16x16, OLED_COLOR_NORMAL);
else
OLED_PrintString(81, 17, "未连接", &font16x16, OLED_COLOR_NORMAL);
if(musicc==0)
OLED_PrintString(81, 49, "1", &font16x16, OLED_COLOR_NORMAL);
else
OLED_PrintString(81, 49, "2", &font16x16, OLED_COLOR_NORMAL);
OLED_ShowFrame();
osDelay(10);
}
/* USER CODE END vOLEDTask */
}
蓝牙串口接收任务(参考DMA实现)
void vBULETask(void const * argument)
{
/* USER CODE BEGIN vBULETask */
UART_RX_TypeDef *pRecvUartData; /* 定义指向串口数据的指针 */
uint8_t *data_ptr;
/* Infinite loop */
for(;;)
{
if (xQueueReceive(blueQueueHandle, &pRecvUartData, portMAX_DELAY) == pdTRUE)
{
data_ptr = pRecvUartData->buffer;
HAL_UART_Transmit(&huart3, pRecvUartData->buffer, pRecvUartData->size, 1000);
if (data_ptr[1] == 0x01&&data_ptr[2]==0x01){
HAL_TIM_PWM_Stop(&htim4, TIM_CHANNEL_4);
request=0;
overTM=0;
}
if(data_ptr[2]==0x01){
blu=1;
}
else if(data_ptr[2]==0x00){
blu=0;
}
}
osDelay(1);
}
/* USER CODE END vBULETask */
}
蓝牙串口发送与运行状态灯任务
void vTXBLUETask(void const * argument)
{
/* USER CODE BEGIN vTXBLUETask */
uint8_t aicyx=0;
/* Infinite loop */
for(;;)
{
switch(overTM){
case 0:break;
case 1:send_data[1]=send_data[2]=0x01;break;
case 2:send_data[1]=send_data[2]=0x02;break;
case 3:send_data[1]=send_data[2]=0x03;break;
case 4:send_data[1]=send_data[2]=0x04;break;
case 5:send_data[1]=send_data[2]=0x05;break;
case 6:send_data[1]=send_data[2]=0x06;break;
case 7:send_data[1]=send_data[2]=0x07;break;
case 8:send_data[1]=send_data[2]=0x08;break;
}
if(blu==1)
HAL_UART_Transmit(&huart3, send_data, sizeof(send_data), 1000);
aicyx=~aicyx;
HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, aicyx);
osDelay(500);
}
/* USER CODE END vTXBLUETask */
}
按键中断回调函数
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
// 确认一下是否为KEY1按下
if(HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin) == 0){
HAL_TIM_PWM_Stop(&htim4, TIM_CHANNEL_4);
request=0;
overTM=0;
// 等待KEY1松开
while(HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin) == 0);
}
// 确认一下是否为KEY2按下
if(HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin) == 0){
request=1;
overTM=0;
// 等待KEY2松开
while(HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin) == 0);
}
if(HAL_GPIO_ReadPin(KEY3_GPIO_Port, KEY3_Pin) == 0){
if(musicc==0)
musicc=1;
else
musicc=0;
// 等待KEY3松开
while(HAL_GPIO_ReadPin(KEY3_GPIO_Port, KEY3_Pin) == 0);
}
}
语音串口中断回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){
if (huart->Instance == USART2){
if(rx_data[0]=='1'&&rx_data[1]=='0'){
request=1;
overTM=0;
}
else if(rx_data[0]=='0'&&rx_data[1]=='1'){
HAL_TIM_PWM_Stop(&htim4, TIM_CHANNEL_4);
request=0;
overTM=0;
}
else if(rx_data[0]=='0'&&rx_data[1]=='0'){
spe=1;
}
HAL_UART_Receive_IT(&huart2, rx_data, 2);
}
}
音频1为题目要求音乐
音频2为马云之歌(简单整活,音频实现过于简易)
注意:任务间尽量不要使用全局变量传递消息(虽然此程序使用全局变量并未发现bug)。博主当时还未深刻学习FreeRTOS,不知全局变量风险。#
源码地址:https://gitee.com/ZhouYuxin123/smart-doorbell---course-design/tree/master
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?