音阶频率对照表
百度就可以查到,我对照的是下面网址中的:
http://blog.csdn.net/u012266559/article/details/51512616

单片机产生音乐的原理
音乐的产生主要是通过单片机的I/O口输出高低不同的脉冲信号来控制蜂鸣器发音,要想产生音频脉冲信号,需要算出某音频的周期(1/频率),然后将此周期除以2,即为半周期的时间。利用单片机定时器计时这个半周期的时间,每当计时到后就输出脉冲的I/O口反相,这样就在此I/O口上得到此脉冲的频率。
我是直接利用stm32的PWM端口输出PWM波(设置成占空比为50%)就可以实现,关键是每个音阶对应频率的方波如何求。
从下图看,只要理解原理,那么不管单片机的时钟频率多大,我们都可以自己求出相应的音阶所需要的arr值。

程序用到的单片机引脚
我用的是stm32开发板,利用PF9端口输出PWM波,PF8端口连着的是蜂鸣器,所以只需要用杜邦线把PF9和PF8端口连在一起就可以了。

程序中定义的的宏定义
10000的来历上图中有计算过程,然后音阶频率对照表中可以查到
低1 DO 的频率是262,所以我们得到
低1 DO 对应的arr值是 (R/262)-1 ,其余音符对应arr的计算方式同理。
#define R 10000 //84MHz/(psc+1)=10000
#define L1 (R/262)-1 //低1 DO

关于音符0的处理以及改进
在我写完的程序中,我是这样处理的,一旦遇到音符0,让PWM停止输出。有想过关闭TIM14和PORTF时钟,但是没有用——因为用同样的方法,在一首歌结束之后就是一段相同频率的杂音。所以这种方法是不可以让PWM输出停止的。最后换了个方法,把PF9设置成普通IO口而且是输入模式就可以了,就不会有噪声了。

但是这种方法很麻烦,后来想到其实在遇到音符0的时候,只需要将PWM输出频率变大,让蜂鸣器发出一个人耳听不到的超声波就可以了——程序已经写完了,懒得改了。

主要程序代码

