更多信息请访问:Harmonyos.51cto.com在物联网套件上,使用鸿蒙OS物联网硬件子系统的PWM接口驱动蜂鸣器播放音乐。使用PWM输出方波的API鸿蒙系统物联网硬件子系统提供了PWM相关接口。接口头文件是wifiiot_pwm.h,开始输出方波的接口是:/***@briefOutputsPWMsignalsbasedontheinputparameters。**这个函数outputsPWMsignalsfromaspecifiedportbasedon*thecyconfiguredfrequencydivisionmultipleandduty*@paramportIndicatesthePWMportnumber.*@paramdutyIndi??catesthePWMdutycycle.*@paramfreqReturn*Indicatesthefrequency-divisionlinkWIFI_IOT_SUCCESS}iftheoperationissuccessful;*returnsanerrorcodedefinedin{@linkwifiiot_errno.h}否则。*@since1.0*@version1.0*/unsignedintPwmStart(WifiIotPwmPortport,unsignedshortduty,unsignedshortfreq);从PwmStart接口的注释可以看出PWM输出方波的频率。freq参数为分频倍数,PWM实际输出的方波频率等于PWM时钟源的频率除以分频倍数,即f=Fcs/freq其中,Fcs为频率PWM时钟源;PWM输出方波的占空比可以通过PwmStart接口的duty参数来控制。方波周期的比例,具体的占空比是duty与freq的比值,比如你要输出一个占空比为50%的方波信号,那么duty填写的值应该是freq/2;这张表中的音符频率对应关系有一个规则——将音高提高一个八度,频率加倍。表格来自:https://liam.page/2018/04/09/pitch-interval-and-harmonic/开发板可以输出的最低频率通过前面的公式,我们知道:PWM的方波频率输出与freq成反比,freq越大,输出方波频率越小;freq是一个unsingedshort类型,最大值为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);}在160M时钟源的情况下,输出方波的最小频率为:160M/65535=2441.44...这个频率还是略高的,上面没找到注释名桌子。但是我可以用上面的表值继续外推两个八度来覆盖这个频率(不过通常只用到7个八度,所以还是有点高)。如果时钟源频率可以更低,那么输出频率也可以更低!好在调用hi_pwm_set_clock接口可以修改时钟源:/***@ingroupiot_pwm**EnumeratesthePWMclocksources.CNcomment:PWM时钟源枚举。CNend*/typedefenum{PWM_CLK_160M,/**<160MAPBclock.CNcomment:160M工作时钟CNend*/PWM_CLK_XTAL,/**<24M/40Mcrystalclock.CNcomment:24M或40M晶振CNend*/PWM_CLK_MAX/**<最大值,不能使用。CNcomment:最大值,CNend*/}hi_pwm_clk_source;hi_u32hi_pwm_set_clock(hi_pwm_clk_sourceclk_type);通过注释我们知道hi_pwm_set_clock(PWM_CLK_XTAL);时钟源可以设置为晶振,晶振可以是24M或者40M;那么问题来了——晶振时钟频率是多少?什么是晶体时钟频率?晶振频率可以通过实验计算得到,具体步骤如下:usehi_pwm_set_clock(PWM_CLK_XTAL);设置时钟源为晶振时钟;使用PwmStart(WIFI_IOT_PWM_PORT_PWM0,20*1000,40*1000);输出方波信号;用示波器测量方波频率,根据测量的频率计算出时钟源频率;经实测,方波的频率为1000Hz,因此时钟频率为1000*40*1000,即40MHz;可以输出方波的最低频率因此,方波的最低频率为40M/65535,即:>>>40*1000*1000/65535610.3608758678569根据上面的频率表,可以知道E5以上的音符都可以输出;准备乐谱对于代码实现来说比较简单,我选择我用《两只老虎》的乐谱作为素材,在简谱网站上找到了简谱:numberednotationexplanationssomesymbolsonthecolumnednotation,有些同学可能不知道是什么就是说,这里简单解释一下:左上角的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后面的横线表示延迟一拍;在“onehasnoeyes”这句中,5后面的点表示半拍的延长,一条下划线表示半拍一次,两条下划线表示四分之一的时间;编写代码有了以上知识,我们就可以编写代码了,关键代码如下:staticconstuint16_tg_tuneFreqs[]={//音符0对应的分频系数,//40MHz时钟源,C6~B6:38223,//11046.534052,//21174.730338,//31318.528635,//41396.925511,//5156822728,//6176020249,//71975.551021//5_783.99/低八度}//音符staticconstuint8_st[g]=score/Note简化符号:http://www.jianpu.cn/pu/33/33945.htm1,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应该低一个八度,分数在链接的图片错了,最后声音听起来不对};//乐谱的时长,按照计分法记述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);//设置clocksourcetocrystalclock(40MHz,defaultclocksourceis160MHz)for(size_ti=0;i
