【STM32嵌入式系统设计与开发】——15PassiveBeep(无源蜂鸣器应用_GPIO输出状态实现)

这里写目录标题


STM32资料包:

百度网盘下载链接:链接:https://pan.baidu.com/s/1mWx9Asaipk-2z9HY17wYXQ?pwd=8888

提取码:8888


一、任务描述

二、任务实施

观察电路图:

TXD(底板) ------------------------> PA10

RXD(底板) ------------------------> PA9

P11 (底板) ------------------------> PA12

使用USB-AB型数据线,连接15核心板USB口,串口发送接收到的数据。

1、工程文件夹创建

步骤1:复制工程模板"1_Template"重命名为"12_PassiveBeep"。

步骤2:修改项目工程名,先删除projects文件夹内除了Template.uvprojx文件外的所有内容并修改为"PassiveBeep.uvprojx"。并删除output/obj和output/lst中的所有文件。

步骤3:运行"PassiveBeep.uvprojx"打开目标选项"Options for Target"中的"Output"输出文件,并修改可执行文件名称为"PWM"点击"OK"保存设置。最后点击"Rebuild"编译该工程生成Usart文件。

步骤4:复制2_LEDTest中的"1_LED"和文件复制到hardware中。

步骤5:在"bsplibrary"中新建"passivebeep"文件夹,并新建"passivebeep.c"和"passivebeep.h"文件。

步骤5:工程组文件中添加"led"和"passivebeep"文件夹内的所有文件。

步骤6:目标选项添加添加头文件路径。

2、函数编辑

(1)主函数编辑

通过初始化GPIO控制无源蜂鸣器的引脚,并在循环中播放预先定义的音乐,实现了简单的音乐播放功能

步骤1:端口初始化准备

c 复制代码
	//函数初始化,端口准备
	uint32_t temp=0;
	delay_init();            //启动滴答定时器
    usart1_init(9600);       //USART1初始化
	LED_Init();              //板载LED初始化
	ExpLEDInit();            //开发板LED初始化
    BEEP_Init();             //无源蜂鸣器初始化 

步骤2:实现一个简单的计时器,并在每秒打印一次计时信息。利用LED状态的改变来指示系统正在运行。

c 复制代码
while(1) 
  {
	play_music(); //播放音乐		 
  }

(2)USART1初始化函数(usart1_init())

配置了 PA9 为复用推挽输出,用于 USART1 的 TXD,并配置了 PA10 为浮空输入,用于 USART1 的 RXD。并配置了 USART1 的参数,包括波特率、数据位长度、停止位数、校验位、硬件流控制和工作模式。

c 复制代码
/*********************************************************************
 @Function  : USART1初始化
 @Parameter : bound : 波特率 
 @Return    : N/A
**********************************************************************/   	
void usart1_init(uint32_t bound)
{
    GPIO_InitTypeDef GPIO_InitStructure;             										          // 定义 GPIO 初始化结构体
    USART_InitTypeDef USART_InitStructure;            										          // 定义 USART 初始化结构体
    NVIC_InitTypeDef NVIC_InitStructure;              										          // 定义 NVIC 初始化结构体

    /* 时钟使能:启用 USART1 和 GPIOA 的时钟 */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);

    /* 引脚复用配置 */  
    // 配置 PA9 为复用推挽输出,用于 USART1 的 TXD
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;   		                             // 设置 GPIO 端口
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;                                // 设置 GPIO 速度
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; 								 // 设置 GPIO 模式为复用推挽
    GPIO_Init(GPIOA, &GPIO_InitStructure);          							     // 初始化 GPIO

    // 配置 PA10 为浮空输入,用于 USART1 的 RXD
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;                                      // 设置 GPIO 端口
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;                           // 设置 GPIO 模式为浮空输入
    GPIO_Init(GPIOA, &GPIO_InitStructure);                                          // 初始化 GPIO

    /* NVIC 中断配置 */ 
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;                               // 设置中断通道为 USART1
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;                       // 设置抢占优先级为3
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;                              // 设置子优先级为3
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                                 // 使能中断通道
    NVIC_Init(&NVIC_InitStructure);                                                 // 初始化 NVIC

    /* USART1 配置 */ 
    USART_InitStructure.USART_BaudRate = bound;                                     // 设置波特率
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;                     // 设置数据位长度为8位
    USART_InitStructure.USART_StopBits = USART_StopBits_1;                          // 设置停止位为1位
    USART_InitStructure.USART_Parity = USART_Parity_No;                             // 设置校验位为无校验
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // 设置硬件流控制为无
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;                 // 设置工作模式为接收和发送
    USART_Init(USART1, &USART_InitStructure);                                       // 初始化 USART1

		/*中断配置*/
		USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);                                //开接受中断 
		USART_ITConfig(USART1,USART_IT_IDLE,ENABLE);                                //开空闲中断
		USART_ITConfig(USART1,USART_IT_TXE,ENABLE);                                 //开发送中断	
		USART_Cmd(USART1, ENABLE);                                                  //启用USART1
		USART_DataTypeStr.Usart_Tc_State = SET;	                                    //置位发送允许标志	      
}

