一、无源蜂鸣器和有源蜂鸣器

步进电机以及无源蜂鸣器这些都需要脉冲信号才能够驱动,这次尝试用GPIO的PWM接口驱动无源蜂鸣器弹奏一曲《一闪一闪亮晶晶》。
无源蜂鸣器:

无源内部没有震荡源,直流信号无法让它鸣叫。必须用去震荡的电流驱动它,2K-5KHZ的方波PWM (Pulse Width
Modulation脉冲宽度调制)。
5KHZ的电流方波是啥意思?那就是每秒震动5K次,每一个完整的周期占用200us的时间,高点平占一部分时间,低电平占一部分时间。

声音频率可控,可以做出不同的音效。
有源蜂鸣器:
内部带震荡电路,一通电就鸣叫,所以可以跟前面LED一样,给个高电平就能响,编程比无源的方便。

二、PWM和输出模式

单纯和上次一样操作设置GPIO口的高低是没法实现输出PWM的。好在树莓派的某些PIN口有这种模式,那就是PIN12口。可以通过控制PIN12口的PWM模式来实现。就理解为方波把。由于pygpio暂不支持操作硬件的PWM。这里我们用wiringpi库。
wiringPi中的pinMode (1,PWM_OUT),可以设置模式。PIN12是wiringpi的1号。

图中t(pwm)就是一个周期的时间长度。对于2K频率来说,那么周期就是1S/2K=500us。图中的D叫做占空比。指的是高电平的时间占用整个周期时间的百分比。第一个周期D=50%,那么就是高电平低电平的时间各占一半。接下来的D为33%,那就是通电时间为33%,剩余的不通电时间占用67%。
占空比的确会影响频率,但是我没有具体去探究会如何影响频率。我测试的时候使用的占空比是50%,也就是高低电平各占用一半的时间。
由于可以参考的例子是在太少了。只能自己翻芯片手册查找相关资料。具体的相关资料在BCM2835芯片手册的第九章(具体翻阅手册查看,真是最好的办法)。阅读这一章以后我得出的关键点有如下几点:
1 PWM的频率是受时钟管理器控制的,(树莓派的基础时钟频率是19.2MHZ)。
2 PWM的输出占空比模式有两种,一种是平衡模式,一种是MS模式。
先看占空比中的平衡模式和MS模式,假设我们希望输出的占空比为 N/M。
平衡模式是指的按照某一种算法计算何时发送低电平,何时发送高电平,该算法力求任意一段时间占空比都最接近N/M,下图是(4/8的时候的几种发送方式),很显然good的算法任意取得一段时间都更加接近4/8。

M/S模式就是整个S周期内,先发送M时间的高电平,剩余的S-M时间为低电平。

因此如果是4/8的占空比。
M/S模式8个时间长度内发送的就是 11110000 (周期为8个时间长度)。   而平衡模式则是 10101010(可以说最小周期为2个时间长度,大的周期为 8个时间长度)。
可能看不懂没关系。用图来解释更有说服力。
假设我们需要的频率为5KHZ,那么周期时间就是1s/5000hz=200us。设定占空比为 0.5 也就是高低电平各占一半,那么需要高电平占100us,低电平占100us。
如果是平衡模式。一个大周期内(200us)波形图看起来如下:

也就是这个大周期内,任意取一段时间占空比都接近0.5,其实实际频率比5K要大几倍。
如果是MS模式。则看起来如下:

显然这个才是我们需要的标准的5K频率。因为这个模式最小频率就是200us了。
wiringPi中的pwmSetMode (PWM_MODE_MS) 可以设置为ms模式。
前面说到树莓派基础时钟频率是19.2MHZ。pwm也受这个基础频率的控制,也就是最小的基础周期是1/19200000
S。这个周期太小了,我们控制蜂鸣器需要2-5K的频率。我们先将基础频率调大一些。通过pwmsetClock(int
clock)可以将时钟基础频率设置为 19.2M/clock的大小。然后我们再基于这个频率通过pwmsetRasnge(int
range)设置最终的频率,range的范围是2-4095。
通过pwmsetClock(clock)以及pwmsetRasnge(range)将最终的频率控制在 19.2MHz/clock/range的大小。
这里我设置clock为32 将时钟基础频率设置为19.2MHZ/32=600khz。
这样我们只要设置range从300到120就能得到2k-5k的频率。
那如何设置占空比呢?还有一个函数pwmWrite(value)。value指定了range指定的时间内发送高电平的基础周期个数(以时钟基础频率计算)。因此value/range就是占空比。pwmWrite(range/2)就能得到50%的占空比。range/5
就得到20%占空比。如果设置value为0,那么就是这段时期内一直是低电平,没有任何高电平,蜂鸣器就不发声了。
验证一下如下图。

