本文介绍如何在HiSpark Wi-Fi IoT套件上,使用Harmony OS IoT硬件子系统的PWM接口 驱动蜂鸣器 播放音乐。
用PWM输出方波
PWM输出的方波频率
通过PwmStart接口的注释,可以知道freq参数是分频倍数,PWM实际输出的方波频率等于 PWM时钟源频率 除以 分频倍数,即
f = Fcs / freq
其中,Fcs是PWM时钟源频率;
PWM输出方波的占空比
通过PwmStart接口的duty参数可以控制输出方波的占空比,占空比是指PWM输出的方波波形的高电平时间占整个方波周期的比例,具体占空比值是 duty 和 freq的比值,例如想要输出占空比 50%的方波信号,那么duty填的值就要是 freq/2;
音符-频率对应关系
参考:https://liam.page/2018/04/09/pitch-interval-and-harmonic/
开发板可以输出的最低频率
通过前面的公式,我们知道:
PWM输出的方波频率和freq成反比,freq越大,输出的方波频率越小;
freq是unsinged short类型,最大值为65535;
因此,输出频率的最小值取决于时钟源,PWM的默认时钟源为160M:
unsignedintHalPwmInit(HalWifiIotPwmPortport){if(hi_pwm_set_clock(PWM_CLK_160M)!=HI_ERR_SUCCESS){return(unsignedint)HAL_WIFI_IOT_FAILURE; }returnhi_pwm_init((hi_pwm_port)port); }
我们通过直接调用hi_pwm_set_clock接口,可以修改时钟源:
/** *@ingroupiot_pwm * *EnumeratesthePWMclocksources.CNcomment:PWM时钟源枚举。CNend */typedefenum{ PWM_CLK_160M,/**< 160M APB clock.CNcomment:160M 工作时钟 CNend */ PWM_CLK_XTAL, /**< 24M/40M crystal clock.CNcomment:24M或40M 晶体时钟 CNend */ PWM_CLK_MAX /**< Maximum value, which cannot be used.CNcomment:最大值,不可使用CNend */} hi_pwm_clk_source;hi_u32 hi_pwm_set_clock(hi_pwm_clk_source clk_type);
通过注释我们知道hi_pwm_set_clock(PWM_CLK_XTAL);可以将时钟源设置为晶体时钟,晶体时钟可能为24M或40M;
那么问题来了——晶体时钟到底是多少?
晶体时钟频率是多少?
我们可以通过通过实验,测算出晶体时钟频率,具体步骤如下:
使用hi_pwm_set_clock(PWM_CLK_XTAL);设置时钟源为晶体时钟;
使用PwmStart(WIFI_IOT_PWM_PORT_PWM0, 20*1000, 40*1000);输出方波信号;
使用示波器测量方波频率;
经实际测量,方波评率为1000Hz,因此,时钟频率为1000 * 40 * 1000也就是 40 MHz;
可以输出的方波最低频率
因此,方波最低频率就是 40M / 65535 ,也就是:
>>>40*1000*1000/65535 610.3608758678569
对照上面的频率表,可以知道,能够输出E♭以上的所有音符;
准备曲谱
为了代码实现起来简单,我选择了《两只老虎》的曲谱作为素材,很快找到了简谱:
简谱说明
对于缺乏音乐基础的同学,简谱上的一些记号可能不太清楚是什么意思,这里简单说明一下:
左上角的1=C是表示调式(可以不用关心),1是唱名,C是音名,1=C是正调(就是常规的对应关系: 1-C,2-D, 3-E, 4-F, 5-G, 6-A, 7-B);
左上角的 4/4 是四四拍,是指 四分音符为一拍, 每小节有四拍;
下面谱子上的竖线就是每个小节分隔符,和4/4对应;
“跑得快”上面5后面的横线表示延时一拍;
“一直没有眼睛”一句,5后面的点表示顺延半拍,一条下划线表示二分之一时间,两条下划线表示四分之一时间;
编写代码
有了以上知识,我们就可以编写代码了,关键部分代码如下:
staticvolatileintg_buttonPressed=0;staticconstuint16_tg_tuneFreqs[]={0,//40MHz对应的分频系数: 38223,//11046.5 34052,//21174.7 30338,//31318.5 28635,//41396.9 25511,//51568 22728,//61760 20249,//71975.5 51021//5_783.99//第一个八度的5};//曲谱音符staticconstuint8_tg_scoreNotes[]={//《两只老虎》简谱:http://www.jianpu.cn/pu/33/33945.htm 1,2,3,1,1,2,3,1,3,4,5,3,4,5,5,6,5,4,3,1,5,6,5,4,3,1,1,8,1,1,8,1,//最后两个5应该是低八度的,链接图片中的曲谱不对,声音到最后听起来不太对劲};//曲谱时值,根据简谱记谱方法转写,4/4拍中下面划一条线是半拍,划两条线是四分之一拍,点是顺延半拍staticconstuint8_tg_scoreDurations[]={4,4,4,4,4,4,4,4,4,4,8,4,4,8,3,1,3,1,4,4,3,1,3,1,4,4,4,4,8,4,4,8, };staticvoid*BeeperMusicTask(constchar*arg){ (void)arg;printf("BeeperMusicTaskstart!\r\n"); hi_pwm_set_clock(PWM_CLK_XTAL);//设置时钟源为晶体时钟(40MHz,默认时钟源160MHz) for(size_ti=0;i< sizeof(g_scoreNotes)/sizeof(g_scoreNotes[0]); i++) { uint32_t tune = g_scoreNotes[i]; // 音符 uint16_t freqDivisor = g_tuneFreqs[tune]; uint32_t tuneInterval = g_scoreDurations[i] * (125*1000); // 音符时间 printf("%d %d %d %d\r\n", tune, (40*1000*1000) / freqDivisor, freqDivisor, tuneInterval); PwmStart(WIFI_IOT_PWM_PORT_PWM0, freqDivisor/2, freqDivisor); usleep(tuneInterval); PwmStop(WIFI_IOT_PWM_PORT_PWM0); } return NULL; }
其中谱子最后两个5是谱子的错误,应该是低八度的5,也就是5下面应该打一个点;我修改了代码,让整个曲子听起来更自然;
编辑:hfy
-
有源无源蜂鸣器
+关注
关注
0文章
2浏览量
1158 -
鸿蒙
+关注
关注
57文章
2358浏览量
42876
发布评论请先 登录
相关推荐
评论