(3)USART数据发送函数( USART1_Send_Data())

初始化PD14端口,并为推挽输出。

c 复制代码
/*********************************************************************
 @Function  : USART数据发送函数
 @Parameter : Data 	 :要发送的数据缓存.
							Lenth  :发送长度
 @Return    : 发送状态   1 :失败   0 :成功
**********************************************************************/
char USART1_Send_Data(char* Data,uint8_t Lenth) 
{
	uint8_t uNum = 0;
	if(USART_DataTypeStr.Usart_Tc_State == 1)                       //判断发送标志位是否置1
	{
		USART_DataTypeStr.Usart_Tc_State = 0;                       //将发送标志位清零,表示数据已经成功放入缓存,等待发送
		USART_DataTypeStr.Usart_Tx_Len = Lenth;                     //获取需要发送的数据的长度       
	  for(uNum = 0;uNum < USART_DataTypeStr.Usart_Tx_Len;uNum ++)   //将需要发送的数据放入发送缓存
	  {
		  USART_DataTypeStr.Usart_Tx_Buffer[uNum] = Data[uNum];
	  }
    USART_ITConfig(USART1,USART_IT_TXE,ENABLE);			            //数据放入缓存后打开发送中断,数据自动发送
	}
	return USART_DataTypeStr.Usart_Tc_State;                        //返回放数据的状态值,为1表示发送失败,为0表示发送成功了
}

(4)USART数据发送函数( USART1_IRQHandler())

c 复制代码
/*********************************************************************
 @Function  : USART1中断服务函数
 @Parameter : N/A 
 @Return    : N/A
**********************************************************************/
void USART1_IRQHandler(void)                
{
	 uint8_t Clear = Clear;                                                                           // 定义清除标志的变量,并初始化为自身
	static uint8_t uNum = 0;                                                                          // 静态变量,用于循环计数
	 
  if(USART_GetITStatus(USART1,USART_IT_RXNE) != RESET)                                                // 判断读数据寄存器是否为非空
  {
    USART_ClearFlag(USART1, USART_IT_RXNE);                                                           // 清零读数据寄存器,其实硬件也可以自动清零
    USART_DataTypeStr.Usart_Rx_Buffer[USART_DataTypeStr.Usart_Rx_Num ++] = \
		(uint16_t)(USART1->DR & 0x01FF);                                                              // 将接收到的数据存入接收缓冲区
		(USART_DataTypeStr.Usart_Rx_Num) &= 0xFF;                                                     // 防止缓冲区溢出
  } 
	
	else if(USART_GetITStatus(USART1,USART_IT_IDLE) != RESET)   // 检测空闲
	{
	  Clear = USART1 -> SR;                                                                         // 读SR位
		Clear = USART1 -> DR;                                                                       // 读DR位,
	  USART_DataTypeStr.Usart_Rx_Len = USART_DataTypeStr.Usart_Rx_Num;                              // 获取数据长度
		for(uNum = 0; uNum < USART_DataTypeStr.Usart_Rx_Len; uNum ++)          
		{
				USART_DataTypeStr.Usart_Rx_Data[uNum] = USART_DataTypeStr.Usart_Rx_Buffer[uNum];      // 将接收到的数据复制到接收数据缓冲区
		}
		USART_DataTypeStr.Usart_Rx_Num = 0;                                                           // 清空接收计数器
		USART_DataTypeStr.Usart_Rc_State = 1;                                                         // 数据读取标志位置1,读取串口数据
	}
	
	if(USART_GetITStatus(USART1,USART_IT_TXE) != RESET)                                                  // 判断发送寄存器是否为非空
  {
		USART1->DR = \
		((USART_DataTypeStr.Usart_Tx_Buffer[USART_DataTypeStr.Usart_Tx_Num ++]) & (uint16_t)0x01FF);    // 发送数据
		(USART_DataTypeStr.Usart_Tx_Num) &= 0xFF;                                                       // 防止缓冲区溢出
    if(USART_DataTypeStr.Usart_Tx_Num >= USART_DataTypeStr.Usart_Tx_Len)
    {   
			USART_ITConfig(USART1,USART_IT_TXE,DISABLE);                                                // 发送完数据,关闭发送中断
			USART_DataTypeStr.Usart_Tx_Num = 0;                                                         // 清空发送计数器
			USART_DataTypeStr.Usart_Tc_State = 1;                                                       // 发送标志置1,可以继续发送数据了
    } 		
	}
	
}

