详解树莓派Model B+控制蜂鸣器演奏乐曲
步进电机以及无源蜂鸣器这些都需要脉冲信号才能够驱动,这里将用GPIO的PWM接口驱动无源蜂鸣器弹奏乐曲,本文基于树莓派Mode B+,其他版本树莓派实现时需参照相关资料进行修改!
1 预备知识
1.1 无源蜂鸣器和有源蜂鸣器
无源蜂鸣器:内部没有震荡源,直流信号无法让它鸣叫。必须用去震荡的电流驱动它,2K-5KHZ的方波PWM (Pulse Width Modulation脉冲宽度调制)。5KHZ的电流方波就是每秒震动5K次,每一个完整的周期占用200us的时间,高点平占一部分时间,低电平占一部分时间。声音频率可控,可以做出不同的音效。
有源蜂鸣器:内部带震荡电路,一通电就鸣叫,所以可以跟前面LED一样,给个高电平就能响,编程比无源的更方便。
本文利用无源蜂鸣器弹奏乐曲,用的就是淘宝上普通的电磁式阻抗16欧交流/2KHz 3V 5V 12V通用无源蜂鸣器,如果手边没有无源蜂鸣器,用普通的耳机也可以来代替无源蜂鸣器。
1.2 PWM
PWM(Pulse Width Modulation)即脉冲宽度调制,是一种利用微处理器的数字输出来控制模拟电路的控制技术。可以用下面的一幅图来形象地说明PWM:
图中tpwm就是一个周期的时间长度。对于2KHz频率来说,那么周期就是1s/2K=500us。图中的D叫做占空比,指的是高电平的时间占用整个周期时间的百分比。第一个周期D=50%,那么就是高电平低电平的时间各占一半。接下来的D为33%,那就是通电时间为33%,剩余的不通电时间占用67%。树莓派Model B+有4个PIN脚支持PWM输出,如下图最右侧:
但是,需要注意的是BCM2835芯片只支持两路PWM输出,所以以上12 Pin脚和32 Pin脚对应的都是channel 1的PWM输出,即如果这两个Pin的功能都选择的是PWM输出,则它们输出的PWM是完全相同的,同理33 Pin脚和35 Pin脚对应芯片channel 2的PWM输出。
博通公司公布的BCM2835芯片资料BCM2835 ARM Peripherals中第9章比较详细的介绍了PWM相关内容,此外还可参考网上整理好的寄存器介绍资料rip-registers,通过阅读可以得知树莓派Model B+支持两种模式的PWM输出:一种是Balanced mode(平衡模式),一种是Mark-Space mode(MS模式)。另外树莓派的PWM输出基础频率是19.2MHz,PWM输出频率受这个基础频率的限制。
1.3 树莓派PWM分析
进行分析前先看一下实验的物理电路连接:
图中,红色杜邦线一头连接树莓派的32 Pin脚(PWM0),一头连接示波器的探针;绿色杜邦线一头连接树莓派的12 Pin脚(PWM0),一头连接无源蜂鸣器的正极;黄色杜邦线一头连接树莓派的6 Pin脚(ground),一头连接无源蜂鸣器的负极,此外示波器探针的ground也连接到黄色杜邦线,结合bcm2835 C library来进行分析:
(1)下载bcm2835库:wget http://www.airspayce.com/mikem/bcm2835/bcm2835-1.50.tar.gz
(2)解压:tar -zxvf bcm2835-1.50.tar.gz
(3)进入目录:cd bcm2835-1.35
(4)编译:./configure && make
(5)安装:sudo make install
修改examples/pwm/pwm.c的内容如下:
// pwm.c
//
// Example program for bcm2835 library
// Shows how to use PWM to control GPIO pins
//
// After installing bcm2835, you can build this
// with something like:
// gcc -o pwm pwm.c -l bcm2835
// sudo ./pwm
//
// Or you can test it before installing with:
// gcc -o pwm -I ../../src ../../src/bcm2835.c pwm.c
// sudo ./pwm
//
// Author: Mike McCauley
// Copyright (C) 2013 Mike McCauley
// $Id: RF22.h,v 1.21 2012/05/30 01:51:25 mikem Exp $ #include <bcm2835.h>
#include <stdio.h> // PWM output on RPi Plug P1 pin 12 (which is GPIO pin 18)
// in alt fun 5.
// Note that this is the _only_ PWM pin available on the RPi IO headers
#define PIN RPI_GPIO_P1_12
// and it is controlled by PWM channel 0
#define PWM_CHANNEL 0
// This controls the max range of the PWM signal
#define RANGE 1024 #define PIN2 RPI_BPLUS_GPIO_J8_32 int main(int argc, char **argv)
{
if (!bcm2835_init())
return ; // Set the output pin to Alt Fun 5, to allow PWM channel 0 to be output there
bcm2835_gpio_fsel(PIN, BCM2835_GPIO_FSEL_ALT5); bcm2835_gpio_fsel(PIN2, BCM2835_GPIO_FSEL_ALT0); // 打开PI 32 Pin脚的PWM0输出功能 // Clock divider is set to 16.
// With a divider of 16 and a RANGE of 1024, in MARKSPACE mode,
// the pulse repetition frequency will be
// 1.2MHz/1024 = 1171.875Hz, suitable for driving a DC motor with PWM
bcm2835_pwm_set_clock(BCM2835_PWM_CLOCK_DIVIDER_16);
bcm2835_pwm_set_mode(PWM_CHANNEL, , );
bcm2835_pwm_set_range(PWM_CHANNEL, RANGE); printf("this is banlance mode, anykey will change to markspace mode\n");
bcm2835_pwm_set_data(PWM_CHANNEL, RANGE/);
getchar(); printf("change to markspace mode, anykey to exit\n");
bcm2835_pwm_set_mode(PWM_CHANNEL, , );
bcm2835_pwm_set_range(PWM_CHANNEL, RANGE);
bcm2835_pwm_set_data(PWM_CHANNEL, RANGE/);
getchar(); bcm2835_close();
return ;
}
pwm.c
代码中首先设置PWM输出为平衡模式,之后按任意键切换为MS模式,编译:gcc -o pwm pwm.c -lbcm2835,运行:sudo ./pwm,示波器分别捕获到如下波形图:
代码第47行用divider=16对19.2MHz的基础频率进行调整,调整后的pwm频率为19.2MHz/16=1.2MHz,根据BCM2835芯片资料及代码49行和52行内容可知占空比应为N/M=(RANGE/4)/RANGE=256/1024,平衡模式力求任意一段时间占空比都最接近N/M=1/4,即把256个高电平时钟周期平均的分配到1024个之中周期中,可以这样进行处理,每4个时钟周期为一组,其中的一个周期内为高电平,这样即可实现“平衡”,这时真实的PWM输出帧率为1.2MHz/4=300KHz,如以上左图所示;对于MarkSpace模式来说,占空比为M/S=(RANGE/4)/RANGE=256/1024,这种模式不需要进行平衡,即可以认为1024个时钟周期的前256个为高电平,其余的为低电平,这时真实的PWM输出帧率为1.2MHz/1024=1171.875Hz,如以上右图所示。
2 树莓派播放音乐
2.1 乐理知识
一首乐曲有若干音符组成,每个音符由音调和演奏时间组成。不同的音调在物理上就对应不同频率的音波。所以我们只要控制输出的频率和时长就能输出一首音乐了。当然实际的音乐很复杂,又有连接,还有重音什么的,这个就先不在讨论范围内了。
每个音符都会播放一定的时间,这样就能构成一首歌曲。在音乐上,音符节奏分为1拍、1/2拍、1/4拍、1/8拍,假设一拍音符的时间为1;半拍为0.5;1/4拍为0.25;1/8拍为0.125……,所以我们可以为每个音符赋予这样的拍子播放出来,音乐就成了。
Arduino官方网站给出了不同音符对应的不同频率的头文件pitches.h,相关内容可以参考博文,在本文我们把pitches.h文件直接应用到树莓派,该文件内容如下:
/*************************************************
* Public Constants
*************************************************/ #define NOTE_B0 31
#define NOTE_C1 33
#define NOTE_CS1 35
#define NOTE_D1 37
#define NOTE_DS1 39
#define NOTE_E1 41
#define NOTE_F1 44
#define NOTE_FS1 46
#define NOTE_G1 49
#define NOTE_GS1 52
#define NOTE_A1 55
#define NOTE_AS1 58
#define NOTE_B1 62
#define NOTE_C2 65
#define NOTE_CS2 69
#define NOTE_D2 73
#define NOTE_DS2 78
#define NOTE_E2 82
#define NOTE_F2 87
#define NOTE_FS2 93
#define NOTE_G2 98
#define NOTE_GS2 104
#define NOTE_A2 110
#define NOTE_AS2 117
#define NOTE_B2 123
#define NOTE_C3 131
#define NOTE_CS3 139
#define NOTE_D3 147
#define NOTE_DS3 156
#define NOTE_E3 165
#define NOTE_F3 175
#define NOTE_FS3 185
#define NOTE_G3 196
#define NOTE_GS3 208
#define NOTE_A3 220
#define NOTE_AS3 233
#define NOTE_B3 247
#define NOTE_C4 262
#define NOTE_CS4 277
#define NOTE_D4 294
#define NOTE_DS4 311
#define NOTE_E4 330
#define NOTE_F4 349
#define NOTE_FS4 370
#define NOTE_G4 392
#define NOTE_GS4 415
#define NOTE_A4 440
#define NOTE_AS4 466
#define NOTE_B4 494
#define NOTE_C5 523
#define NOTE_CS5 554
#define NOTE_D5 587
#define NOTE_DS5 622
#define NOTE_E5 659
#define NOTE_F5 698
#define NOTE_FS5 740
#define NOTE_G5 784
#define NOTE_GS5 831
#define NOTE_A5 880
#define NOTE_AS5 932
#define NOTE_B5 988
#define NOTE_C6 1047
#define NOTE_CS6 1109
#define NOTE_D6 1175
#define NOTE_DS6 1245
#define NOTE_E6 1319
#define NOTE_F6 1397
#define NOTE_FS6 1480
#define NOTE_G6 1568
#define NOTE_GS6 1661
#define NOTE_A6 1760
#define NOTE_AS6 1865
#define NOTE_B6 1976
#define NOTE_C7 2093
#define NOTE_CS7 2217
#define NOTE_D7 2349
#define NOTE_DS7 2489
#define NOTE_E7 2637
#define NOTE_F7 2794
#define NOTE_FS7 2960
#define NOTE_G7 3136
#define NOTE_GS7 3322
#define NOTE_A7 3520
#define NOTE_AS7 3729
#define NOTE_B7 3951
#define NOTE_C8 4186
#define NOTE_CS8 4435
#define NOTE_D8 4699
#define NOTE_DS8 4978
pitches.h
可以看到,这是一张类似表格的东西,里面是定义的大量的宏,即用宏名代替了频率名,对应到键盘的各个按键上。我们需要对应相应的音符到宏名上,为了实现这个首先看看钢琴大谱表与钢琴琴键的对照表:
为了将个音符的音名直观的看出来,给出以下表格:
2.2 播放音乐
对照以上表格及射雕英雄传主题曲铁血丹心简谱实现树莓派播放,铁血丹心简谱如下:
上面的简谱中缺少前奏,程序中增加了从其他版本中摘录的前奏部分,主程序tiexuedanxin.c代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h> #include <bcm2835.h>
#include "pitches.h" #define PWM_CHANNEL 0
typedef struct _TONE{
int freq;
int t_ms;
} TONE,*PTONE; int pin = RPI_GPIO_P1_12;
int baseFreq = ; // BCM2835_PWM_CLOCK_DIVIDER_32 对应600KHz typedef struct _melodyNode{
int note;
float fDuration;
}melodyNode; melodyNode melody[]= {
//
{NOTE_A4, 1.5}, //
{NOTE_G4, 0.5}, //
{NOTE_A4, }, //
{NOTE_G4, 0.5}, //
{NOTE_E4, 0.5}, // 3 //
{NOTE_G4, }, //
{NOTE_D4, }, // 2 //
{NOTE_C4, 1.5}, //
{NOTE_A3, 0.5}, // .6
{NOTE_D4, 0.5}, //
{NOTE_E4, 0.5}, //
{NOTE_G4, 0.5}, //
{NOTE_F4, 0.5}, // 4 //
{NOTE_E4, }, //
{NOTE_E4, 0.5}, //
{NOTE_G4, 0.5}, // 5 //
{NOTE_A4, 1.5}, //
{NOTE_G4, 0.5}, //
{NOTE_A4, }, //
{NOTE_G4, 0.5}, //
{NOTE_E4, 0.5}, // 5 //
{NOTE_G4, }, //
{NOTE_D4, }, // 2 //
{NOTE_C4, 1.5}, //
{NOTE_A3, 0.5}, // .6
{NOTE_D4, 0.5}, //
{NOTE_E4, 0.5}, //
{NOTE_G3, 0.5}, // .5
{NOTE_B3, 0.5}, // .7 //
{NOTE_A3, }, // .6 {, }, //
{NOTE_E4, 0.5}, //
{NOTE_D4, 0.5}, //
{NOTE_C4, 1.5}, //
{NOTE_B3, 0.5}, // .7 //
{NOTE_A3, 1.5}, // .6
{NOTE_E3, 0.5}, // .3
{NOTE_A3, }, // .6 //{NOTE_A3, 1}, // .6
{NOTE_A4, 0.5}, //
{NOTE_G4, 0.5}, //
{NOTE_E4, }, //
{NOTE_G4, 0.5}, //
{NOTE_D4, 0.5}, // {NOTE_E4, }, // {NOTE_E4, 0.5}, //
{NOTE_D4, 0.5}, //
{NOTE_C4, 1.5}, //
{NOTE_B3, 0.5}, // .7 {NOTE_A3, 1.5}, // .6
{NOTE_E3, 0.5}, // .6
{NOTE_A3, }, // .6 {, }, //
{NOTE_D4, 0.5}, //
{NOTE_C4, 0.5}, //
{NOTE_A3, }, // .6
{NOTE_C4, 0.5}, //
{NOTE_D4, 0.5}, // {NOTE_E4, }, // 3*/
{NOTE_E4, }, // 3 逐草四方 {NOTE_A4, 1.5}, //
{NOTE_G4, 0.5}, //
{NOTE_A4, }, //
{NOTE_G4, 0.5}, //
{NOTE_E4, 0.5}, // {NOTE_G4, }, //
{NOTE_D4, }, // {NOTE_C4, 1.5}, //
{NOTE_A3, 0.5}, // .6
{NOTE_D4, 0.5}, //
{NOTE_E4, 0.5}, //
{NOTE_G4, 0.5}, //
{NOTE_FS4, 0.5}, // #4 {NOTE_E4, }, //
{NOTE_E4, 0.5}, //
{NOTE_G4, 0.5}, // {NOTE_A4, 1.5}, //
{NOTE_G4, 0.5}, //
{NOTE_A4, 1.0}, //
{NOTE_G4, 0.5}, //
{NOTE_E4, 0.5}, // {NOTE_G4, 1.0}, //
{NOTE_D4, }, // {NOTE_C4, 1.5}, //
{NOTE_A3, 0.5}, // .6
{NOTE_D4, 0.5}, //
{NOTE_E4, 0.5}, //
{NOTE_G3, 0.5}, // .5
{NOTE_B3, 0.5}, // .7 {NOTE_A3, }, // .6 {, }, //
{NOTE_E4, 0.5}, // 3 应知爱意似
{NOTE_D4, 0.5}, //
{NOTE_C4, 1.0}, //
{NOTE_C4, 0.5}, //
{NOTE_B3, 0.5}, // .7 {NOTE_A3, 1.5}, // .6
{NOTE_E3, 0.5}, // .3
{NOTE_A3, 2.0}, // .6 {, }, //
{NOTE_A3, 0.5}, // .6
{NOTE_G3, 0.5}, // .5
{NOTE_E3, 1.0}, // .3
{NOTE_G3, 0.5}, // .5
{NOTE_D3, 0.5}, // .2 {NOTE_E3, 3.0}, // .3 {, }, //
{NOTE_E4, 0.5}, // 3 身经百劫也
{NOTE_D4, 0.5}, //
{NOTE_C4, 1.0}, //
{NOTE_C4, 0.5}, //
{NOTE_B3, 0.5}, // .7 {NOTE_A3, 1.5}, // .6
{NOTE_E4, 0.5}, //
{NOTE_D4, 2.0}, // {, }, //
{NOTE_D4, 0.5}, //
{NOTE_C4, 0.5}, //
{NOTE_A3, 1.0}, // .6
{NOTE_B3, 0.5}, // .7
{NOTE_G3, 0.5}, // .5 {NOTE_A3, 3.0}, // .6
}; void beep(int freq, int t_ms)
{
int range;
/*if(freq<2000||freq>5000)
{
printf("invalid freq\n");
return;
}*/
if(freq == )
range=;
else
range=baseFreq/freq;
printf("will call bcm2835_pwm_set_range freq: %d range: %d\n", freq, range);
bcm2835_pwm_set_range(PWM_CHANNEL, range);
bcm2835_pwm_set_data(PWM_CHANNEL, range/);
if(t_ms>)
{
delay(t_ms);
}
} void init()
{
if (!bcm2835_init())
exit () ; printf("will init pin %d\n", pin);
// Set the output pin to Alt Fun 5, to allow PWM channel 0 to be output there
bcm2835_gpio_fsel(pin, BCM2835_GPIO_FSEL_ALT5);
bcm2835_pwm_set_clock(BCM2835_PWM_CLOCK_DIVIDER_32);
bcm2835_pwm_set_mode(PWM_CHANNEL, , );
} int main (void)
{
int index=;
int nLen = sizeof(melody)/sizeof(melody[]);
init(); for ( ; index<nLen; index++)
{
int noteDuration = *melody[index].fDuration;
beep(melody[index].note, noteDuration);
printf("will call bcm2835_pwm_set_data 0 after beep\n");
bcm2835_pwm_set_data(PWM_CHANNEL, );
printf("index: %d nLen: %d@@@@@@@@@@@@\n", index, nLen);
//delay(100);
} bcm2835_pwm_set_data(PWM_CHANNEL, );
bcm2835_close(); return ;
}
tiexuedanxin
注意代码中195行做了特殊处理,这时候频率并不是为0,只是让树莓派不再发声。
详解树莓派Model B+控制蜂鸣器演奏乐曲的更多相关文章
- Raspberry Pi开发之旅-控制蜂鸣器演奏乐曲
一.无源蜂鸣器和有源蜂鸣器 步进电机以及无源蜂鸣器这些都需要脉冲信号才能够驱动,这次尝试用GPIO的PWM接口驱动无源蜂鸣器弹奏一曲<一闪一闪亮晶晶>. 无源蜂鸣器: 无源内部没有震荡源, ...
- Raspiberry Camera详解+picamera库+Opencv控制
使用树莓派的摄像头,将树莓派自身提供的picamera的API数据转换为Python Oencv可用图像数据: # import the necessary packages from picamer ...
- Raspberry Camera详解+picamera库+Opencv控制
使用树莓派的摄像头,将树莓派自身提供的picamera的API数据转换为Python Oencv可用图像数据: # import the necessary packages from picamer ...
- verilog实验1:基于FPGA蜂鸣器演奏乐曲并数码管显示
一.实验任务 利用FPGA进行代码开发,使蜂鸣器演奏出乐曲<生日快乐>,将音调显示在数码管.原理为蜂鸣器为交流源蜂鸣器,在引脚上加一定频率的方波就可以发声,而且发声的频率由所加方波决定.这 ...
- (四)、 nodejs中Async详解之一:流程控制
为了适应异步编程,减少回调的嵌套,我尝试了很多库.最终觉得还是async最靠谱. 地址:https://github.com/caolan/async Async的内容分为三部分: 流程控制:简化十种 ...
- Async详解之一:流程控制
为了适应异步编程,减少回调的嵌套,我尝试了很多库.最终觉得还是async最靠谱. 地址:https://github.com/caolan/async Async的内容分为三部分: 流程控制:简化十种 ...
- nodejs中Async详解之一:流程控制
为了适应异步编程,减少回调的嵌套,我尝试了很多库.最终觉得还是async最靠谱. 地址:https://github.com/caolan/async Async的内容分为三部分: 流程控制:简化十种 ...
- Spring详解篇之IoC控制反转
###一.Spring概况 spring是一个开源框架 是一个轻量的控制反转和面向切面的容器框架 大小和开销都是轻量的. 通过控制反转技术可以达到松耦合的目的 切面编程,允许通过分离应用的业务逻辑. ...
- 详解Azure的权限控制
注意:本文档仅限于Azure国际版,国内版略有不同 Azure中的角色分配相对来说是比较复杂的的,对于任何云组织来说,云的资源访问管理权限都是一项非常重要的功能,azure中的授权系统叫做基于角色 ...
随机推荐
- [NodeJS] 优缺点及适用场景讨论
概述: NodeJS宣称其目标是“旨在提供一种简单的构建可伸缩网络程序的方法”,那么它的出现是为了解决什么问题呢,它有什么优缺点以及它适用于什么场景呢? 本文就个人使用经验对这些问题进行探讨. 一. ...
- Entity Framework 6 Recipes 2nd Edition 译 -> 目录 -持续更新
因为看了<Entity Framework 6 Recipes 2nd Edition>这本书前面8章的翻译,感谢china_fucan. 从第九章开始,我是边看边译的,没有通读,加之英语 ...
- redux学习
redux学习: 1.应用只有一个store,用于保存整个应用的所有的状态数据信息,即state,一个state对应一个页面的所需信息 注意:他只负责保存state,接收action, 从store. ...
- 来吧,HTML5之基础标签(上)
什么是html5 HTML 5 是下一代的 HTML.HTML5 仍处于完善之中.然而,大部分现代浏览器已经具备了某些 HTML5 支持. 学习过程中标签的理解 <a>标签 定义超链接, ...
- Loadrunner Http Json接口压力测试
前天接到了一个测试任务,要求测试一下ES(elsticsearch)在不同并发下的查询效率.如图: 业务场景是在客户端根据具体车牌查询相关车辆信息,结果返回前10条记录. 从图中可以看到,接口的请求参 ...
- Autofac - 属性注入
属性注入不同于通过构造函数方式传入参数. 这里是通过注入的方式, 在类创建完毕之后, 资源释放之前, 给属性赋值. 这里, 我重新弄一些类来演示这一篇吧. public class ClassA { ...
- JDBC增加删除修改
一.配置程序--让我们程序能找到数据库的驱动jar包 1.把.jar文件复制到项目中去,整合的时候方便. 2.在eclipse项目右击"构建路径"--"配置构建路径&qu ...
- Dropzone.js实现文件拖拽上传
dropzone.js是一个开源的JavaScript库,提供 AJAX 异步文件上传功能,支持拖拽文件.支持最大文件大小.支持设置文件类型.支持预览上传结果,不依赖jQuery库. 使用Dropzo ...
- Postman - 功能强大的 API 接口请求调试和管理工具
Postman 是一款功能强大的的 Chrome 应用,可以便捷的调试接口.前端开发人员在开发或者调试 Web 程序的时候是需要一些方法来跟踪网页请求的,用户可以使用一些网络的监视工具比如著名的 Fi ...
- BPM配置故事之案例5-必填与水印文本
物资申请表改好了,但是没过两天老李又找来了. 老李:这个表格每次都是各个部门发给我们,再由我们采购部来填,太影响效率了,以后要让他们自己填. 小明:那就让他们填呗,他们有权限啊. 老李:可是他们说不会 ...