前言:之前的STM32L433CB单片机还有几个模块没有解决,最佳抽空把按键模块和PWM蜂鸣器模块调通了。
1.按键模块
按键模块重点是需要了解中断模式:
(1)中断简而言之是暂时中止当前的工作,而去处理更为急需处理的事情,把急需处理的事情处理完毕之后,再回头来继续原来的事情。
(2)stm32的中断分为抢占优先级和响应优先级。抢占优先级高的中断,可以打断抢占优先级低的中断。抢占优先级相同的中断,响应优先级高的可以优先执行。
(3)中断向量表:中断向量是中断服务程序的入口地址,在计算机中中断向量的地址存放一条跳转到中断服务程序的跳转指令。中断地址是存储中断向量的内存单元。中断向量表是用来存放中断向量
(4)嵌套中断:中断系统正在执行一个中断服务时,有另一个优先级更高的中断提出中断请求,这时会暂时终止当前正在执行的级别较低的中断源的服务程序,去处理级别更高的中断源,待处理完毕,再返回到被中断了的中断服务程序继续执行,这个过程就是中断嵌套。如果中断里调用HAL_Delay就会停在那里,因为根本不会进入那个级别更低的中断。CUBE生成的程序中, SysTick是中断型延时,SysTick是内核中断,优先级别默认最低。所以我后面的延时函数使用了SysTick。
了解中断之后就是STM32中的按键:
按键需要上拉电阻,当按键按下接地,低电平导通,CPU读取低电平
配置方法
使按键对应的PC13和PA15为GPIO模式,勾上修改,将GPIO mode 设置为下降沿触发中断,设置电阻为上拉电阻。
使能按键中断,两个按键中断优先级是一样的
2.PWM蜂鸣器模块
pwm波形产生的原理:
通用定时器可以利用GPIO引脚进行脉冲输出,在配置为比较输出、PWM输出功能时,捕获/比较寄存器TIMx_CCR被用作比较功能,下面把它简称为比较寄存器。
这里直接举例说明定时器的PWM输出工作过程:若配置脉冲计数器TIMx_CNT为向上计数,而重载寄存器TIMx_ARR被配置为N,即TIMx_CNT的当前计数值数值X在TIMxCLK时钟源的驱动下不断累加,当TIMx_CNT的数值X大于N时,会重置TIMx_CNT数值为0重新计数。
而在TIMxCNT计数的同时,TIMxCNT的计数值X会与比较寄存器TIMx_CCR预先存储了的数值A进行比较,当脉冲计数器TIMx_CNT的数值X小于比较寄存器TIMx_CCR的值A时,输出高电平(或低电平),相反地,当脉冲计数器的数值X大于或等于比较寄存器的值A时,输出低电平(或高电平)。
如此循环,得到的输出脉冲周期就为重载寄存器TIMx_ARR存储的数值(N+1)乘以触发脉冲的时钟周期,其脉冲宽度则为比较寄存器TIMx_CCR的值A乘以触发脉冲的时钟周期,即输出PWM的占空比为 A/(N+1) 。
(1)当 PA1 输出高电平的时候,蜂鸣器将发声, 当 PA1 输出低电平的时候,蜂鸣器停止发声。R10U为了防止蜂鸣器误发声,下拉输出,推挽输出
(2)有源蜂鸣器内含振荡源,只要一通电就发声,但发生频率固定,音色单一;无源蜂鸣器内部不含振荡源,内部结构相当于电磁场扬声器,可以通过给他输出一定频率的信号才能发声。
(3)人耳能听到的频率范围在20Hz–20kHz之间,通过STM32的GPIO引脚快速切换高低电平输出就能实现无源蜂鸣器的发声,切换的频率不同,发出的音调就不一样。当CNT达到ARR值的时候,重新归零,然后重新向上计数,依次循环。改变CCRx的值,就可以改变PWM输出的占空比;改变ARR的值,就可以改变PWM输出的频率。
时钟树配置为80MHz,可知PWM的时钟为80MHz
PWM频率为80MHz/ARR,周期为1*ARR/80MHz,占空比为CRRx/ARR
修改工程名,路径和编译工具
生成代码:
stm32l4_it.c文件:
void EXTI15_10_IRQHandler(void)
{
/* USER CODE BEGIN EXTI15_10_IRQn 0 */
delay_ms(10); //延时消抖
/* USER CODE END EXTI15_10_IRQn 0 */
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_13);
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_15);
/* USER CODE BEGIN EXTI15_10_IRQn 1 */
/* USER CODE END EXTI15_10_IRQn 1 */
}
/* USER CODE BEGIN 1 */
void delay_ms(uint32_t nms) //利用SysTick写一个延时函数
{
uint32_t temp;
SysTick->LOAD = 8000*nms;
SysTick->VAL=0X00;
SysTick->CTRL=0X01;
do
{
temp=SysTick->CTRL;
}
while((temp&0x01)&&(!(temp&(1<<16))));
SysTick->CTRL=0x00;
SysTick->VAL =0X00;
}
/* USER CODE END 1 */
stm32l4_it.h文件:
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdint.h"
/* USER CODE END Includes */
/* USER CODE BEGIN EFP */
void delay_ms(uint32_t nms);
/* USER CODE END EFP */
tim.c文件:
/* USER CODE BEGIN 1 */
int tone[]={247,262,294,330,349,392,440,294,523,587,659,698,784,1000};//音调对应的频率
int yindiao[]= //音调
{
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
};
int dtime[]= //节拍
{
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
};
void sound(int freq)
{
if(freq!=1000)
{
int Arr;
TIM_OC_InitTypeDef sConfigOC = {0};
Arr = 500000/freq;
htim2.Init.Period = Arr;//改变频率来改变计数器周期
HAL_TIM_PWM_Init(&htim2);
sConfigOC.Pulse = Arr/4;
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
{
Error_Handler();
}
HAL_TIM_MspPostInit(&htim2);
}
HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_2); //使能PWM定时器
}
void buzzer_quit()
{
HAL_TIM_PWM_Stop(&htim2,TIM_CHANNEL_2);//停止PWM定时器
}
void play_mus()//播放音乐
{
int i;
for(i=0;i sound(tone[yindiao[i]]); delay_ms(150*dtime[i]); buzzer_quit(); delay_ms(20); } } /* USER CODE END 1 */ tim.h文件: /* USER CODE BEGIN Prototypes */ void sound(int freq); void start_pwm(); void buzzer_quit(); void play_mus(); /* USER CODE END Prototypes */ gpio.c文件: /* USER CODE BEGIN 2 */ void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)//中断回调函数,当按键按下跳入 { switch(GPIO_Pin) { case GPIO_PIN_13: //按下PC13对应按键播放音乐 play_mus(); break; case GPIO_PIN_15: //按下PA15按键停止播放 buzzer_quit(); break; } } /* USER CODE END 2 */ 由于两个按键优先级一样,中断不能被另一个打断。 gpio.h文件: /* USER CODE BEGIN Includes */ #include "tim.h" //包含tim.h头文件 /* USER CODE END Includes */
上一篇:STM32笔记2:建库操作之点亮LED
下一篇:STM32学习笔记--按键输入实验
推荐阅读最新更新时间:2024-11-17 09:42
设计资源 培训 开发板 精华推荐
- DC1820A-A,用于 LTC3646 高效低静态电流降压转换器的演示板
- TWR-MCF5225X-KIT,用于 MCF52259CAG80 V2 ColdFire 微控制器的 ColdFire MCF5225X 连接塔式系统模块
- HV254DB1,高压放大器阵列演示板
- B4420QDS: QorIQ® Qonverge开发系统
- ADR433A 3 Vout 超低噪声 XFET 电压基准的典型应用,具有灌电流和拉电流能力
- LTC3424EMS 三路输出升压转换器的典型应用电路
- LTC3788 的典型应用 - 2 相、双输出同步升压控制器
- RDR-839 - 使用 TinySwitch-4 的设备的 12 W 电源
- 设备托架的电源解决方案
- FRDM-KEAZ128: KEA Freedom评估板