(5)无源蜂鸣器GPIO初始化函数( BEEP_Init())

初始化PA12端口,并为推挽输出。

c 复制代码
/*********************************************************************
 @Function  : 无源蜂鸣器引脚定义
 @Parameter : N/A
 @Return    : N/A
**********************************************************************/ 
void BEEP_Init(void)
{ 
    GPIO_InitTypeDef  GPIO_InitStructure;                 // 定义GPIO初始化结构体变量
  
	/*时钟使能*/	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 使能GPIOA的时钟
	
	/*引脚配置*/		
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;            // 设置引脚为GPIOA的Pin 12,即BEEP对应的引脚
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;      // 设置引脚为推挽输出模式
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;     // 设置引脚的输出速度为50MHz
	GPIO_Init(GPIOA, &GPIO_InitStructure);                // 根据GPIO初始化结构体参数配置GPIOA
	GPIO_ResetBits(GPIOA,GPIO_Pin_12);                    // 将GPIOA的Pin 12引脚输出低电平
}

(6)合成音符函数( Sound())

c 复制代码
/*********************************************************************
 @Function  : 合成音符
 @Parameter : frq : 音符频率
 @Return    : N/A
**********************************************************************/
void Sound(uint16_t frq)
{
  uint32_t time;                     // 定义延时时间变量
  
  if(frq != 1000)                    // 判断音符频率是否为1000
  {
    time = 500000 / ((uint32_t)frq); // 计算延时时间
    BEEP = 1;                        // 给蜂鸣器引脚输出高电平,使蜂鸣器响
    delay_us(time);                  // 微秒级延时,使蜂鸣器持续一段时间
    BEEP = 0;                        // 给蜂鸣器引脚输出低电平,关闭蜂鸣器
    delay_us(time);                  // 微秒级延时,使蜂鸣器停止响
  }
  else
    delay_us(1000);                   // 如果音符频率为1000,直接进行1毫秒的延时
}

(7)播放音乐函数( play_music())

c 复制代码
/*********************************************************************
 @Function  : 播放音乐
 @Parameter : N/A
 @Return    : N/A
**********************************************************************/
void play_music(void)
{    
  uint16_t i, e;                                                       // 定义循环变量 i、e
  uint32_t yanshi = 10;                                                // 定义延时系数变量
  
  for(i = 0; i < sizeof(music) / sizeof(music[0]); i++)                // 外层循环遍历乐谱音调数组
  {
    for(e = 0; e < ((uint16_t)time[i]) * tone[music[i]] / yanshi; e++) // 内层循环根据乐谱和节拍时间控制音符持续时间
    {
       Sound((uint32_t)tone[music[i]]);                                // 调用合成音符函数,根据乐谱音调播放音符
    }
  }
}

3、宏定义

步骤1:主函数添加所需的头文件,主源文件部分报错消失

c 复制代码
//头文件包含
/***********Hardweare***************/
#include "led.h"
#include "passivebeep.h"

步骤2:添加中断源文件所需的头文件

c 复制代码
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
#include ".\delay\delay.h"
#include "passivebeep.h"

/******红海情歌******/
/*音调*/               // 0   1   2   3   4   5   6   7  低1  低2 低3 低4 低5 低6低7
const uint16_t tone[] = {247,262,294,330,349,392,440,294,523,587,659,698,784,1000};   
/*乐谱音调*/
uint8_t music[] = 
{
    5,5,6,8,7,6,5,6,13,13,5,5,6,8,7,6,5,3,13,13,2,2,3,5,3,5,6,3,2,1,6,6,5,6,5,3,6,5,13,13,
    5,5,6,8,7,6,5,6,13,13,5,5,6,8,7,6,5,3,13,13,2,2,3,5,3,5,6,3,2,1,6,6,5,6,5,3,6,1,    
    13,8,9,10,10,9,8,10,9,8,6,13,6,8,9,9,8,6,9,8,6,5,13,2,3,5,5,3,5,5,6,8,7,6,6,10,9,9,8,6,5,6,8
};
/*节拍时间*/
uint8_t time[] = 
{
    2,4,2,2,2,2,2,8,4, 4,2,4,2,2,2,2,2,8,4, 4, 2,4,2,4,2,2,4,2,2,8,2,4,2,2,2,2,2,8,4,4, 
    2,4,2,2,2,2,2,8,4, 4,2,4,2,2,2,2,2,8,4,4,2,4,2,4,2,2,4,2,2,8,2,4,2,2,2,2,2,8,
    4,2,2,2,4,2,2,2,2,2,8,4,2,2,2,4,2,2,2,2,2,8,4,2,2,2,4,2,2,5,2,6,2,4,2,2,2,4,2,4,2,2,12
};