#include "sys.h"
#include "delay.h"
#include "led.h"
#include "timer.h"
#include "key.h"#define  ZERO  3000//#define  R  10000 //F_CLOCK/(psc+1)=10000#define  L1       (R/262)-1        //低1 DO#define  half_L1 (R/277)-1        //#1 DO##define  L2       (R/294)-1#define  half_L2  (R/311)-1#define  L3       (R/330)-1#define  L4       (R/349)-1#define  half_L4  (R/370)-1#define  L5       (R/392)-1#define  half_L5  (R/410)-1#define  L6       (R/440)-1#define  half_L6  (R/466)-1#define  L7       (R/494)-1#define  M1       (R/523)-1        //中1 DO#define  half_M1 (R/554)-1        //#1  DO##define  M2       (R/587)-1#define  half_M2  (R/622)-1#define  M3       (R/659)-1#define  M4       (R/698)-1#define  half_M4  (R/740)-1#define  M5       (R/784)-1#define  half_M5  (R/831)-1#define  M6       (R/880)-1#define  half_M6  (R/932)-1#define  M7       (R/988)-1#define  H1       (R/1046)-1        //高1 DO#define  half_H1 (R/1109)-1        //#1 DO##define  H2       (R/1175)-1#define  half_H2  (R/1245)-1#define  H3       (R/1318)-1#define  H4       (R/1397)-1#define  half_H4  (R/1480)-1#define  H5       (R/1568)-1#define  half_H5  (R/1661)-1#define  H6       (R/1760)-1#define  half_H6  (R/1865)-1#define  H7       (R/1967)-1int flag=0;//标志int x;int tune[] =
{  M6,M7,H1,M7,H1,H3,M7,M7,M7,M3,M3,  M6,M5,M6,H1,M5,M5,M5,M3,M4,M3,M4,H1,M3,M3,ZERO,H1,H1,H1,M7,half_M4,M4,M7,M7,M7,ZERO,M6,M7,H1,M7,H1,H3,M7,M7,M7,M3,M3,M6,M5,M6,H1,M5,M5,M5,M2,M3,M4,H1,M7,M7,H1,H1,H2,H2,H3,H1,H1,H1,H1,M7,M6,M6,M7,half_M5,M6,M6,M6,H1,H2,H3,H2,H3,H5,H2,H2,H2,M5,M5,H1,M7,H1,H3,H3,H3,H3,H3,M6,M7,H1,M7,H2,H2,H1,M5,M5,M5,H4,H3,H2,H1,H3,H3,H3,H3,H6,H6,H5,H5,H3,H2,H1,H1,ZERO,H1,H2,H1,H2,H2,H5,H3,H3,H3,H3,H6,H6,H5,H5,H3,H2,H1,H1,ZERO,H1,H2,H1,H2,H2,M7,M6,M6,M6,M6,M7
};float duration[]= {  0.5,0.5,     1.5,0.5,1,1,     1,1,1,0.5,0.5,1.5,0.5,1,1,     1,1,1,1,          1.5,0.5,1,1, 1,1,0.5,0.5,0.5,0.5,    1+0.5,0.5,1,1,     1,1,1,0.5,0.5,1+0.5,0.5,1,1,    1,1,1,0.5,0.5,     1+0.5,0.5,1,1,1,1,1,0.5,0.5,    1,0.5,0.25,0.25,0.25,0.5,    0.5,0.5,0.5,0.25,0.5,1,0.5,0.5,0.5,0.5,1,1,    1,1,1,0.5,0.5,    1+0.5,0.5,1,1,1,1,1,0.5,0.5,    1.5,0.5,1,1,    1,1,1,1,0.5,0.5,1,1,0.5,0.5,    1.5,0.25,0.5,1,    1,1,1,1,1,1,1,1,    1,1,1,1,    0.5,0.5,1,1,0.5,0.5,1,0.5,0.5,1,1,    1,1,1,1,    1,1,1,1,0.5,0.5,1,1,0.5,0.5,    1,0.5,0.25,0.5,1,    1,1,1,0.5,0.5
};//这部分是整首曲子的节拍部分,也定义个序列duration,浮点(数组的个数和前面音符的个数是一样的,一一对应么)int length = sizeof(tune)/sizeof(tune[0]);//这里用了一个sizeof函数, 可以查出tone序列里有多少个音符
//int length;//这里定义一个变量,后面用来表示共有多少个音符void main(void)
{Stm32_Clock_Init(336,8,2,7);//设置时钟,168Mhz delay_init(168);            //延时初始化 for(x=0;x<length;x++)//循环音符的次数{  if(flag==1) //上一个音符是0,在遇到下一个音符前重新使用IO口的复用功能{//RCC->AHB1ENR|=1<<5; //使能PORTF时钟   //RCC->APB1ENR|=1<<8; //使能TIM14时钟GPIO_Set(GPIOF,PIN9,GPIO_MODE_AF,GPIO_OTYPE_PP,GPIO_SPEED_100M,GPIO_PUPD_PU);//复用功能,上拉输出GPIO_AF_Set(GPIOF,9,9); //PF9,AF9           flag=0;//将标志置0}if(tune[x]==ZERO){//RCC->APB1ENR|=0<<8; //关闭TIM14时钟 //RCC->AHB1ENR|=0<<5; //关闭PORTF时钟使PF9引脚无法输出PWM波GPIO_Set(GPIOF,PIN9,GPIO_MODE_IN,GPIO_OTYPE_PP,GPIO_SPEED_100M,GPIO_PUPD_PU);//将PF9设置成普通IO口,输入flag=1;//将关闭标志置1}GPIO_Set(GPIOF,PIN9,GPIO_MODE_AF,GPIO_OTYPE_PP,GPIO_SPEED_100M,GPIO_PUPD_PU);//复用功能,上拉输出GPIO_AF_Set(GPIOF,9,9); //PF9,AF9//设置成复用模式(此处就是PWM端口),输出TIM14_PWM_Init(tune[x],8400-1);  //(arr,psc)if(flag==1)delay_ms(300*duration[x]);//否则延时会很长elsedelay_ms(400*duration[x]);//每个音符持续的时间,即节拍duration//设置成一个全拍400ms}//RCC->APB1ENR|=0<<8; //关闭TIM14时钟 //RCC->AHB1ENR|=0<<5; //关闭PORTF时钟GPIO_Set(GPIOF,PIN9,GPIO_MODE_IN,GPIO_OTYPE_PP,GPIO_SPEED_100M,GPIO_PUPD_PU);//把PF9设置成普通IO口输入就可以了,就不会有噪声了。//delay_ms(10000);//还是会有声音,不知道为什么//GPIO_AF_Set(GPIOF,9,9);   //PF9,AF9 while(1);//防止程序跑飞
}//TIM14 PWM部分初始化函数
//PWM输出初始化
//arr:自动重装值
//psc:时钟预分频数
void TIM14_PWM_Init(u32 arr,u32 psc)
{                            //此部分需手动修改IO口设置RCC->APB1ENR|=1<<8;     //TIM14时钟使能    RCC->AHB1ENR|=1<<5;     //使能PORTF时钟 //GPIO_Set(GPIOF,PIN9,GPIO_MODE_AF,GPIO_OTYPE_PP,GPIO_SPEED_100M,GPIO_PUPD_PU);//复用功能,上拉输出//GPIO_AF_Set(GPIOF,9,9);   //PF9,AF9 TIM14->ARR=arr;         //设定计数器自动重装值 TIM14->PSC=psc;         //预分频器分频 TIM14->CCMR1|=6<<4;     //CH1 PWM1模式         TIM14->CCMR1|=1<<3;     //CH1 预装载使能    TIM14->CCER|=1<<0;      //OC1 输出使能  TIM14->CCER|=1<<1;      //OC1 低电平有效    TIM14->CR1|=1<<7;       //ARPE使能 TIM14->CR1|=1<<0;       //使能定时器14TIM14->CCR1=arr*0.5;    //占空比= TIM14->CCR1 / arr(单位:%)//设置占空比为50%
}