50% (range/2)

20% (range/5)

三、代码设计

初始化

void init()
{
if (wiringPiSetup () == -1)
exit (1) ;
//设置针脚为pwm输出模式
pinMode (1, PWM_OUTPUT) ;
//设置pwm 信号模式为ms模式
pwmSetMode(PWM_MODE_MS);
//设置时钟基础频率为19.2M/32=600KHZ
pwmSetClock(32);
}

封装beep函数以及beep的持续时间

void beep(int freq,int t_ms)
{
int range;
if(freq<2000||freq>5000)
{
printf("invalid freq");
return;
}
//设置range为 600KHZ/freq。也就是由range个1/600KHZ组成了freq频率的周期。
range=600000/freq。
pwmSetRange(range);
//设置占空比为50%。
pwmWrite(1,range/2);
if(t_ms>0)
{
delay(t_ms);
}
}

通过delay来控制延时。
通过 pwmWrite(1,0)来关闭输出。

创建乐谱pwm.c

#include <wiringPi.h>

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h> typedef struct _TONE{
int freq;
int t_ms;
} TONE,*PTONE; #define ONESEC 1000/2 #define DO 2093
#define RE 2349
#define MI 2637
#define FA 2794
#define SO 3136
#define LA 3520
#define XI 3951
#define DO1 4186
#define RI1 4698 TONE star_notation[]=
{
{DO,ONESEC},
{DO,ONESEC},
{SO,ONESEC},
{SO,ONESEC},
{LA,ONESEC},
{LA,ONESEC},
{SO,ONESEC*2}, {FA,ONESEC},
{FA,ONESEC},
{MI,ONESEC},
{MI,ONESEC},
{RE,ONESEC},
{RE,ONESEC},
{DO,ONESEC*2}, {SO,ONESEC},
{SO,ONESEC},
{FA,ONESEC},
{FA,ONESEC},
{MI,ONESEC},
{MI,ONESEC},
{RE,ONESEC*2}, {SO,ONESEC},
{SO,ONESEC},
{FA,ONESEC},
{FA,ONESEC},
{MI,ONESEC},
{MI,ONESEC},
{RE,ONESEC*2}, {DO,ONESEC},
{DO,ONESEC},
{SO,ONESEC},
{SO,ONESEC},
{LA,ONESEC},
{LA,ONESEC},
{SO,ONESEC*2}, {FA,ONESEC},
{FA,ONESEC},
{MI,ONESEC},
{MI,ONESEC},
{RE,ONESEC},
{RE,ONESEC},
{DO,ONESEC*2}, }; void beep(int freq,int t_ms)
{
int range;
if(freq<2000||freq>5000)
{
printf("invalid freq");
return;
}
range=600000/freq;
pwmSetRange(range);
pwmWrite(1,range/2);
if(t_ms>0)
{
delay(t_ms);
}
} void init()
{
if (wiringPiSetup () == -1)
exit (1) ;
pinMode (1, PWM_OUTPUT) ;
pwmSetMode(PWM_MODE_MS);
pwmSetClock(32);
} int main (void)
{
int index=0 ; init(); for (;index<sizeof(star_notation)/sizeof(TONE);index++)
{
beep(star_notation[index].freq,star_notation[index].t_ms);
pwmWrite(1,0);
delay(100);
} pwmWrite(1,0); return 0 ;
}

BCM标号1(PIN12 )接无源蜂鸣器的正极,负极接GND。

编译执行

gcc -o pwm pwm.c -lwiringPi
sudo ./pwm

