https://harmonyos.51cto.com/#zz
本文介绍如何在HiSpark Wi-Fi IoT套件上,使用Harmony OS IoT硬件子系统的PWM接口 驱动蜂鸣器 播放音乐。
用PWM输出方波的API
鸿蒙系统IoT硬件子系统提供了PWM相关接口,接口头文件为wifiiot_pwm.h,其中开始输出方波的接口为:
- /**
- * @brief Outputs PWM signals based on the input parameters.
- *
- * This function outputs PWM signals from a specified port based on
- * the configured frequency division multiple and duty cycle.
- *
- * @param port Indicates the PWM port number.
- * @param duty Indicates the PWM duty cycle.
- * @param freq Indicates the frequency-division multiple.
- * @return Returns {@link WIFI_IOT_SUCCESS} if the operation is successful;
- * returns an error code defined in {@link wifiiot_errno.h} otherwise.
- * @since 1.0
- * @version 1.0
- */
- unsigned int PwmStart(WifiIotPwmPort port, unsigned short duty, unsigned short freq);
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/
开发板可以输出的最低频率
通过前面的公式,我们知道:
- unsigned int HalPwmInit(HalWifiIotPwmPort port)
- {
- if (hi_pwm_set_clock(PWM_CLK_160M) != HI_ERR_SUCCESS) {
- return (unsigned int)HAL_WIFI_IOT_FAILURE;
- }
- return hi_pwm_init((hi_pwm_port)port);
- }
160M时钟源条件下,输出方波的最低频率是:160M/65535=2441.44...,这个频率还是略高,在上面的表格中没有找到音名。但是我可以用上面表格值继续往后推算两个八度,就能够覆盖这个频率(不过通常只使用7个八度,所以还是有点高)。
如果时钟源频率可以更低,那么输出频率也可以更低!
幸运的是,通过调用hi_pwm_set_clock接口,可以修改时钟源:
- /**
- * @ingroup iot_pwm
- *
- * Enumerates the PWM clock sources.CNcomment:PWM时钟源枚举。CNend
- */
- typedef enum {
- 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;
那么问题来了——晶体时钟频率到底是多少?
晶体时钟频率是多少?
可以通过实验测算出晶体时钟频率,具体步骤如下:
经实际测量,方波频率为1000Hz,
因此,时钟频率为 1000 * 40 * 1000,即 40 MHz;
可以输出的方波最低频率
因此,方波最低频率就是 40M / 65535 ,也就是:
>>> 40 * 1000 * 1000 / 65535
610.3608758678569
对照上面的频率表,可以知道,能够输出E5及以上的所有音符;
准备曲谱
为了代码实现起来简单,我选择了《两只老虎》的曲谱作为素材,在简谱网找到了简谱:
简谱说明
简谱上的一些记号,有的同学可能不太清楚是什么意思,这里简单说明一下:
编写代码
有了以上知识,我们就可以编写代码了,关键代码如下:
- static const uint16_t g_tuneFreqs[] = { // 音符对应的分频系数
- 0, // 40M Hz 时钟源,C6 ~ B6:
- 38223, // 1 1046.5
- 34052, // 2 1174.7
- 30338, // 3 1318.5
- 28635, // 4 1396.9
- 25511, // 5 1568
- 22728, // 6 1760
- 20249, // 7 1975.5
- 51021 // 5_ 783.99 // 低一个八度的 5
- };
- // 曲谱音符
- static const uint8_t g_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 应该是低八度的,链接图片中的曲谱不对,声音到最后听起来不太对劲
- };
- // 曲谱时值,根据简谱记谱方法转写
- static const uint8_t g_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,
- };
- static void *BeeperMusicTask(const char *arg)
- {
- (void)arg;
- printf("BeeperMusicTask start!\r\n");
- hi_pwm_set_clock(PWM_CLK_XTAL); // 设置时钟源为晶体时钟(40MHz,默认时钟源160MHz)
- for (size_t i = 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下面应该打一个点;我修改了代码,让整个曲子听起来更自然;
服务器租用的常见问题有哪些 关于 服务器租用 的常见问题有哪些,对于很多站长来...
给实例分配用户。 调试 您可以在OpenAPI Explorer中直接运行该接口,免去您计算...
效果展示 您可以 下载 安装我们的 Demo 体验多人视频会议的效果,包括屏幕分享、...
非侵入式注解源码 样例指南 父主题: 分布式事务开发指南...
1. 接口描述 接口请求域名: gaap.tencentcloudapi.com 。 创建安全策略 默认接...
服务器租用 的问题: 一、 服务器租用 服务器关键 虽说直接从IDC机房 服务器租用...
填写文档满意度调查问卷,赢取代金券。立即前往 》 腾讯云文档中心: https://cl...
服务器操作系统在当前Linux服务器操作系统成果的基础上,针对上述差距,结合国内...
域名 必须得实名制才能解析吗?一般来说是的,因为目前在过我们有很多域名都是需...
1. 接口描述 接口请求域名: vpc.tencentcloudapi.com 。 本接口(DescribeFlowL...