PWM

更新时间:2023-01-29 07:32:17下载pdf

文件说明

API 文件

PWM 相关 API 位于 ty_pwm.h 文件中,芯片平台关联的驱动代码位于 ty_pwm_xxxx.c 文件中。

tuya_ble_sdk_demo
└── board
     ├── include
     |    └── ty_pwm.h
     ├── xxxx                      /* xxxx 为芯片平台,如 TLSR825x */
     |    └── ty_board_xxxx        /* xxxx 为芯片平台,如 ty_board_tlsr825x */
     |         └── ty_pwm_xxxx.c   /* xxxx 为芯片平台,如 ty_pwm_tlsr825x.c */
     └── board.h

Demo 文件

tuya_board_api_demo 的 PWM Demo 文件结构如下:

tuya_ble_sdk_demo
├── app  /* API 应用示例 */
|    ├── include
|    |    └── ty_board_demo
|    |    |    ├── demo_config.h        /* demo 配置文件 */
|    |    |    └── ty_pwm_demo.h        /* pwm 模块示例代码 */
|    |    ├── tuya_ble_board_api_demo.h /* board api 示例程序入口 */
|    |    └── tuya_ble_sdk_demo.h       /* tuya_ble_sdk 应用入口 */
|    └── src
|         ├── ty_board_demo
|         |    └── ty_pwm_demo.c        /* pwm 模块示例代码 */
|         ├── tuya_ble_board_api_demo.c /* board api 示例程序入口 */
|         └── tuya_ble_sdk_demo.c       /* tuya_ble_sdk 应用入口 */
└── board /* 部分 API 修改示例 */

修改 demo_config.h 文件即可切换到 PWM 模块示例程序:

#define BOARD_API_DEMO          BOARD_API_PWM

API 列表

函数名称 功能描述
ty_pwm_init 初始化 PWM 模块
ty_pwm_start 启动 PWM 输出
ty_pwm_stop 停止 PWM 输出
ty_pwm_control 控制 PWM 模块
ty_pwm_uninit 关闭 PWM 模块

API 说明

ty_pwm_init

函数名 ty_pwm_init
函数原型 uint32_t ty_pwm_init(ty_pwm_t* p_pwm);
功能概述 初始化 PWM 模块
参数 p_pwm [in]:pwm 参数,由 ty_pwm_t 类型定义
返回值 0:成功;其他:失败
备注 可根据芯片平台按需补充或修改函数内容、参数及返回值

ty_pwm_start

函数名 ty_pwm_start
函数原型 uint32_t ty_pwm_start(ty_pwm_t* p_pwm);
功能概述 启动 PWM 输出
参数 p_pwm [in]:pwm 参数,由 ty_pwm_t 类型定义
返回值 0:成功;其他:失败
备注 可根据芯片平台按需补充或修改函数内容、参数及返回值

ty_pwm_stop

函数名 ty_pwm_stop
函数原型 uint32_t ty_pwm_stop(ty_pwm_t* p_pwm);
功能概述 停止 PWM 输出
参数 p_pwm [in]:pwm 参数,由 ty_pwm_t 类型定义
返回值 0:成功;其他:失败
备注 可根据芯片平台按需补充或修改函数内容、参数及返回值

ty_pwm_control

函数名 ty_pwm_control
函数原型 uint32_t ty_pwm_control(ty_pwm_t* p_pwm, uint8_t cmd, void* arg);
功能概述 控制 PWM 模块
参数 p_pwm [inout]:pwm 参数,由 ty_pwm_t 类型定义
cmd [in]:控制命令,由 ty_pwm_cmd_t 类型定义
arg [in]:命令参数,取决于控制命令
返回值 0:成功;其他:失败
备注 可根据芯片平台按需补充或修改函数内容、参数及返回值

ty_pwm_uninit

函数名 ty_pwm_uninit
函数原型 uint32_t ty_pwm_uninit(ty_pwm_t* p_pwm);
功能概述 关闭 PWM 模块
参数 p_pwm [in]:pwm 参数,由 ty_pwm_t 类型定义
返回值 0:成功;其他:失败
备注 可根据芯片平台按需补充或修改函数内容、参数及返回值

数据类型

ty_pwm_t

typedef struct {
    GPIO_PinTypeDef pin;            /* 引脚编号 */
    pwm_id id;                      /* PWM ID */
    uint8_t polarity;               /* 极性 */
    uint32_t freq;                  /* 周期 */
    uint8_t duty;                   /* 占空比 */
} ty_pwm_t;

ty_pwm_cmd_t

typedef enum {
    TY_PWM_CMD_SET_POLARITY = 0,    /* 极性 */
    TY_PWM_CMD_SET_FREQ,            /* 周期 */
    TY_PWM_CMD_SET_DUTY,            /* 占空比 */
} ty_pwm_cmd_t;

ty_pwm_set_polarity_t

typedef struct {
    uint8_t  polarity;              /* 极性(0-H, 1-L) */
} ty_pwm_set_polarity_t;

ty_pwm_set_freq_t

typedef struct {
    uint32_t freq;                  /* 周期(us) */
} ty_pwm_set_freq_t;

ty_pwm_set_duty_t

typedef struct {
    uint8_t  duty;                  /* 占空比(%) */
} ty_pwm_set_duty_t;

API 示例

以 TLSR825x 平台为例,可参考以下代码补充 PWM 模块的 API 函数,或者直接在应用代码中调用芯片原厂提供的 API 来实现相关功能。

ty_pwm.h

/* 根据TLSR825x的pwm通道和引脚对应关系,修改参数id为func */
typedef struct {
    GPIO_PinTypeDef pin;            /* 引脚编号 */
    GPIO_FuncTypeDef func;          /* 引脚功能 */
    uint8_t polarity;               /* 极性 */
    uint32_t freq;                  /* 周期 */
    uint8_t duty;                   /* 占空比 */
} ty_pwm_t;

ty_pwm_tlsr825x.c

/****************************************************
    PWM0   :  PA2.  PC1.  PC2.  PD5.
    PWM1   :  PA3.  PC3.
    PWM2   :  PA4.  PC4.
    PWM3   :  PB0.  PD2.
    PWM4   :  PB1.  PB4.
    PWM5   :  PB2.  PB5.
    PWM0_N :  PA0.  PB3.  PC4.	PD5.
    PWM1_N :  PC1.  PD3.
    PWM2_N :  PD4.
    PWM3_N :  PC5.
    PWM4_N :  PC0.  PC6.
    PWM5_N :  PC7.
 ****************************************************/

uint32_t ty_pwm_init(ty_pwm_t* p_pwm)
{
    if (p_pwm == NULL) {
        return 1;
    }
    if (p_pwm->duty < 0 || p_pwm->duty > 100) {
        return 2;
    }
    if (p_pwm->func < AS_PWM0 || p_pwm->func > AS_PWM5_N) {
        return 3;
    }

    pwm_set_clk(CLOCK_SYS_CLOCK_HZ, CLOCK_SYS_CLOCK_HZ);
    gpio_set_func(p_pwm->pin, p_pwm->func);
    pwm_id id = (p_pwm->func < AS_PWM0_N) ? (p_pwm->func - AS_PWM0) : (p_pwm->func - AS_PWM0_N);
    pwm_set_mode(id, PWM_NORMAL_MODE);
    pwm_polo_enable(id, p_pwm->polarity);
    pwm_set_cycle_and_duty(id, (uint16_t)(p_pwm->freq * CLOCK_SYS_CLOCK_1US),
                               (uint16_t)(p_pwm->freq * CLOCK_SYS_CLOCK_1US * p_pwm->duty / 100));

    return 0;
}

uint32_t ty_pwm_start(ty_pwm_t* p_pwm)
{
    if (p_pwm == NULL) {
        return 1;
    }
    if (p_pwm->duty < 0 || p_pwm->duty > 100) {
        return 2;
    }
    if (p_pwm->func < AS_PWM0 || p_pwm->func > AS_PWM5_N) {
        return 3;
    }

    pwm_id id = (p_pwm->func < AS_PWM0_N) ? (p_pwm->func - AS_PWM0) : (p_pwm->func - AS_PWM0_N);
    pwm_start(id);
    return 0;
}

uint32_t ty_pwm_stop(ty_pwm_t* p_pwm)
{
    if (p_pwm == NULL) {
        return 1;
    }
    if (p_pwm->func < AS_PWM0 || p_pwm->func > AS_PWM5_N) {
        return 3;
    }

    pwm_id id = (p_pwm->func < AS_PWM0_N) ? (p_pwm->func - AS_PWM0) : (p_pwm->func - AS_PWM0_N);
    pwm_stop(id);
    return 0;
}

