すのはら荘春原庄的雪

基于stm32的智能门铃-课程设计

aicyx·2025-03-01 22:31·13 次阅读

基于stm32的智能门铃-课程设计

介绍

本人的处理器项目课程设计,设计简易,仅为记录学习所用。
代码还未优化,例如全局变量应使用消息队列替换、功能简单可无需使用操作系统等等。

课设题目要求#

image

实现功能#

  1. 按键控制蜂鸣器发声
  2. 语音控制
  3. 手机蓝牙控制
  4. 乐曲选择

硬件部分

主控

STM32F103C8T6

离线语音识别模块

ASR PRO

蓝牙模块

大夏龙雀 BT24 低功耗蓝牙模块

PCB原理图

image

软件部分

ASR PRO#

中文编程,实现简单的离线语音识别。
与STM32串口通信,收发数据简单,无需使用数据包
image

手机端蓝牙#

蓝牙调试助手app
image

STM32#

CubeMX+CLion/CubeIDE/Keil

CubeMX配置
  1. 时钟
    image
    image

  2. debug与滴答时钟
    image

  3. I2C(OLED)
    image

  4. ASR PRO串口与蓝牙串口
    ASR PRO串口
    image
    image
    蓝牙串口
    image
    image
    image

  5. 按键与led灯
    image

  6. PWM
    呼吸灯
    image
    蜂鸣器
    image

  7. FreeRTOS
    基本设置
    image
    任务与消息队列
    image

主要代码

OLED库:波特律动驱动库
DMA实现:FreeRTOS 消息队列 DMA串口空闲中断接收消息

全局变量
Copy
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呼吸灯任务
Copy
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 */ }
音频播放任务与功能函数
Copy
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显示任务
Copy
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实现)
Copy
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 */ }
蓝牙串口发送与运行状态灯任务
Copy
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 */ }
按键中断回调函数
Copy
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); } }
语音串口中断回调函数
Copy
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

posted @   aicyx  阅读(13)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
点击右上角即可分享
微信分享提示
目录