本节通过定时器的PWM模式驱动无源蜂鸣器,来演奏一段音乐。本博客在掌机的系列教程中介绍过蜂鸣器的驱动原理,感兴趣的可以参考电子琴

无源蜂鸣器驱动电路

  蜂鸣器按照有无震荡源(不是电源),可以分为有源蜂鸣器和无源蜂鸣器。有源蜂鸣器上电就能工作,控制简单,但是只有一个音调。无源蜂鸣器需要单片机提供震荡源,虽然控制稍微复杂一点,但是可以发出不同频率的声音。

PWM原理

  根据我们的电路,引脚输出高电平时,驱动电路为蜂鸣器提供了闭合回路,则引脚给高电平,蜂鸣器就能响。然而,只给高电平,无源蜂鸣器不能持续发出声音,只有一瞬间有声音;需要马上给低电平,然后再给一个高电平。即在一个很短的周期内,无源蜂鸣器在高电平持续期间工作,在低电平持续期间休息。周期的倒数就是频率。
  无源蜂鸣器可以用高电平持续的时间调整音量,在一个周期中,高电平持续的时间越长,蜂鸣器声音越大;高电平持续的时间越短,蜂鸣器的声音越小。

  STM32的定时器自带PWM输出模式。为了方便理解PWM,我们想象一个场景:语文老师、数学老师和体育老师带着小白和小黑两个小朋友在玩游戏。语文老师说一个数字x;数学老师负责从0数到x,数到x以后再从0开始,周而复始;体育老师负责说出一个数字y,如果数学老师报的数字比y小,则小白要举手,否则小白把手放下;直到数学老师报数跟y一样大,小白才把手放下,同时小黑举起手来。但是小黑要时刻注意,如果数到最大的数字时,就要做好准备放下手,因为接下来的数字是0。
  例如语文老师说的数字是9,数学老师说的数字是6,即x=9,y=6,那么在一个游戏周期内,小白和小黑举手的情况如下:

数学老师 0 1 2 3 4 5 6 7 8 9
小白
小黑

  通过这个例子,我们来重新理解定时器输出PWM的一些概念:
  语文老师报的数字是9,9就是自动重装值(AutoReload),代表计数周期(Counter Period)。
  数学老师从0数到9,所以称数学老师报的数字是计数值(counter)。9就是最大周期,由于从0开始计数,故一共数了10个数字。数学老师数数的速度,由时钟(84Mhz)和分频(Prescaler)决定。
  体育老师说的数字是6,6就叫做比较值(compare),比较值除以自动重装值得到占空比,6÷10=60%就是占空比。
  在PWM模式1下,小白举手代表引脚输出高电平,小白举手时间占总时间的比例,就是占空比。小黑举手就是引脚输出低电平。PWM模式2与1逻辑相反。
在PWM驱动蜂鸣器的案例中,语文老师报的数字,由音调的频率决定;体育老师报的数字,可以控制音量。小白与小黑是不是需要举手,无需写判断语句,
STM32定时器PWM模式可以自动判断计数值与比较值什么时候相等。

使用CubeMX配置定时器为PWM模式



在定时器2的初始化代码中,增加开启定时器PWM模式的代码

static void MX_TIM2_Init(void)
{/* USER CODE BEGIN TIM2_Init 2 */HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_1);/* USER CODE END TIM2_Init 2 */
}

从音调与音量到定时器的设置

  音调与频率是对应的。

我们先写一个函数,用于根据音调与音量,设置定时器。思路如下:

  溢出时间 = (自动重装值+1)/12000000,频率是时间的倒数,音调与频率有关,所以知道音调(频率)以后,可用以下方法计算自动重装值:
  Autoreload=(12000000/usFraq)-1; //频率变为自动重装值
  在无声时,让counter与0比较,counter始终大于0,则引脚电平始终为低,蜂鸣器不会响,即可以达到静音的目的。
  比较值决定音量,比较值要比自动重装值小,可以用后者乘以小于1的系数得到。实际上把自动重装值右移也是让比较值小于自动重装值的一个方法,效果更好一点。因为即便只有10%的占空比,蜂鸣器还是很响。
  新建Beep.h用于存放宏定义,新建Beep.c编写演奏函数。

//Beep.c
/*** @brief 根据频率让蜂鸣器发出声音* @param 频率,音量* @note  音量建议范围2~10,2是最大,10几乎听不清了* @retval None*/
void Beep_Sound(unsigned short usFraq,unsigned char volume_level)   //usFraq是发声频率,即真实世界一个音调的频率。
{u16 Autoreload;if((usFraq<CL1)||(usFraq>20000))//太低与太高的频率都当做无声{__HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_1,0);//音量__HAL_TIM_SET_COUNTER(&htim2,0);}else{Autoreload=(12000000/usFraq)-1;  //频率变为自动重装值,设置的定时器时钟源为12Mhz__HAL_TIM_SET_AUTORELOAD(&htim2,Autoreload);__HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_1,Autoreload>>volume_level);//音量__HAL_TIM_SET_COUNTER(&htim2,0);//在不使用缓冲的情况下,必须把计数值清零,否则可能出现计数值大于自动重装值以后,必须数到最大值的情况}
}

注意,修改完ARR以后,必须手动清零计数器!
  然后主函数响几个音符:

//main()  while (1){Beep_Sound(CM1,6);HAL_Delay(200);Beep_Sound(CM2,6);HAL_Delay(200);Beep_Sound(CM3,6);HAL_Delay(200);Beep_Sound(CM1,6);HAL_Delay(200);Beep_Sound(0,6);HAL_Delay(200);}

  下载程序,应当可以听到“两只老虎,两只老虎”循环播放。
  程序只要稍加修改,就能演奏音乐了。可以参考演奏音乐与背景音乐

HAL库教程10:定时器的PWM模式应用相关推荐

  1. HAL库教程8:通用定时器的使用

    定时器溢出时间的计算   关于定时器溢出的时间计算,有个公式:   定时器本质上是一个不断自加的计数器,只不过在自加的时候,能够自动比较计数值跟某个设定值而已.定时器+1用时多少?   1/84000 ...

  2. STM32CubeMX与HAL库学习--基本定时器定时中断

    STM32CubeMX与HAL库学习--基本定时器定时中断 背景 STM32CubeMX生成初始化代码 在MDK-ARM里编辑代码 其他 背景 本人小白,最近在学着使用STM32CubeMX与HAL库 ...

  3. HAL库教程6:串口数据接收

    STM32的串口接收机制   与阻塞式发送函数HAL_UART_Transmit配套,有个阻塞式的接收函数,HAL_UART_Receive,但此函数不常用,串口接收通常使用中断函数HAL_UART_ ...

  4. HAL库自学笔记#2【PWM】

    绪言 PWM是TIM常见的作用之一,如果无法理解TIM的基本工作原理的话,可能理解起来很困难.当我第一次接触到PWM的时候,其实也是云里雾里的.但如果理解了TIM的基本工作原理,学习PWM还是很简单的 ...

  5. AVR 定时器快速PWM模式使用

    PWM很常用,AVR自带内部PWM功能,分为快速PWM模式和相位修正PWM模式. 我们这里选择方式15 ,由OCR1A保存上限值,由OCR1B保存匹配值,所以输出管脚 OCR1A不能输PWM,只能有O ...

  6. STM32CuBeMX(HAL库)实现定时器中断(STM32F407ZGT6)

    工具: 1.芯片: STM32F407ZET6 2.STM32CubeMx软件 3.IDE: MDK-Keil软件 4.STM32F4xxHAL库  这部分内容源自https://blog.csdn. ...

  7. HAL库教程3:引脚输入检测

    使用CubeMX配置输入引脚   本章我们要把按键作为输入源,使用单片机来检测引脚的电平状态.首先要查看原理图,按键与那些引脚相连.   我使用的板子,按键K2 -K5分别对应PA4-PA7,且按键按 ...

  8. HAL库教程14:查表法测量NTC热敏电阻

      STM32F4的AD采样的结果是12位的,即采样的最大值为4096.而参考电压是3.3V,所以3.3V与4096是对应的.当然3.3V只是理想状态,实际上可能略有偏差.假设单片机的AD采集引脚电压 ...

  9. 【STM32F4系列】【HAL库】【自制库】WS2812(软件部分)(PWM+DMA)

    文章目录 相关链接 协议 外设设置 硬件PWM 分析 HAL设置 DMA 分析 HAL设置 方案设计 代码实现 解码函数 开始发送和复位 发送函数 波形 成品 相关链接 硬件介绍(PCB设计方案) 模 ...

最新文章

  1. 一致性哈希算法的基本原理
  2. python 语言教程(1)前言
  3. 大象公会:如何做万人传播的原创内容?
  4. C指针原理(2)-ATT汇编
  5. [react] react中什么是非控组件?
  6. 计算机木马不会主动传播什么疾病,研究如何制作自动运行的木马病毒以及如何传播...
  7. sklearn决策树特征权重计算方法
  8. Win10使用Windows照片查看器(Windows Photo Viewer)来打开图片
  9. 标准c语言教程gary,C语言标准教程
  10. 华为 Mate8 Emui 5.0 安卓 7.0 root 记录
  11. 【JavaSE】JDK新特性(二)————接口新特性,函数式接口(Suppier,Comsumer,Predicate,Function)
  12. 【题解】 bzoj1135: [POI2009]Lyz (线段树+霍尔定理)
  13. Nature子刊 | AI驱动的药物开发是一把双刃剑
  14. Python练手小项目(6)随机取红黑球并计算概率
  15. python如何让用户输入_Python如何让用户输入
  16. HP11(HP其他喷头也可) 喷头程序开发项目外包
  17. 看顶级渣男如何邀约100个女朋友(二)
  18. 分区 与 bios 笔记本 tips
  19. 纪念一下毛星云这位年轻的先生
  20. docker compose搭建NACOS集群

热门文章

  1. 软考PMP哪个值得考?
  2. 第十三章 Logstash进阶
  3. android+屏幕色彩度,屏幕:PPI略低,节能技术影响色彩效果
  4. 绿色农业智慧管理:农产品调度可视化平台
  5. Java9中使用jpa_第三篇:SpringBoot中使用JPA
  6. 使用Gradle构建项目
  7. Android.拍照,保存图片,图片大小是0B...
  8. Solidworks 2011 软件下载、安装和破解 图文教程
  9. 三星折叠屏手机之后 人们展开了对折叠iPhone的幻想
  10. 《量化金融R语言初级教程》一1.1 使用时间序列数据