步骤3:添加串口通信宏定义

c 复制代码
#define USART_RX_LEN  200               // 接收缓冲区最大长度
#define USART_TX_LEN  200               // 发送缓冲区最大长度
#define UART_NUM      10                // 串口结构体最大对象数量

步骤4:添加函数声明

c 复制代码
void usart1_init(uint32_t bound);
extern USART_DataTypeDef USART_DataTypeStr; 
char USART1_Send_Data(char* Data,uint8_t Lenth);

步骤5:添加数据类型和宏的头文件

c 复制代码
//定义串口数据结构体
typedef struct USART_DataType 
{
    uint8_t Usart_Rx_Len;          // 接收缓冲区长度
    uint8_t Usart_Tx_Len;          // 发送缓冲区长度
    uint8_t Usart_Rx_Num;          // 接收数据计数
    uint8_t Usart_Tx_Num;          // 发送数据计数
    uint8_t Usart_Rc_State;        // 接收状态标志位
    uint8_t Usart_Tc_State;        // 发送状态标志位
    char Usart_Rx_Buffer[USART_RX_LEN]; // 接收缓冲区
    char Usart_Tx_Buffer[USART_TX_LEN]; // 发送缓冲区
    char Usart_Rx_Data[USART_RX_LEN];   // 接收数据
    char Usart_Tx_Data[USART_TX_LEN];   // 发送数据
} USART_DataTypeDef;

步骤6:定义一个串口数组变量

c 复制代码
USART_DataTypeDef USART_DataTypeStr={0};

窗口看门狗宏定义

步骤1:创建一个宏定义保护

c 复制代码
#ifndef _WWDG_H
#define _WWDG_H



#endif

步骤2:添加函数声明

c 复制代码
void WWDG_Init(uint8_t tr,uint8_t wr,uint32_t fprer);
void WWDG_Set_Counter(uint8_t cnt);       
void WWDG_NVIC_Init(void);

步骤3:添加数据类型和宏的头文件

c 复制代码
#include <stdint.h> 

无源蜂鸣器头文件编辑

步骤1:创建一个宏定义保护

c 复制代码
#ifndef __PWM_H_
#define __PWM_H_



#endif

步骤2:添加函数声明

c 复制代码
//函数声明
void BEEP_Init(void);         
void Sound(uint16_t frq);
void play_music(void);

步骤3:添加数据类型和宏的头文件

c 复制代码
//宏定义
#define BEEP PAout(12)                // PA12

步骤3:添加数据类型和宏的头文件

c 复制代码
#include<stdint.h> 
#include ".\sys\sys.h"

4、知识链接

(1)无源蜂鸣器基础知识

无源蜂鸣器就像是一个小的震动装置,类似于手机的振动器。它的工作原理类似于我们轻轻敲击一个玻璃杯,它会产生清脆的声音。无源蜂鸣器中有一个特殊的材料,当我们给它通电时,它会开始振动,就像一个微型的震动器一样。这种振动产生了声音,就像我们用手敲击玻璃杯一样。通过控制通电的方式和频率,我们可以控制蜂鸣器发出的声音的音调和持续时间,就像我们用手敲击玻璃杯时可以产生不同音调的声音一样。

(2)音符与频率理解


5、工程测试

相关推荐
杰克逊的日记9 天前
MCU编程
单片机·嵌入式硬件
Python小老六9 天前
单片机测ntc热敏电阻的几种方法(软件)
数据库·单片机·嵌入式硬件
懒惰的bit9 天前
STM32F103C8T6 学习笔记摘要(四)
笔记·stm32·学习
HX科技9 天前
STM32给FPGA的外挂FLASH进行升级
stm32·嵌入式硬件·fpga开发·flash·fpga升级
Suagrhaha9 天前
驱动入门的进一步深入
linux·嵌入式硬件·驱动
国科安芯9 天前
基于ASP4644多通道降压技术在电力监测系统中集成应用与发展前景
嵌入式硬件·硬件架构·硬件工程
Li Zi9 天前
STM32 ADC(DMA)双缓冲采集+串口USART(DMA)直接传输12位原始数据到上位机显示并保存WAV格式音频文件 收藏住绝对实用!!!
经验分享·stm32·单片机·嵌入式硬件
进击的程序汪9 天前
触摸屏(典型 I2C + Input 子系统设备)从设备树解析到触摸事件上报
linux·网络·嵌入式硬件
damo王9 天前
Zephyr 系统深入解析:SoC 支持包结构与中断调度器调优实践
单片机·嵌入式硬件·zephyr
逼子格9 天前
硬件工程师笔试面试高频考点汇总——(2025版)
单片机·嵌入式硬件·面试·硬件工程·硬件工程师·硬件工程师真题·硬件工程师面试