标签:value 蜂鸣器 声音 develop 意思 lan sse tun http
本文介绍如何在HiSpark Wi-Fi IoT套件上,使用Harmony OS IoT硬件子系统的PWM接口 驱动蜂鸣器 播放音乐。通过PwmStart
接口的注释,可以知道freq参数是分频倍数,PWM实际输出的方波频率等于 PWM时钟源频率 除以 分频倍数,即
f = Fcs / freq
其中,Fcs是PWM时钟源频率;
通过PwmStart
接口的duty
参数可以控制输出方波的占空比,占空比是指PWM输出的方波波形的高电平时间占整个方波周期的比例,具体占空比值是 duty 和 freq的比值,例如想要输出占空比 50%的方波信号,那么duty填的值就要是 freq/2;
参考:https://liam.page/2018/04/09/pitch-interval-and-harmonic/
通过前面的公式,我们知道:
unsinged short
类型,最大值为65535;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);
}
我们通过直接调用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;
那么问题来了——晶体时钟到底是多少?
我们可以通过通过实验,测算出晶体时钟频率,具体步骤如下:
hi_pwm_set_clock(PWM_CLK_XTAL);
设置时钟源为晶体时钟;PwmStart(WIFI_IOT_PWM_PORT_PWM0, 20*1000, 40*1000);
输出方波信号;1000 * 40 * 1000
也就是 40 MHz;因此,方波最低频率就是 40M / 65535 ,也就是:
>>> 40 * 1000 * 1000 / 65535
610.3608758678569
对照上面的频率表,可以知道,能够输出E?以上的所有音符;
为了代码实现起来简单,我选择了《两只老虎》的曲谱作为素材,很快找到了简谱:
对于缺乏音乐基础的同学,简谱上的一些记号可能不太清楚是什么意思,这里简单说明一下:
有了以上知识,我们就可以编写代码了,关键部分代码如下:
static volatile int g_buttonPressed = 0;
static const uint16_t g_tuneFreqs[] = {
0, // 40M Hz 对应的分频系数:
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 应该是低八度的,链接图片中的曲谱不对,声音到最后听起来不太对劲
};
// 曲谱时值,根据简谱记谱方法转写,4/4拍中下面划一条线是半拍,划两条线是四分之一拍,点是顺延半拍
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下面应该打一个点;我修改了代码,让整个曲子听起来更自然;
标签:value 蜂鸣器 声音 develop 意思 lan sse tun http
原文地址:https://blog.51cto.com/xusiwei/2545519