HarmonyOS LYEVK-3861開發板播放《蜜雪冰城》
在LYEVK-3861開發板的學習過程中,發現缺少基于鴻蒙2.0的相關文檔,同時缺少基于2.0系統 IoT接口的應用示例。在學習PWM相關接口的過程中,了解到PWM接口驅動蜂鳴器可以實現類似音樂播放的效果,個人覺得是個不錯的思路,就有了本次的學習開發之旅。
環境準備
1、開發環境、編譯環境搭建,參考官方文檔,此處不在贅述。參考鏈接如下:
2、OpenHarmony 2.0 Canary源碼 源碼獲取,參考:
3、LYEVK-3861 IoT物聯網開發板套件
開發調試
2.1 相關基礎知識介紹
PWM輸出方波的IOT接口
鴻蒙系統IoT硬件子系統提供了一些外設相關的接口,目錄位于:
- base/iot_hardware/peripheral/interfaces/kits
PWM相關接口,接口頭文件為iot_pwm.h,其中開始輸出方波的接口為:
- unsigned int IoTPwmStart(unsigned int port, unsigned short duty, unsigned int freq);
接口參數介紹:
freq:IoTPwmStart接口中freq參數是分頻倍數,PWM實際輸出的方波頻率等于 PWM時鐘源頻率 除以 分頻倍數,即
- f = Fcs / freq
其中,Fcs是PWM時鐘源頻率;
duty:IoTPwmStart接口的duty參數可以控制輸出方波的占空比,占空比是指PWM輸出的方波波形的高電平時間占整個方波周期的比例,具體占空比值取值為1到99,例如想要輸出占空比 50%的方波信號,那么duty填的值就要是50。
音符-頻率對應關系

這個表中有一個規律——音高升高一個八度,頻率升高一倍。
- hi_u32 hi_pwm_set_clock(hi_pwm_clk_source clk_type);
160M時鐘源條件下,輸出方波的最低頻率是:160M/65535=2441.44…,這個頻率略高,在上面的表格中沒有找到音名。通過調用hi_pwm_set_clock接口,可以修改時鐘源,將時鐘源設置為晶體時鐘且時鐘頻率為40MHz,40M/65535= 610.3…,這樣就能夠輸出E5及以上的所有音符。
2.2 曲譜轉換
由于個人比較喜歡《蜜雪冰城》,我選擇了《蜜雪冰城主題曲》的曲譜作為素材,簡譜如下:
簡譜轉換
每個音符都需要有節拍,在外面的代碼里體現為停頓時間,不同音符的不同停頓時間,可以實現簡單的音樂起伏。
常見的節拍簡譜對應:

通過簡譜和以上表格的對應,就可以將我們現有的簡譜,轉換成為可以被程序識別的”程序譜子“。
2.3 編寫代碼
接口初始化
修改device/hisilicon/hispark_pegasus/sdk_liteos/build/config/usr_config.mk配置文件,打開PWM編譯支持,如已打開,可略過:
- # CONFIG_UART_DMA_SUPPORT is not set
- CONFIG_PWM_SUPPORT=y
- # CONFIG_PWM_HOLD_AFTER_REBOOT is not set
修改device/hisilicon/hispark_pegasus/sdk_liteos/app/wifiiot_app/init/app_io_init.c的如下代碼:
- #ifdef CONFIG_PWM_SUPPORT
- /* PWM 0/2/3/4/5 配置同理 */
- //hi_io_set_func(HI_IO_NAME_GPIO_8, HI_IO_FUNC_GPIO_8_PWM1_OUT);
- //GPIO引腳復用
- hi_io_set_func(HI_IO_NAME_GPIO_8, HI_IO_FUNC_GPIO_8_GPIO); //button
- hi_io_set_pull(HI_IO_NAME_GPIO_8, HI_IO_PULL_UP);
- hi_io_set_func(HI_IO_NAME_GPIO_9,HI_IO_FUNC_GPIO_9_PWM0_OUT);// PWM
- #endif
備注:2.0把GPIO的引腳復用從應用層移到了板級,對IO的功能做了更加細分的處理,之前一直以為2.0移除了相關的接口實現,最后才發現2.0做了功能上的優化。
實例代碼
按鍵驅動

說明:按鍵主要是為了開啟音樂的播放。
“程序”曲譜
《蜜雪冰城主題曲》的“程序”曲譜,定義如下:

以上的曲譜,看起來比較直觀,也比較容易理解,其中的一些宏定義定義如下:

有了以上的枚舉,可以自己直接譜曲,甚至不用拘泥于現有的曲子,當然放出來的具體效果如何,就因人而異了。
音符頻率
以下是IoTPwmStart接口的入口參數freq的定義,和前述枚舉是一一對應的:
音樂處理
- /* 音樂處理*/
- static void *BeeperMusicTask(const char *arg)
- {
- (void)arg;
- int status = 0;
- printf("BeeperMusicTask start!\r\n");
- hi_pwm_set_clock(PWM_CLK_XTAL); // 設置時鐘源為晶體時鐘(40MHz,默認時鐘源160MHz)
- while (1)
- {
- usleep(M_INTERVAL_TIME_US);
- /*第一次點擊按鍵播放,播放完以后按鍵才能繼續生效*/
- if (music == 1)
- {
- for (size_t i = 0; i < sizeof(g_interval) / sizeof(g_interval[0]); i++)
- {
- uint32 tune = g_interval[i].tuneNotes; // 音符
- uint16 freqDivisor = g_tuneFreqs[tune];
- uint32 tuneInterval = g_interval[i].interval * (TICKS_DELAY); // 音符時間
- IoTPwmStart(IOT_PWM_PORT0, PWM_DUTY, freqDivisor);
- usleep(tuneInterval);
- IoTPwmStop(IOT_PWM_PORT0);
- music = 0;
- }
- }
- }
- return NULL;
- }
功能展示
以上都完成之后,就可以編譯、燒錄,并測試最后的完成效果。
說明:
1、本程序需要Hi3861開發板配合交通燈板實現完整的演示
2、燒錄完成之后,RESET重啟開發板之后,音樂不會播放;
3、重啟開發板之后,點擊交通燈板開發播放音樂;播放過程中,按鍵失去效果,待播放完成之后,再次點擊按鍵,音樂繼續播放。