STM32F4应用笔记(二)利用蜂鸣器播放天空之城相关推荐

  1. Arduino应用笔记(一)利用蜂鸣器播放天空之城

    这是本科时候做的,前两天翻到了以前写的程序,就找了出来. 我用的是Arduino UNO,利用面包板搭建电路,将蜂鸣器一端连到数字5引脚,另一端接地. 代码如下: #define NOTE_D0 -1 ...

  2. 51单片机蜂鸣器播放天空之城

    51单片机蜂鸣器播放天空之城 附:天空之城乐谱 第三张图片中65行46968改为64968,希望凉解.(由于本人对乐谱知之甚少,上述有关音符代码由网络提供.如有错误,敬请雅正.)

  3. 鸿蒙开发板HI3861 利用蜂鸣器播放音乐 open Harmony1.0.0(附cmsis_os2.h源码)

    本文利用鸿蒙开发板HI3861在鸿蒙1.0.0源码下利用蜂鸣器播放音乐. pwm_buz.c #include <stdio.h> #include "ohos_init.h&q ...

  4. MSP430G2553单片机——利用蜂鸣器播放一首歌

    利用MSP430G2553单片机和无源蜂鸣器播放一首歌,下面给出两种方案. 方案一: 播放<两只老虎> #include<MSP430G2553.h> //音乐播放 // by ...

  5. (十)51单片机——利用蜂鸣器播放《孤勇者》(附成果展示)

    目录 硬件部分 蜂鸣器介绍 驱动电路 ULN2003 乐理部分 音符 音符与频率对照 代码部分 运行结果 随着最近孤勇者成为小朋友们的接头暗号之后,于是产生了利用单片机去播放孤勇者的想法,接下来我们来 ...

  6. 推荐系统读书笔记(二)利用用户行为数据

    2.1 用户行为数据简介 显性反馈行为:用户明确表示对物品喜好的行为.评分.喜欢.不喜欢. 隐性反馈行为:不能明确反应用户喜好的行为.比如页面浏览.   显性反馈数据 隐性反馈数据 用户兴趣 明确 不 ...

  7. Flexe2.0 学习笔记二(利用PopUpManager实现一个组件登录窗体)

    通过对代码的学习实现了一个登录窗体的显示,还未涉及到参数的传递,这次的问题是窗体位置的控制需要如何解决?努力学习ing..... 代码下载 问题已解决 只要在 helpWindow = TitleWi ...

  8. Arduino红外遥控无源蜂鸣器播放音乐

    Arduino红外遥控无源蜂鸣器播放音乐/模拟电子琴 简介 关于频谱 实验材料 接线 实验代码 模拟电子琴 接线 代码 总结 原文链接:https://www.yourcee.com/newsinfo ...

  9. python蜂鸣器天空之城频率_51单片机蜂鸣器播放音乐天空之城PPT教程+程序+Proteus仿真...

    /*************** author:zc description: 蜂鸣器播放音乐 天空之城 晶振11.0592Mhz 实现方法: while(1)循环中生成音调方波: 定时器1记录每个音 ...

  10. 利用CC2530单片机的蜂鸣器播放音乐的代码

    使用 CC2530 单片机播放音乐需要使用蜂鸣器,这是一个较简单的方法. 下面是一个例子,它使用蜂鸣器播放了著名的<莫扎特第五交响曲>的第一段: #include "ioCC25 ...

最新文章

  1. java中的权限修饰符_Java的权限修饰符的区别和用法总结
  2. 关于防范csrf攻击基于token鉴权
  3. 一步步带你做vue后台管理框架(三)——登录功能
  4. 基于STM32分析栈、堆、全局区、常量区、代码区、RAM、ROM
  5. 关于编译器的一个问题
  6. 2019年第十届蓝桥杯 - 省赛 - C/C++大学C组 - F. 旋转
  7. 魏桥集团创始人张士平去世,他是如何成为山东首富的?
  8. php如何编写通信协议,定制通讯协议
  9. WebM VP8 SDK Usage/关于WebM VP8 SDK的用法
  10. 2020年已裸辞5个月(软文)
  11. ORM框架之Spring Data JPA(一)Hibernate实现JPA规范
  12. Redis初识、设计思想与一些学习资源推荐
  13. 制作可被svchost调用的服务(上)
  14. 单(两)个正态总体的统计量的分布相关定理
  15. 不是吧?DNSPod挪车码免费送?
  16. java实现易宝支付
  17. OA系统调研报告:技术推动OA发展
  18. 浙江理工大学计算机考研难度,浙江理工大学考研难度(浙江理工大学是211吗)...
  19. 物联网的技术前景!!!
  20. python利用dominate库生成静态网页

热门文章

  1. Activiti6教程一
  2. 阿里巴巴的商品主图视频要怎么保存比较快
  3. MySQL修改表字段的长度
  4. 【第133期】 游戏策划:给@1的简历分析
  5. Window下MySQL 8.0重新设置密码
  6. php 处理raw数据,PHP用HTTP_RAW_POST_DATA来接收post过来的数据
  7. Kerberos下pyhive使用
  8. 英特尔服务器主板型号参数对照表,Intel主板芯片组参数速查表(201805版)
  9. 台式计算机主板,台式电脑主板开机过程详解
  10. 如何用手机制作一寸或二寸证件照?