uint32_t ty_pwm_control(ty_pwm_t* p_pwm, uint8_t cmd, void* arg)
{
    if ((p_pwm == NULL) || (arg == NULL)) {
        return 1;
    }
    if (p_pwm->func < AS_PWM0 || p_pwm->func > AS_PWM5_N) {
        return 3;
    }
    pwm_id id = (p_pwm->func < AS_PWM0_N) ? (p_pwm->func - AS_PWM0) : (p_pwm->func - AS_PWM0_N);

    switch(cmd) {
    case TY_PWM_CMD_SET_POLARITY: {
            ty_pwm_set_polarity_t* param = arg;
            p_pwm->polarity = param->polarity;
            pwm_polo_enable(id, p_pwm->polarity);
        }
        break;
    case TY_PWM_CMD_SET_FREQ: {
            ty_pwm_set_freq_t* param = arg;
            p_pwm->freq = param->freq;
            pwm_set_cycle_and_duty(id, (uint16_t)(p_pwm->freq * CLOCK_SYS_CLOCK_1US),
                                       (uint16_t)(p_pwm->freq * CLOCK_SYS_CLOCK_1US * p_pwm->duty / 100));
        }
        break;
    case TY_PWM_CMD_SET_DUTY: {
            ty_pwm_set_duty_t* param = arg;
            if (p_pwm->duty < 0 || p_pwm->duty > 100) {
                return 2;
            }
            p_pwm->duty = param->duty;
            pwm_set_cmp(id, (uint16_t)(p_pwm->freq * CLOCK_SYS_CLOCK_1US * p_pwm->duty / 100));
        }
        break;
    default:
        break;
    }

    return 0;
}

uint32_t ty_pwm_uninit(ty_pwm_t* p_pwm)
{
    uint32_t res = ty_pwm_stop(p_pwm);
    if (res) {
        return res;
    }
    gpio_set_func(p_pwm->pin, AS_GPIO);
    return 0;
}

应用示例

功能概述

初期输出周期 500us,占空比 50%,极性高电平的 PWM 波形;2s 后,更新占空比为 80%;再 2s 后,更新周期为 800us;再 2s 后,更新极性为低电平;再 2s 后,停止 PWM 输出并关闭 PWM 模块。

代码示例

以 TLSR825x 平台为例:

#include "ty_pwm_demo.h"
#include "ty_pwm.h"
#include "tuya_ble_log.h"
#include "tuya_ble_port.h"

/***********************************************************
************************micro define************************
***********************************************************/
#define PWM_PIN             GPIO_PB5
#define PWM_FUNC            AS_PWM5

#define PWM_POL             0
#define PWM_POL_UPDATE      1
#define PWM_FREQ            500
#define PWM_FREQ_UPDATE     800
#define PWM_DUTY            50
#define PWM_DUTY_UPDATE     80

#define PWM_UPDATE_TIME_MS  2000

/***********************************************************
***********************variable define**********************
***********************************************************/
static ty_pwm_t sg_pwm = {
    .pin = PWM_PIN,
    .func = PWM_FUNC,
    .polarity = PWM_POL,
    .freq = PWM_FREQ,
    .duty = PWM_DUTY
};

static tuya_ble_timer_t sg_pwm_timer;

/***********************************************************
***********************function define**********************
***********************************************************/
/**
 * @brief pwm timer callback
 * @param[in] none
 * @return none
 */
void __pwm_timer_cb(void)
{
    static uint8_t s_step = 0;

    switch (s_step) {
    case 0: {
            ty_pwm_set_duty_t new_duty = {
                .duty = PWM_DUTY_UPDATE
            };
            ty_pwm_control(&sg_pwm, TY_PWM_CMD_SET_DUTY, &new_duty);
        }
        break;
    case 1: {
            ty_pwm_set_freq_t new_freq = {
                .freq = PWM_FREQ_UPDATE
            };
            ty_pwm_control(&sg_pwm, TY_PWM_CMD_SET_FREQ, &new_freq);
        }
        break;
    case 2: {
            ty_pwm_set_polarity_t new_pol = {
                .polarity = PWM_POL_UPDATE
            };
            ty_pwm_control(&sg_pwm, TY_PWM_CMD_SET_POLARITY, &new_pol);
        }
        break;
    case 3: {
            ty_pwm_stop(&sg_pwm);
            ty_pwm_uninit(&sg_pwm);
        }
        break;
    default:
        break;
    }
    if (s_step <= 3) {
        s_step++;
    }
}

/**
 * @brief ty_pwm api demo init
 * @param none
 * @return none
 */
void ty_pwm_demo_init(void)
{
    uint32_t res;
    res = ty_pwm_init(&sg_pwm);
    if (res) {
        TUYA_APP_LOG_ERROR("ty_pwm_init failed, error code: %d", res);
        return;
    }
    res = ty_pwm_start(&sg_pwm);
    if (res) {
        TUYA_APP_LOG_ERROR("ty_pwm_start failed, error code: %d", res);
        return;
    }
    tuya_ble_timer_create(&sg_pwm_timer, PWM_UPDATE_TIME_MS, TUYA_BLE_TIMER_REPEATED, (tuya_ble_timer_handler_t)__pwm_timer_cb);
    tuya_ble_timer_start(sg_pwm_timer);
}