PWM(Pulse Width Modulation,脉宽调制)驱动用于生成可控的脉冲信号,广泛应用于LED亮度调节、电机速度控制、音频播放等场景。
该示例使用 A10引脚 输出PWM信号,经过实际验证可用。
⚠️ 重要提示:
根据项目实际情况,A11 和 A12 引脚已用作协议串口输出,因此在选择PWM输出引脚时需要注意:
| 引脚 | 可用性 | 说明 |
|---|---|---|
| A10 | ✅ 可用 | 已验证可用,推荐使用 |
| A11 | ❌ 不可用 | 已用作协议串口TX,除非不需要协议输出 |
| A12 | ❌ 不可用 | 已用作协议串口RX,除非不需要协议输出 |
| B11 | ✅ 可用 | 可用于PWM输出 |
推荐:使用 A10 或 B11 引脚作为PWM输出。
#include "Driver_GPT_PWM.h"
#include "IOMuxManager.h"
#include "PowerManager.h"
#include "ClockManager.h"
void* GPT0_PWM(void);
功能: 获取GPT0 PWM驱动的实例指针
返回值:
示例:
void *pwm_handler = GPT0_PWM();
int32_t HAL_GPT_PWMInitialize(void *pGpt, void *user_param);
功能: 初始化PWM接口
参数:
pGpt: PWM实例指针,由 GPT0_PWM() 获取user_param: 用户参数,通常传 NULL返回值:
CSK_DRIVER_OK (0): 成功示例:
HAL_GPT_PWMInitialize(pwm_handler, NULL);
int32_t HAL_GPT_PWMUninitialize(void *pGpt);
功能: 反初始化PWM接口,释放资源
参数:
pGpt: PWM实例指针返回值:
CSK_DRIVER_OK (0): 成功int32_t HAL_GPT_PWMPowerControl(void *pGpt, CSK_POWER_STATE state);
功能: 控制PWM电源状态
参数:
pGpt: PWM实例指针state: 电源状态
CSK_POWER_OFF: 关闭电源CSK_POWER_LOW: 低功耗模式CSK_POWER_FULL: 全功率模式返回值:
CSK_DRIVER_OK (0): 成功示例:
HAL_GPT_PWMPowerControl(pwm_handler, CSK_POWER_FULL);
int32_t HAL_GPT_PWMControl(void *pGpt, uint32_t control, GPT_CHANNEL_TYPE channel);
功能: 配置PWM通道的工作模式
参数:
pGpt: PWM实例指针control: 控制参数(多个参数通过或运算组合)channel: PWM通道号(GPT_CHANNEL0 - GPT_CHANNEL5)控制参数:
| 参数 | 说明 |
|---|---|
CSK_GPT_PWM_MODE |
PWM模式(必须) |
CSK_GPT_PWM_CLKSRC_XTAL |
使用晶振时钟 |
CSK_GPT_PWM_CLKSRC_PCLK |
使用外设时钟 |
CSK_GPT_PWM_OUTMODE_EDGE_ALIGNED |
边沿对齐模式 |
CSK_GPT_PWM_OUTMODE_CENTRAL_ALIGNED |
中心对齐模式 |
CSK_GPT_PWM_OUTPOLARITY_LOW |
输出极性低电平有效 |
CSK_GPT_PWM_OUTPOLARITY_HIGH |
输出极性高电平有效 |
CSK_GPT_PWM_CLKDIV_1 |
时钟1分频 |
CSK_GPT_PWM_CLKDIV_2 |
时钟2分频 |
CSK_GPT_PWM_CLKDIV_4 |
时钟4分频 |
CSK_GPT_PWM_CLKDIV_8 |
时钟8分频 |
CSK_GPT_PWM_CLKDIV_16 |
时钟16分频 |
CSK_GPT_PWM_CLKDIV_32 |
时钟32分频 |
CSK_GPT_PWM_CLKDIV_64 |
时钟64分频 |
CSK_GPT_PWM_CLKDIV_128 |
时钟128分频 |
CSK_GPT_PWM_OPERATION_MODE_PWM |
PWM操作模式 |
示例:
uint32_t control = CSK_GPT_PWM_MODE |
CSK_GPT_PWM_CLKSRC_XTAL |
CSK_GPT_PWM_OUTMODE_EDGE_ALIGNED |
CSK_GPT_PWM_OUTPOLARITY_LOW |
CSK_GPT_PWM_CLKDIV_2 |
CSK_GPT_PWM_OPERATION_MODE_PWM;
HAL_GPT_PWMControl(pwm_handler, control, GPT_CHANNEL4);
int32_t HAL_GPT_SetPWMFreqDuty(void *pGpt, GPT_CHANNEL_TYPE channel, uint32_t freq, uint8_t duty);
功能: 设置PWM输出的频率和占空比
参数:
pGpt: PWM实例指针channel: PWM通道号freq: 频率(单位:Hz),例如 1000 表示 1kHzduty: 占空比(0-100),例如 50 表示 50%返回值:
CSK_DRIVER_OK (0): 成功示例:
// 设置1kHz频率,50%占空比
HAL_GPT_SetPWMFreqDuty(pwm_handler, GPT_CHANNEL4, 1000, 50);
// 设置10kHz频率,80%占空比
HAL_GPT_SetPWMFreqDuty(pwm_handler, GPT_CHANNEL4, 10000, 80);
int32_t HAL_GPT_EnablePWM(void *pGpt, GPT_CHANNEL_TYPE channel);
功能: 使能指定通道的PWM输出
参数:
pGpt: PWM实例指针channel: PWM通道号返回值:
CSK_DRIVER_OK (0): 成功示例:
HAL_GPT_EnablePWM(pwm_handler, GPT_CHANNEL4);
int32_t HAL_GPT_DisablePWM(void *pGpt, GPT_CHANNEL_TYPE channel);
功能: 禁止指定通道的PWM输出
参数:
pGpt: PWM实例指针channel: PWM通道号返回值:
CSK_DRIVER_OK (0): 成功示例:
HAL_GPT_DisablePWM(pwm_handler, GPT_CHANNEL4);
PWM输出需要正确配置引脚复用功能。使用 IOMuxManager_PinConfigure 函数配置引脚。
不同的引脚对应不同的PWM通道,具体映射关系需要参考芯片手册。以下是示例中使用的配置:
// A10引脚对应PWM通道4
#define PWM_CH4_PAD (CSK_IOMUX_PAD_A) // A组引脚
#define PWM_CH4_PIN (10) // 引脚编号10
#define PWM_CH4_SEL (CSK_IOMUX_FUNC_ALTER8) // 功能选择:PWM模式
配置示例:
IOMuxManager_PinConfigure(PWM_CH4_PAD, PWM_CH4_PIN, PWM_CH4_SEL);
基础 PWM 输出: ls_app_pwm.c
#include "stdint.h"
#include "lisa_log.h"
#include "Driver_GPT_PWM.h"
#include "IOMuxManager.h"
#include "shell.h"
#include "ClockManager.h"
#include "PowerManager.h"
#define TAG "pwm"
// 设置引脚PA10为PWM输出
#define PWM_CH4_PAD (CSK_IOMUX_PAD_A)
#define PWM_CH4_PIN (10)
#define PWM_CH4_SEL (CSK_IOMUX_FUNC_ALTER8)
#define PWM_CH4_FREQ (1000) // 频率
#define PWM_CH4_DUTY (50) // 占空比
static void *s_pwm_handler = NULL;
/******** PWM 初始化接口 ***********/
int ls_app_pwm_init()
{
uint32_t ret = 0;
if (!s_pwm_handler) {
__HAL_PMU_GPT_RST_ENABLE();
__HAL_CRM_GPT_S_CLK_ENABLE();
__HAL_CRM_GPT_T0_CLK_ENABLE();
__HAL_CRM_GPT_CLK_ENABLE();
s_pwm_handler = GPT0_PWM();
IOMuxManager_PinConfigure(PWM_CH4_PAD, PWM_CH4_PIN, PWM_CH4_SEL);
HAL_GPT_PWMUninitialize(s_pwm_handler);
HAL_GPT_PWMInitialize(s_pwm_handler, NULL);
ret = HAL_GPT_PWMPowerControl(s_pwm_handler, CSK_POWER_FULL);
ret |= HAL_GPT_PWMControl(s_pwm_handler, CSK_GPT_PWM_MODE | CSK_GPT_PWM_CLKSRC_XTAL |
CSK_GPT_PWM_OUTMODE_EDGE_ALIGNED | CSK_GPT_PWM_OUTPOLARITY_LOW |
CSK_GPT_PWM_CLKDIV_2 | CSK_GPT_PWM_OPERATION_MODE_PWM, GPT_CHANNEL4);
ret |= HAL_GPT_SetPWMFreqDuty(s_pwm_handler, GPT_CHANNEL4, PWM_CH4_FREQ, PWM_CH4_DUTY);
ret |= HAL_GPT_DisablePWM(s_pwm_handler, GPT_CHANNEL4);
if (0 != ret) LISA_LOGE(TAG, "ls app pwm init failed: %d!", ret);
}
return ret;
}
/******** PWM 控制接口 ***********/
int ls_app_pwm_ctl(bool onoff)
{
if (s_pwm_handler) {
int32_t ret = onoff ? HAL_GPT_EnablePWM(s_pwm_handler, GPT_CHANNEL4) :
HAL_GPT_DisablePWM(s_pwm_handler, GPT_CHANNEL4);
LISA_LOGD(TAG, "ls app pwm %s, ret: %d", onoff?"on":"off", ret);
return 0;
}
return -1;
}
/* **********************************
shell调试命令:
gpio.pwmtest 1 //开启pwm输出
gpio.pwmtest 0 //关闭pwm输出
* **********************************/
void shell_gpio_pwm_test(int onoff)
{
SHELL_ITEM_EXPORT("gpio.pwmtest", shell_gpio_pwm_test, "gpio A10 pwm test(1:on 0:off)");
ls_app_pwm_init();
ls_app_pwm_ctl((onoff == 0) ? false : true);
}
您可以 main.c 中调用 ls_app_pwm_init(); ls_app_pwm_ctl(true); 后开启 PWM 方波输出
初始化PWM前必须使能时钟和复位:
__HAL_PMU_GPT_RST_ENABLE();
__HAL_CRM_GPT_S_CLK_ENABLE();
__HAL_CRM_GPT_T0_CLK_ENABLE();
__HAL_CRM_GPT_CLK_ENABLE();
占空比范围是 0-100,精度为整数百分比。如需更高精度,可能需要调整时钟分频。
不同的引脚对应不同的PWM通道,使用前需要确认引脚与通道的映射关系。
检查步骤:
IOMuxManager_PinConfigure__HAL_CRM_GPT_CLK_ENABLE()HAL_GPT_EnablePWM 使能输出使用 HAL_GPT_SetPWMFreqDuty 函数可以动态修改频率:
HAL_GPT_SetPWMFreqDuty(pwm_handler, GPT_CHANNEL4, new_freq, duty);
使用示波器测量对应引脚的波形,应该能看到:
