安信可离线语音VC-01/02:硬件规格书、开发资料、烧录工具、应用开发
安信可离线语音模组 VC-01、VC-02 系列教程 【基础认知篇】
安信可离线语音模组 VC-01、VC-02 系列教程 【快速上手篇】
安信可离线语音模组 VC-01、VC-02 系列教程 【中级入门篇】
安信可离线语音模组 VC-01、VC-02 系列教程 【高级进阶篇】
安信可离线语音模组 VC-01、VC-02 系列教程 【二次开发篇】虚拟开发环境搭建和分享
安信可离线语音模组 VC-01、VC-02 系列教程 【二次开发篇】事件和GPIO控制
安信可离线语音模组 VC-01、VC-02 系列教程 【二次开发篇】PWM输出
安信可离线语音模组 VC-01、VC-02 系列教程 【二次开发篇】串口输出
安信可离线语音模组 VC-01、VC-02 系列教程 【二次开发篇】SDK音频替换失败记录过程
安信可离线语音模组 VC-01、VC-02 系列教程 【二次开发篇】自定义音频播放控制
安信可离线语音VC-01/02:硬件规格书、开发资料、烧录工具、应用开发
安信可离线语音模组 VC-01、VC-02 系列教程 【基础认知篇】
安信可离线语音模组 VC-01、VC-02 系列教程 【快速上手篇】
安信可离线语音模组 VC-01、VC-02 系列教程 【中级入门篇】
安信可离线语音模组 VC-01、VC-02 系列教程 【高级进阶篇】
安信可离线语音模组 VC-01、VC-02 系列教程 【二次开发篇】虚拟开发环境搭建和分享
安信可离线语音模组 VC-01、VC-02 系列教程 【二次开发篇】事件和GPIO控制
安信可离线语音模组 VC-01、VC-02 系列教程 【二次开发篇】PWM输出
安信可离线语音模组 VC-01、VC-02 系列教程 【二次开发篇】串口输出
安信可离线语音模组 VC-01、VC-02 系列教程 【二次开发篇】SDK音频替换失败记录过程
安信可离线语音模组 VC-01、VC-02 系列教程 【二次开发篇】自定义音频播放控制
安信可离线语音模组 VC-01、VC-02 系列教程 【二次开发篇】PWM输出
简介
在上一篇文章中我们对SDK的GPIO输出进行了控制, 我们将在本章节对PWM的输出进行控制(如果没有看过上一篇文章的,建议先去看对组件和设计的库函数的介绍),本篇SDK文件还是使用的上一章节的SDK(如无特殊说明,SDK不变)。
默认PWM DEMO输出现象
首先,在user_config.h 文件中开启对PWMLED的宏, 使其用户代码默认烧录USER_DEMO_PWM_LED的例程。
首先对默认的Demo进行编译,并且下载到VC-02中。
将示波器连接到开发板背部的GPIOA27上, 那么此时示波器的波形如下所示:
占空比缓慢变化
#ifndef USER_INC_USER_PWM_H_#define USER_INC_USER_PWM_H_#ifdef __cplusplusextern "C" {#endif#include "unione.h"/** @ingroup uni_pwm_def* PWM管脚号*/typedef enum {PWM_NUM_1_A27 = 0,PWM_NUM_1_B0,PWM_NUM_1_B2, ///< PWM 1 only 1 pin work a timePWM_NUM_2_A28, ///< used for PA enable, don't use it on HB-M demo boardPWM_NUM_2_B1,PWM_NUM_2_B3, ///< PWM 2 only 1 pin work a timePWM_NUM_MAX}USER_PWM_NUM;/** @addtogroup uni_pwm_inf@{*//***@brief PWM初始化*@param num PWM管脚号*@param hz 频率*@param is_high_duty \a TRUE :占空比用高电平持续时间计算; \a FALSE :占空比用低电平持续时间计算*@retval 0 操作成功*@retval -1 操作失败*/int user_pwm_init(USER_PWM_NUM num, uni_u32 hz, uni_bool is_high_duty);/***@brief PWM反初始化*@param num PWM管脚号*@retval 0 操作成功*@retval -1 操作失败*/int user_pwm_final(USER_PWM_NUM num);/***@brief 开使PWM输出*@param num PWM管脚号*@param duty 占空比*@retval 0 操作成功*@retval -1 操作失败*/int user_pwm_start(USER_PWM_NUM num, uni_u8 duty);/***@brief 停止PWM输出*@param num PWM管脚号*@retval 0 操作成功*@retval -1 操作失败*/int user_pwm_stop(USER_PWM_NUM num);/***@brief 暂停PWM输出*@param num PWM管脚号*@retval 0 操作成功*@retval -1 操作失败*/int user_pwm_pause(USER_PWM_NUM num);/***@brief 恢复PWM输出*@param num PWM管脚号*@retval 0 操作成功*@retval -1 操作失败*/int user_pwm_resume(USER_PWM_NUM num);/***@brief PWM占空比切换*@param num PWM管脚号*@param duty 占空比*@retval 0 操作成功*@retval -1 操作失败*/int user_pwm_change_duty(USER_PWM_NUM num, uni_u8 duty);/***@brief PWM占空比增加*@param num PWM管脚号*@param ch_duty 增加的占空比*@retval 0 操作成功*@retval -1 操作失败*/int user_pwm_duty_inc(USER_PWM_NUM num, uni_u8 ch_duty);/***@brief PWM占空比减小*@param num PWM管脚号*@param ch_duty 减小的占空比*@retval 0 操作成功*@retval -1 操作失败*/int user_pwm_duty_dec(USER_PWM_NUM num, uni_u8 ch_duty);/** @}*/#ifdef __cplusplus}#endif#endif
自定义控制命令
static uni_pthread_t g_pwm_thread_id = 0;static bool g_pwm_thread_running = false;// Thread function to update LED brightness levelsstatic void _pwm_led_process(void *args) {LED_BRIGHT_LEVEL level = BRIGHT_LEVEL_0;g_pwm_thread_running = true;while (g_pwm_thread_running) {user_pwm_led_set_brightness(PWM_LED_GPIO_NUM, level);level += 1;if (level >= BRIGHT_LEVEL_MAX) {level = BRIGHT_LEVEL_0;}// uni_sleep(1); // Optional: slow down effect}}// Create PWM LED threadstatic Result _create_pwm_led_thread(void) {if (g_pwm_thread_running) {return E_OK;}thread_param param;uni_memset(¶m, 0, sizeof(param));param.stack_size = STACK_SMALL_SIZE;param.priority = OS_PRIORITY_LOW;uni_strncpy(param.task_name, "pwm_led", sizeof(param.task_name) - 1);if (0 != uni_pthread_create(&g_pwm_thread_id, ¶m, _pwm_led_process, NULL)) {return E_FAILED;}uni_pthread_detach(g_pwm_thread_id); // Auto cleanupreturn E_OK;}// Stop PWM threadstatic void _stop_pwm_led_thread(void) {if (!g_pwm_thread_running) {return;}g_pwm_thread_running = false;// Destroy thread if supported (may be platform-specific)if (g_pwm_thread_id != 0) {uni_pthread_destroy(g_pwm_thread_id); // Hard stopg_pwm_thread_id = 0;}user_pwm_led_set_brightness(PWM_LED_GPIO_NUM, BRIGHT_LEVEL_0); // Turn off LED}// Callback on voice commandstatic void _on_wakeup_cmd_cb(USER_EVENT_TYPE event, user_event_context_t *context) {if (context == NULL) return;event_goto_awakend_t *awake = &context->goto_awakend;if (strcmp(awake->cmd, "wakeup_uni") == 0) {_create_pwm_led_thread();user_player_reply_list_random(awake->reply_files);}}static void _custom_setting_cb(USER_EVENT_TYPE event,user_event_context_t *context) {event_custom_setting_t *setting = NULL;if (context) {setting = &context->custom_setting;if (strcmp(setting->cmd, "TurnOn") == 0) {_stop_pwm_led_thread();user_player_reply_list_random(setting->reply_files);}}}// Register event callbackstatic void _register_event_callback(void) {user_event_subscribe_event(USER_GOTO_AWAKENED, _on_wakeup_cmd_cb);user_event_subscribe_event(USER_CUSTOM_SETTING, _custom_setting_cb);}// Main entryint hb_user_pwm_testing(void) {if (0 != user_pwm_led_init(PWM_LED_GPIO_NUM)) {return -1;}_register_event_callback();return 0;}
上述代码的主要功能是定义两个用户事件 :
第一个为自定义设置的事件。
另一个则是唤醒事件 (上一篇文章中有介绍)。在识别到 “你好小美” 和 “打开灯光” 的时候控制对应的PWM行为。 如果当前PWM输出的线程没有被创建, 那么当识别到“你好小美”的时候将启动线程。当识别到“打开灯光”的时候则根据上述创建线程时的线程号删除线程。
/home/vc02/Downloads/uni_hb_m_solution/unione_lite_app_hb_m/user/src/user_main.c ,增加对上述自定义宏的支持。
实验现象

使用“你好小美” 唤醒,波形如下:
附件
uni_app_release_update.zip (882.62 KB, 下载次数: 0)
总结
业务咨询请联系:18022036575