Raspberry Pi开发之旅-控制蜂鸣器演奏乐曲的更多相关文章

  1. Raspberry Pi开发之旅-发送邮件记录时间及IP

    由于我使用树莓派的场景大多数是在没有显示器.只用terminal连接它的情况下,所以,它的IP地址有时会在重启之后变掉(DHCP的),导致我无法通过terminal连接上它.然后我又要很麻烦地登录路由 ...

  2. Raspberry Pi开发之旅-同步时间

    使用htpdate同步时间 由于树莓派板子上没有 RTC 硬件和电池,因此树莓派上的系统时间重启是保存不了的.网上已经有人想到应对 NTP 被防火墙封掉类似的需求了,开源的 htpdate 命令直接使 ...

  3. 详解树莓派Model B+控制蜂鸣器演奏乐曲

    步进电机以及无源蜂鸣器这些都需要脉冲信号才能够驱动,这里将用GPIO的PWM接口驱动无源蜂鸣器弹奏乐曲,本文基于树莓派Mode B+,其他版本树莓派实现时需参照相关资料进行修改! 1 预备知识 1.1 ...

  4. Raspberry Pi开发之旅-WIFI遥控小车

    一.简单介绍树莓派的GPIO口 上图是树莓派2代的接口(不同型号接口会有差异),我们就以此为例来说下这些接口. 1.GPIO介绍 GPIO 英文全称是:General-purpose input/ou ...

  5. Raspberry Pi开发之旅-光照强度检测(BH1750)

    一.前期准备 1.环境要求 GY30模块(BH1750FVI传感器),树莓派系统,python-smbus,iic开启 2.取消对IIC驱动的黑名单 nano /etc/modprobe.d/rasp ...

  6. Raspberry Pi开发之旅-实现云平台监控

    一.基本设置 1 sudo raspi-config 移动到第五项“Enable Camera”,回车进入,按tab键切换到“Enable”回车确认.回到主菜单,tab键切换到“Finish”回车确认 ...

  7. Raspberry Pi开发之旅-土壤湿度检测

    一.土壤传感器 传感器四个针脚:  针脚 含义 AO 模拟信号输出 DO 数字信号输出 GND 电源负极 VCC 电源正极 二.接线 YL-38和YL69 之间直接用2根母对母线连接. YL-38和树 ...

  8. Raspberry Pi开发之旅-远程监控

    1.安装辅助工具 1 2 sudo apt-get install libjpeg8-dev sudo apt-get install cmake 2.编辑源文件 1 2 sudo git clone ...

  9. Raspberry Pi开发之旅-空气温湿度检测(DHT11)

    一.首先,简单介绍下DHT11: DHT11是一个温湿度传感器,分为3个接口,分别为:VCC, DATA, GND  引脚号 名称 类型 说明 1 VCC 电源 +级,输入3V-5.5V 2 DATA ...

随机推荐

  1. 1.spring boot要求最低jdk1.8,平安默认1.6问题,-》安装JDK1.8 2.maven 3.3.3要求最低jdk1.7->安装jdk 1.8

    1.spring boot要求最低jdk1.8,平安默认1.6问题,->安装JDK1.82.maven 3.3.3要求最低jdk1.7->安装jdk 1.8

  2. 学习swift从青铜到王者之swift基础部分01

    1.1 变量和常量 var 变量名称 = 值(var可以修改) let 常量名称 = 值(let不可以修改) 1.2 基本数据类型 整数类型和小数类型 两种基本数据类型不可以进行隐式转换 var in ...

  3. 装机、做系统必备:秒懂MBR和GPT分区表

    从Intel 6系列主板之后,就开始提供UEFI BIOS支持,正式支持GPT硬盘分区表,一举取代了此前的MBR分区表格式,不过为了保持对老平台的兼容,微软即使最新的Windows 10系统也继续提供 ...

  4. LinQ开篇介绍

    语言集成查询(LINQ)是 Visual Studio2008中引入的一组功能. 可为 C# 和 Visual Basic 语言语法提供强大的查询功能. LINQ引入了标准易学的数据查询和更新模式,能 ...

  5. DES加密算法的C++实现

    <信息安全技术>这门课又在讲 DES 加密算法了,以前用纯C写过一次,这次我用 C++ 重新写了一个,写篇文章以备后用.本文介绍了 DES 算法加密的大致步骤和整体流程. 一.DES算法原 ...

  6. firewalld filter

    实现 firewalld  的filter 功能 1. 关闭 INPUT ,关闭OUTPUT  (设置黑名单) 任何主机 都 ping 不通 本主机 1>命令 : iptables -P INP ...

  7. Android仿微信朋友圈图片查看器

    转载请注明出处:http://blog.csdn.net/allen315410/article/details/40264551 看博文之前,希望大家先打开自己的微信点到朋友圈中去,细致观察是不是发 ...

  8. BestCoder Round #56/hdu5463 Clarke and minecraft 水题

    Clarke and minecraft 问题描述 克拉克是一名人格分裂患者.某一天,克拉克分裂成了一个游戏玩家,玩起了minecraft.渐渐地,克拉克建起了一座城堡. 有一天,克拉克为了让更多的人 ...

  9. HDU4403 A very hard Aoshu problem DFS

    A very hard Aoshu problem                           Time Limit: 2000/1000 MS (Java/Others)    Memory ...

  10. JVM架构

    1 JVM的内存模型 1.1 堆空间 每个jvm都有一个堆,所有的对象都放在这里. 1.2 java栈空间 每个线程都有一个java栈,所有的java栈都放在这里. 1.3 本地方法栈 每个线程都有一 ...