外设及示例

更新时间:2023-01-29 07:31:53下载pdf

本文主要是用来介绍如何通过 Tuya OS 使用各部分外设,通过阅读该文档你可以对 Tuya OS 的设备驱动模型有一定的认识。

那么如何如何借助 Tuya OS 控制各部分外设呢?首先需要了解设备的驱动框架。

阅读 sdk\include\tuya_driver.h 可以看到 Tuya OS 的设备驱动框架,它支持的设备类型有:

typedef enum {
    TUYA_DRV_PIN             = 0x01,
    TUYA_DRV_UART,
    TUYA_DRV_PWM,
    TUYA_DRV_TIMER,
    TUYA_DRV_ADC,          
    TUYA_DRV_I2C,
    TUYA_DRV_RTC,
    TUYA_DRV_SPI,
    TUYA_DRV_CUSTOM,
} tuya_drv_type_t;

驱动查找函数:

void *tuya_driver_find(uint8_t type, uint8_t port);

对设备外设进行驱动的过程都遵守 查找设备 -> 初始化设备 -> 启动/使能设备 -> 操作设备 -> 去使能设备 这个流程。GPIO 除外,它没有查找设备这一步。

1. GPIO

在 TuyaOS 中 GPIO 的接口函数如下:

函数名称 功能描述
int tuya_pin_init(tuya_pin_name_t pin, tuya_pin_mode_t mode); 初始化引脚模式
int tuya_pin_write(tuya_pin_name_t pin, tuya_pin_level_t level); 设置引脚的电平
int tuya_pin_read(tuya_pin_name_t pin); 读取引脚的电平
int tuya_pin_irq_init(tuya_pin_name_t pin, tuya_pin_mode_t irq_mode, tuya_pin_irq_cb cb, void *arg); 初始化引脚中断
int tuya_pin_irq_enable(tuya_pin_name_t pin); 使能引脚中断
int tuya_pin_irq_disable(tuya_pin_name_t pin); 禁能引脚中断
int tuya_pin_control(tuya_pin_name_t pin, uint8_t cmd, void *arg); 引脚相关控制

tuya_pin.h 文件位于 sdk\include 中。


1.1 tuya_pin_init()


int tuya_pin_init(tuya_pin_name_t pin, tuya_pin_mode_t mode);

引脚初始化函数。

Parameters:

  • pin: 要初始化的引脚序号,应为 tuya_pin_name_t 枚举中的值。
  • mode: 初始化的模式选择,应为 tuya_pin_mode_t 枚举中的值。

Return:

  • OPRT_OK: 函数执行成功。
  • other: 函数执行失败。

tuya_pin_name_t 枚举:

//! TUYA_PA ->  TUYA_PA0 - TUYA_PA31
//! TUYA_PB ->  TUYA_PB0 - TUYA_PB31
//! TUYA_PC ->  TUYA_PC0 - TUYA_PC31
//! TUYA_PD ->  TUYA_PD0 - TUYA_PD31
//! TUYA_PE ->  TUYA_PE0 - TUYA_PE31
typedef enum {
    TUYA_PINS_NAME(TUYA_PA),
    TUYA_PINS_NAME(TUYA_PB),
    TUYA_PINS_NAME(TUYA_PC),
    TUYA_PINS_NAME(TUYA_PD),
    TUYA_PINS_NAME(TUYA_PE),
} tuya_pin_name_t;

tuya_pin_mode_t 枚举:

typedef enum {
    //! PU  ->  pull up
    //! PD  ->  pull dowm
    //! FL  ->  floating
    //! PP  ->  push pull
    //! OD  ->  open drain
    //! hiz ->  high-impedance level

    TUYA_PIN_MODE_IN_PU               = TUYA_PIN_IN     | TUYA_PIN_PULL_UP,
    TUYA_PIN_MODE_IN_PD               = TUYA_PIN_IN     | TUYA_PIN_PULL_DOWN,
    TUYA_PIN_MODE_IN_FL               = TUYA_PIN_IN_FL,

    TUYA_PIN_MODE_IN_IRQ_RISE         = TUYA_PIN_IN_IRQ | TUYA_PIN_IRQ_RISE | TUYA_PIN_PULL_UP, 
    TUYA_PIN_MODE_IN_IRQ_FALL         = TUYA_PIN_IN_IRQ | TUYA_PIN_IRQ_FALL | TUYA_PIN_PULL_UP,
    TUYA_PIN_MODE_IN_IRQ_RISE_FALL    = TUYA_PIN_IN_IRQ | TUYA_PIN_IRQ_RISE_FALL | TUYA_PIN_PULL_UP,
    TUYA_PIN_MODE_IN_IRQ_LOW          = TUYA_PIN_IN_IRQ | TUYA_PIN_IRQ_LOW   | TUYA_PIN_PULL_UP,
    TUYA_PIN_MODE_IN_IRQ_HIGH         = TUYA_PIN_IN_IRQ | TUYA_PIN_IRQ_HIGH  | TUYA_PIN_PULL_UP,
    
    TUYA_PIN_MODE_OUT_PP_LOW          = TUYA_PIN_OUT_PP | TUYA_PIN_INIT_LOW,
    TUYA_PIN_MODE_OUT_PP_HIGH         = TUYA_PIN_OUT_PP | TUYA_PIN_INIT_HIGH,

    TUYA_PIN_MODE_OUT_PP_PU_LOW       = TUYA_PIN_OUT_PP | TUYA_PIN_PULL_UP | TUYA_PIN_INIT_LOW,
    TUYA_PIN_MODE_OUT_PP_PU_HIGH      = TUYA_PIN_OUT_PP | TUYA_PIN_PULL_UP | TUYA_PIN_INIT_HIGH,

    TUYA_PIN_MODE_OUT_PP_PD_LOW       = TUYA_PIN_OUT_PP | TUYA_PIN_PULL_DOWN | TUYA_PIN_INIT_LOW,
    TUYA_PIN_MODE_OUT_PP_PD_HIGH      = TUYA_PIN_OUT_PP | TUYA_PIN_PULL_DOWN | TUYA_PIN_INIT_HIGH,

    TUYA_PIN_MODE_OUT_OD_LOW          = TUYA_PIN_OUT_OD | TUYA_PIN_INIT_LOW,
    TUYA_PIN_MODE_OUT_OD_HIZ          = TUYA_PIN_OUT_OD | TUYA_PIN_INIT_HIGH,

    TUYA_PIN_MODE_OUT_OD_PU_LOW       = TUYA_PIN_OUT_OD | TUYA_PIN_PULL_UP | TUYA_PIN_INIT_LOW,
    TUYA_PIN_MODE_OUT_OD_PU_HIGH      = TUYA_PIN_OUT_OD | TUYA_PIN_PULL_UP | TUYA_PIN_INIT_HIGH,
} tuya_pin_mode_t;

1.2 tuya_pin_write()


int tuya_pin_write(tuya_pin_name_t pin, tuya_pin_level_t level);

设置引脚电平。设置的引脚应在之前初始化为输出模式。

Parameters:

  • pin: 要设置的引脚序号,应为 tuya_pin_name_t 枚举中的值。
  • level: 要设置的电平值,应为 tuya_pin_level_t 枚举中的值。

Return:

  • OPRT_OK: 函数执行成功。
  • other: 函数执行失败。

tuya_pin_level_t 枚举:

typedef enum {
    TUYA_PIN_LOW  = 0,
    TUYA_PIN_HIGH
} tuya_pin_level_t;

1.3 tuya_pin_read()


int tuya_pin_read(tuya_pin_name_t pin);

读取引脚电平。设置的引脚应在之前初始化为输入模式。

Parameters:

  • pin: 要读取的引脚序号,应为 tuya_pin_name_t 枚举中的值。

Return:

  • TUYA_PIN_LOW: 读取到的电平值为低。
  • TUYA_PIN_HIGH: 读取到的电平值为高。


1.4 tuya_pin_irq_init()


int tuya_pin_irq_init(tuya_pin_name_t pin, tuya_pin_mode_t irq_mode, tuya_pin_irq_cb cb, void *arg);

GPIO 中断初始化函数。

Parameters:

  • pin: 初始的引脚序号,应为 tuya_pin_name_t 枚举中的值。
  • irq_mode: 中断触发模式,应为 tuya_pin_mode_t 枚举中的值。
  • cb: 回调函数。
  • arg: 回调函数参数值。

Return:

  • OPRT_OK: 函数执行成功。
  • other: 函数执行失败。


1.5 tuya_pin_irq_enable()


int tuya_pin_irq_enable(tuya_pin_name_t pin);

GPIO 中断使能函数。

Parameters:

  • pin: 要使能的中断引脚,应为 tuya_pin_name_t 枚举中的值。

Return:

  • OPRT_OK: 函数执行成功。
  • other: 函数执行失败。


1.6 tuya_pin_irq_disable()


int tuya_pin_irq_disable(tuya_pin_name_t pin);

GPIO 中断去使能函数。

Parameters:

  • pin: 去使能的中断引脚,应为 tuya_pin_name_t 枚举中的值。

Return:

  • OPRT_OK: 函数执行成功。
  • other: 函数执行失败。


1.7 应用示例

下图 1 处的日志是将 PA7 接到 PA6 上打印出来的结果。2 处的日志是将 PA8 从浮空状态到 GND 触发了外部中断时出现的日志输出。

点击到 GitHub 查看完整工程代码

外设及示例


2. LED

2.1 tuya_create_led_handle()


OPERATE_RET tuya_create_led_handle(IN CONST tuya_pin_name_t pinname,IN CONST BOOL_T high,OUT LED_HANDLE *handle);

LED 设备创建。

Parameters:

  • pinname: LED 引脚号
  • high: TRUE:LED 引脚初始化为高电平;FLASE:LED 引脚初始化为低电平。
  • handle: [OUT] LED 句柄。

Return:

  • OPRT_OK: 函数执行成功。
  • other: 函数执行失败。


2.2 tuya_set_led_light_type()


VOID tuya_set_led_light_type(IN CONST LED_HANDLE handle,IN CONST LED_LT_E type,
                             IN CONST USHORT_T flh_mstime,IN CONST USHORT_T flh_ms_sumtime);

LED 输出类型设置。

Parameters:

  • handle: LED 句柄。
  • type: LED 输出类型,应为 LED_LT_E 枚举中的值。
  • flh_mstime: 状态改变间隔时间,单位毫秒 ms。
  • flh_ms_sumtime: 闪烁总时间,单位毫秒 ms。设置为 0xFFFF 将会一直闪烁。注意该数据类型为 USHORT_T ,设置的最大时间应为 65534ms。

Return:

  • OPRT_OK: 函数执行成功。
  • other: 函数执行失败。

这里值得一说的是 LED_LT_E 中的几个枚举值:

typedef enum {
    OL_LOW = 0,    // output level low
    OL_HIGH,       // output level high
    OL_FLASH_LOW,  
    OL_FLASH_HIGH, 
}LED_LT_E;

OL_FLASH_LOW 类型是 LED 闪烁,并且最后引脚输出为高电平。

OL_FLASH_HIGH 类型是 LED 闪烁,并且最后引脚输出为低电平。

函数中的 flh_mstime 形参是 LED 状态改变的间隔时间,flh_ms_sumtime 为 LED 闪烁总时间。配置成 OL_FLASH_LOWOL_FLASH_HIGH 这种 LED 闪烁模式时,第一次会先将引脚设置为低电平然后再按照设置的间隔时间进行闪烁,等闪烁时间达到总时间会将最总状态设置为指定状态。OL_FLASH_LOW 最终引脚输出为高电平。OL_FLASH_HIGH 最终引脚输出为低电平。


2.3 应用示例

点击到 GitHub 查看完整工程代码


3. KEY

在 TuyaOS 中按键的接口函数如下:

函数名称 功能描述
OPERATE_RET key_init(IN CONST KEY_USER_DEF_S *p_tbl, IN CONST INT_T cnt, IN CONST INT_T timer_space); 按键服务初始化函数
OPERATE_RET reg_proc_key(IN CONST KEY_USER_DEF_S *key_ud); 注册一个新的按键。

tuya_key.h 文件位于 sdk\include 中。


3.1 key_init()


OPERATE_RET key_init(IN CONST KEY_USER_DEF_S *p_tbl, IN CONST INT_T cnt, IN CONST INT_T timer_space);

按键服务初始化函数。

Parameters:

  • p_tbl: 按键配置结构体。
  • cnt: 注册的按键个数。
  • timer_space: 按键检测时间,不要超过 100ms。如果传入为 0,使用默认时间 20ms。

Return:

  • OPRT_OK: 函数执行成功。
  • other: 函数执行失败。

这里需要特别注意的也就是按键注册结构体:

typedef struct {
    /** PIN ID */
    tuya_pin_name_t port;
    /** whether low level trigger */
    BOOL_T low_level_detect;
    /** long press type, see KEY_LONG_PRESS_TP_E */
    KEY_LONG_PRESS_TP_E lp_tp;
    /** unit: ms, lp_tp == LP_ONCE_TRIG then valid and must >= 1000ms */
    USHORT_T long_key_time;
    /** unit:ms , 0:disable default:400ms */
    USHORT_T seq_key_detect_time;
    /** handler of KEY event */
    KEY_CALLBACK call_back;
}KEY_USER_DEF_S;
结构体成员 含义
port 按键使用的引脚 ID。
low_level_detect TRUE: 低电平有效,FALSE: 高电平有效。
lp_tp 按键长按触发方式,更多信息查看 KEY_LONG_PRESS_TP_E 枚举。
long_key_time 长按时间,单位毫秒 ms。lp_tp 类型为 LP_ONCE_TRIG 时有效,时间应该大于等于 1000ms。
seq_key_detect_time 连按检测时间,单位毫秒 ms。0 关闭连按检测,默认事件为 400 ms。
call_back 按键触发后调用的回调函数。

按键长按类型枚举体 KEY_LONG_PRESS_TP_E

typedef enum {
    /** long press invalid */
    LP_INVALID = 0,
    /** long press once trigger */
    LP_ONCE_TRIG,
    /** long press more normal trigger */
    LP_MORE_NORMAL_TRIG,
    /** press key immedialtely trigger */
    FALLING_EDGE_TRIG,
    /** press key immedialtely trigger & LONG */
    FALLING_LONG_TRIG,
}KEY_LONG_PRESS_TP_E;

按键回调函数原型如下:

typedef VOID(* KEY_CALLBACK)(tuya_pin_name_t port,PUSH_KEY_TYPE_E type,INT_T cnt);

PUSH_KEY_TYPE_E 为按键按下类型枚举体:

typedef enum {
    /** one shot */
    NORMAL_KEY = 0,
    /** continual shot */
    SEQ_KEY,
    /** long press */
    LONG_KEY,
}PUSH_KEY_TYPE_E;

3.2 reg_proc_key()


OPERATE_RET reg_proc_key(IN CONST KEY_USER_DEF_S *key_ud);

注册一个新的按键。

Parameters:

  • key_ud: 按键配置结构体。

Return:

  • OPRT_OK: 函数执行成功。
  • other: 函数执行失败。

3.3 应用示例

这里使用 TUYA_PA9 引脚作为按键,可以通过日志看出按键被按下的状态是长按、短按还是连按。

点击到 GitHub 查看完整工程代码

外设及示例


4. UART

在 TuyaOS 中串口的接口函数如下:

函数名称 功能描述
int tuya_uart_init(tuya_uart_t *uart); 串口初始化
int tuya_uart_read(tuya_uart_t *uart, void *data, uint16_t len); 串口发送数据
int tuya_uart_write(tuya_uart_t *uart, void *data, uint16_t len); 串口读数据
int tuya_uart_control(tuya_uart_t *uart, uint8_t cmd, void *arg); 串口控制
int tuya_uart_deinit(tuya_uart_t *uart); 串口去初始化

tuya_uart.h 文件位于 sdk\include 中。

在 CBU (BK7231N) 中,UART1(模组上丝印为 TX2,RX2) 被用作 log 日志打印使用,建议大家在进行实验时使用 UART0 (模组上丝印为 TX1,RX1)进行操作。


4.1 tuya_uart_init()


int tuya_uart_init(tuya_uart_t *uart);

串口设备初始化函数。初始化串口,申请资源。

Parameters:

  • uart: 串口句柄,初始化相关参数。

Return:

  • OPRT_OK: 函数执行成功。
  • other: 函数执行失败。

int tuya_uart_init(tuya_uart_t *uart); 串口初始化函数,通过该函数对串口的波特率、数据位、停止位等进行配置。想要使用该函数进行初始化,必须先对 tuya_uart_t 结构体中的 tuya_uart_cfg_t 结构体有一个了解。

tuya_uart_t 结构体原型如下:

struct tuya_uart{
    tuya_drv_node_t     node;	//串口节点
    tuya_uart_cfg_t     cfg;	//串口配置参数
    tuya_uart_cb_t      cb;		//串口回调函数
    tuya_uart_ops_t    *ops;
    void               *rxfifo;
};
typedef struct tuya_uart tuya_uart_t;

在对串口进行配置的时候,只需要关心 tuya_uart_t 结构体中的 tuya_uart_cfg_t 结构体, tuya_uart_cfg_t 结构体原型如下:

typedef struct {
    uint16_t                flag;		//配置接收或发送模式
    uint16_t                bufsz;		//接收缓存大小
    tuya_uart_baudrate_t    baudrate;	//波特率
    tuya_uart_databits_t    databits;	//数据位
    tuya_uart_stopbits_t    stopbits;	//停止位
    tuya_uart_parity_t      parity;		//校验位
} tuya_uart_cfg_t;

tuya_uart_cfg_t 结构体中的 flag 参数是用来配置串口的接收或发送模式,其可选择的配置如下(tuya_drv_flag_t 位于sdk\include\tuya_driver.h 中):

typedef enum{
    TUYA_DRV_INT_RX_FLAG     = 0x01, //中断接收
    TUYA_DRV_INT_TX_FLAG     = 0x02, //中断发送
    TUYA_DRV_DMA_RX_FLAG     = 0x04, //DMA 接收 
    TUYA_DRV_DMA_TX_FLAG     = 0x08, //DMA 发送
    TUYA_DRV_NONBLOCK_FLAG   = 0x10, //非阻塞方式
}tuya_drv_flag_t;

其他配置可选参数如下:

//波特率
typedef enum{
    TUYA_UART_BAUDRATE_300        = 300,
    TUYA_UART_BAUDRATE_600        = 600,
    TUYA_UART_BAUDRATE_1200       = 1200,
    TUYA_UART_BAUDRATE_2400       = 2400,
    TUYA_UART_BAUDRATE_4800       = 4800,
    TUYA_UART_BAUDRATE_9600       = 9600,
    TUYA_UART_BAUDRATE_19200      = 19200,
    TUYA_UART_BAUDRATE_38400      = 38400,
    TUYA_UART_BAUDRATE_57600      = 57600,
    TUYA_UART_BAUDRATE_74880      = 74880,
    TUYA_UART_BAUDRATE_115200     = 115200,
    TUYA_UART_BAUDRATE_230400     = 230400,
    TUYA_UART_BAUDRATE_460800     = 460800,
    TUYA_UART_BAUDRATE_921600     = 921600,
    TUYA_UART_BAUDRATE_1500000    = 1500000,
    TUYA_UART_BAUDRATE_1843200    = 1843200,
    TUYA_UART_BAUDRATE_3686400    = 3686400,
}tuya_uart_baudrate_t;

//数据位
typedef enum{
    TUYA_UART_DATA_BIT5           = 0x05,
    TUYA_UART_DATA_BIT6           = 0x06,
    TUYA_UART_DATA_BIT7           = 0x07,
    TUYA_UART_DATA_BIT8           = 0x08,
}tuya_uart_databits_t;

//停止位
typedef enum{
    TUYA_UART_STOP_BIT1           = 0x01,
    TUYA_UART_STOP_BIT1_5         = 0x02,
    TUYA_UART_STOP_BIT2           = 0x03,
}tuya_uart_stopbits_t;

//校验位
typedef enum{
    TUYA_UART_PARITY_NONE         = 0,   
    TUYA_UART_PARITY_ODD          = 1,  
    TUYA_UART_PARITY_EVEN         = 2,   
}tuya_uart_parity_t;

在调用 tuya_uart_init(tuya_uart_t *uart); 函数对串口进行初始化之前,需要先调用 tuya_driver_find() 函数找到串口设备。

这里以初始化 UART0 为例,示例代码如下:

#include "uni_log.h"
#include "tuya_driver.h"
#include "tuya_uart.h"
...
tuya_uart_t * uart0;

void uart0_init(void)
{
    int32_t op_ret;
    
    uart0 = (tuya_uart_t *)tuya_driver_find(TUYA_DRV_UART, TY_UART0);
    if (NULL == uart0) {
        PR_DEBUG("find uart0 fail");
        return;
    }

    TUYA_UART_8N1_CFG(uart0, TUYA_UART_BAUDRATE_115200, 256, TUYA_DRV_INT_RX_FLAG);

    op_ret = tuya_uart_init(uart0);
    if (OPRT_OK != op_ret) {
        PR_ERR("uart init fail, error code: %d", op_ret);
    }

    return;
}
...

示例中使用的是阻塞的方式进行配置的,如果想要将串口配置成非阻塞的方式,只需将 tuya_uart_cfg_t 结构体中的 flag 参数或上 TUYA_DRV_NONBLOCK_FLAG 皆可将串口配置为非阻塞的方式。


4.2 tuya_uart_write()


int tuya_uart_write(tuya_uart_t *uart, void *data, uint16_t len);

串口发送函数。

Parameters:

  • uart: 串口句柄。
  • data: 要发送数据的指针。
  • len: 要发送的数据字节长度。

Return:

实际发送的数据长度。



4.2 tuya_uart_read()


int tuya_uart_read(tuya_uart_t *uart, void *data, uint16_t len);

串口接收函数。

Parameters:

  • uart: 串口句柄。
  • data: [OUT]接收数据存放地址的指针。
  • len: 能够接收数据的最大长度。

Return:

实际接收到的数据长度。



4.3 tuya_uart_control()


int tuya_uart_control(tuya_uart_t *uart, uint8_t cmd, void *arg);

串口设备控制函数。

Parameters:

  • uart: 串口句柄。
  • cmd: 命令控制字,可取值:TUYA_DRV_CONFIG_CMD。
  • arg: 控制的参数。

Return:

  • OPRT_OK: 函数执行成功。
  • other: 函数执行失败。


4.4 tuya_uart_deinit()


int tuya_uart_deinit(tuya_uart_t *uart);

串口设备去初始化函数。关闭串口,释放串口占用的资源。

Parameters:

  • uart: 串口句柄,初始化相关参数。

Return:

  • OPRT_OK: 函数执行成功。
  • other: 函数执行失败。


4.5 应用示例

示例中串口 0 初始化波特率为115200,初始化完成后会先打印 hello uart0, baudrate 115200 ,随后给串口 0 发送什么它就会回复什么。默认是串口配置的是阻塞方式,如果想要配置为非阻塞方式,可以将 UART_NONBLOCK_EN 宏设置为 1 ,初始化串口的时候就会设置为非阻塞的方式。更多细节点击下方链接阅读源码进行查看。

点击到 GitHub 查看完整工程代码

外设及示例


5. PWM

CBU 的 PWM 编号和硬件引脚对应图如下:

PWM 端口号 引脚
PWM0 P6
PWM1 P7
PWM2 P8
PWM3 P9
PWM4 P24
PWM5 P26

在 TuyaOS 中与 PWM 相关的接口函数如下:

函数名称 功能描述
int tuya_pwm_init(tuya_pwm_t *pwm); PWM 初始化
int tuya_pwm_start(tuya_pwm_t *pwm); 启动 PWM
int tuya_pwm_stop(tuya_pwm_t *pwm); 停止 PWM
int tuya_pwm_set(tuya_pwm_t *pwm, float frequency, float percent); 设置 PWM 频率和占空比
int tuya_pwm_frequency_set(tuya_pwm_t *pwm, float frequency); 设置 PWM 频率
int tuya_pwm_duty_set(tuya_pwm_t *pwm, float percent); 设置 PWM 占空比
int tuya_pwm_polarity_set(tuya_pwm_t *pwm, tuya_pwm_polarity_t polarity); 设置 PWM 初始极性
int tuya_pwm_deinit(tuya_pwm_t *pwm); PWM 去初始化

tuya_pwm.h 文件位于 sdk\include 中。

5.1 tuya_pwm_init()


int tuya_pwm_init(tuya_pwm_t *pwm);

PWM 初始化函数。

Parameters:

  • pwm: PWM句柄。

Return:

  • OPRT_OK: 函数执行成功。

  • other: 函数执行失败。



使用 PWM 初始化函数时,需要关注 tuya_pwm_t 结构体中的 cfg 成员。cfg 是 PWM 的配置结构体,其原型如下:

typedef struct{
    uint8_t         pin;			//PWM输出的引脚号
    uint8_t         polarity;		//PWM输出极性
    uint32_t        period_ns;		//PWM输出的周期
    uint32_t        pulse_ns;		//PWM输出的脉宽
    float           percent;		//PWM数据占空比
}tuya_pwm_cfg_t;

PWM 配置结构体中的 pin 指的是对应的 PWM 引脚,具体的 PWM 对应的 pin 可以查看上面的表格。

polarity 用来设置 PWM 的极性,可供选择的选项有:

typedef enum{
    TUYA_PWM_POSITIVE = 0,
    TUYA_PWM_NEGATIVE,
}tuya_pwm_polarity_t;

period_ns 是 PWM 输出的周期,通过对 period_ns 的设置来配置 PWM 的输出频率,period_ns 和 PWM 的输出频率 frequency 之间的关系为:

period_ns = (uint32_t)1000000000 / (frequency)。

pulse_ns 是 PWM 输出的脉宽,通过对 pulse_ns 的设置可以配置 PWM 的输出的占空比。在 SDK 对 PWM 占空比的设置是通过 pulse_nspercentperiod_ns 共同来完成的,其计算方法如下:

pulse_ns = period_ns * percent。

在实际使用过程中,可以通过直接操作结构体来配置 PWM ,也可以通过使用 TUYA_PWM_CFG 这个宏去配置 PWM。 TUYA_PWM_CFG 原型如下:

#define TUYA_PWM_CFG(__PWM, __PIN, __FREQUENCY, __PERCENT)                      \
    (__PWM)->cfg.pin       = __PIN;                                             \
    (__PWM)->cfg.period_ns = (uint32_t)1000000000 / (__FREQUENCY);              \
    (__PWM)->cfg.percent   = __PERCENT;                                       \
    (__PWM)->cfg.pulse_ns  = (uint32_t)((__PWM)->cfg.period_ns * (__PERCENT));  \
    (__PWM)->cfg.polarity  = TUYA_PWM_POSITIVE

5.2 tuya_pwm_start()


int tuya_pwm_start(tuya_pwm_t *pwm);

启动 PWM。

Parameters:

  • pwm: PWM 句柄。

Return:

  • OPRT_OK: 函数执行成功。

  • other: 函数执行失败。



5.3 tuya_pwm_stop()


int tuya_pwm_stop(tuya_pwm_t *pwm);

停止 PWM。

Parameters:

  • pwm: PWM 句柄。

Return:

  • OPRT_OK: 函数执行成功。

  • other: 函数执行失败。



5.4 tuya_pwm_set()


int tuya_pwm_set(tuya_pwm_t *pwm, float frequency, float percent);

设置 PWM 的频率、占空比。

Parameters:

  • pwm: PWM 句柄。
  • frequency: PWM 频率。
  • percent: PWM 占空比(输入在 0~1.0 之间)。

Return:

  • OPRT_OK: 函数执行成功。

  • other: 函数执行失败。



5.5 tuya_pwm_frequency_set()


int tuya_pwm_frequency_set(tuya_pwm_t *pwm, float frequency);

设置 PWM 频率。

Parameters:

  • pwm: PWM 句柄。
  • frequency: PWM 频率。

Return:

  • OPRT_OK: 函数执行成功。

  • other: 函数执行失败。



5.6 tuya_pwm_duty_set()


int tuya_pwm_duty_set(tuya_pwm_t *pwm, float percent);

设置 PWM 占空比。

Parameters:

  • pwm: PWM 句柄。
  • percent: PWM 占空比(输入在 0~1.0 之间)。

Return:

  • OPRT_OK: 函数执行成功。

  • other: 函数执行失败。



5.7 tuya_pwm_polarity_set()


int tuya_pwm_polarity_set(tuya_pwm_t *pwm, tuya_pwm_polarity_t polarity);

设置 PWM 极性。

Parameters:

  • pwm: PWM 句柄。
  • polarity: PWM 极性。

Return:

  • OPRT_OK: 函数执行成功。

  • other: 函数执行失败。


tuya_pwm_polarity_t 枚举原型如下:

typedef enum {
    TUYA_PWM_POSITIVE = 0,
    TUYA_PWM_NEGATIVE,
} tuya_pwm_polarity_t;

5.8 tuya_pwm_deinit()


int tuya_pwm_deinit(tuya_pwm_t *pwm);

PWM 去初始化。

Parameters:

  • pwm: PWM 句柄。

Return:

  • OPRT_OK: 函数执行成功。

  • other: 函数执行失败。



5.9 应用示例

这里的应用示例演示了如何初始化 PWM,后续其他对于 PWM 的设置可以通过调用上方对应的设置接口进行设置。

点击到 GitHub 查看完整工程代码


6. ADC

CBU 的 ADC 测量范围为:0-2.4V。

在 CBU(BK7231N) 中,SDK 中 ADC 的编号和模组丝印对应如下:

SDK 枚举值 模组丝印
TUYA_ADC0 P26
TUYA_ADC1 P24
TUYA_ADC2 ADC(P23)

在 TuyaOS 中与 ADC 相关的接口函数如下:

函数名称 功能描述
int tuya_adc_init(tuya_adc_t *adc); ADC 初始化
int tuya_adc_convert(tuya_adc_t *adc, uint16_t *data, uint16_t num); ADC 转换函数
int tuya_adc_deinit(tuya_adc_t *adc); ADC 去初始化

tuya_adc.h 文件位于 sdk\include 中。

6.1 tuya_adc_init()


int tuya_adc_init(tuya_adc_t *adc);

ADC 初始化函数。初始化 ADC,申请相关资源。

Parameters:

  • adc: ADC 句柄。

Return:

  • OPRT_OK: 函数执行成功。

  • other: 函数执行失败。



6.2 tuya_adc_convert()


int tuya_adc_convert(tuya_adc_t *adc, uint16_t *data, uint16_t num);

ADC 转换函数。获取到数据为原始数据,最大值为4096,采集最大电压为 2.4v 。

Parameters:

  • adc: ADC 句柄。
  • data: ADC 转换得到的原始数据。
  • num: ADC 采集次数。

Return:

  • OPRT_OK: 函数执行成功。

  • other: 函数执行失败。



6.3 tuya_adc_deinit()


int tuya_adc_deinit(tuya_adc_t *adc);

ADC 去初始化函数。关闭 ADC,并释放其所占有的资源。

Parameters:

  • adc: ADC 句柄。

Return:

  • OPRT_OK: 函数执行成功。

  • other: 函数执行失败。



6.4 应用示例

示例中初始化了 TUYA_ADC2,也就是模组上丝印为 ADC (P23) 的引脚。初始化完成后会通过日志口每隔 1S 打印一次采集到的值(实际输出的值为转换后的值,实际电压值的 1000 倍)。

点击到 GitHub 查看完整工程代码

外设及示例


7. TIMER

在 TuyaOS 中与定时器相关的接口函数如下:

函数名称 功能描述
int tuya_timer_init(tuya_timer_t *timer); 定时器初始化函数
int tuya_timer_start(tuya_timer_t* timer, uint32_t us); 定时器启动函数
int tuya_timer_stop(tuya_timer_t* timer); 定时器停止函数
int tuya_timer_deinit(tuya_timer_t* timer); 定时器去初始化函数

tuya_timer.h 文件位于 sdk\include 中。

7.1 tuya_timer_init()


int tuya_timer_init(tuya_timer_t *timer);

定时器初始化函数。

Parameters:

  • timer: timer 句柄。

Return:

  • OPRT_OK: 函数执行成功。

  • other: 函数执行失败。


在调用 tuya_timer_init() 函数对定时器进行初始化之前,需要先调用 tuya_driver_find() 函数找到设备,然后对定时器进行配置完成后才可以初始化定时器。

调用 void *tuya_driver_find(uint8_t type, uint8_t port); 去发现定时器设备的时候,需要传入 port 这个参数。在定时器中 port 可以选择的参数有:

typedef enum {
    TUYA_TIMER0 = 0,
    TUYA_TIMER1,
    TUYA_TIMER2,
    TUYA_TIMER3,
    TUYA_TIMER4,
    TUYA_TIMER5,
} tuya_timer_port_t;

定时器的配置参数如下:

typedef enum {
    TUYA_TIMER_MODE_ONCE = 0,	// 单次定时
    TUYA_TIMER_MODE_PERIOD		// 周期定时
} tuya_timer_mode_t;

typedef struct {
    tuya_timer_mode_t    mode;	// 模式
    tuya_timer_isr_cb    cb;	// 回调
    void                *arg;	// 参数
} tuya_timer_cfg_t;

对定时器进行配置的时候,可以直接对结构体进行操作。也可以使用下面的宏进行配置。

#define TUYA_TIMER_CFG(__TIMER, __MODE, __CB, __ARG)                          \
    (__TIMER)->cfg.mode = __MODE;                                             \
    (__TIMER)->cfg.cb   = __CB;                                               \
    (__TIMER)->cfg.arg  = __ARG

配置宏中的 __TIMER 参数填入上面 tuya_driver_find() 返回得到的结构体指针。

__MODE 参数是用来配置定时器是单次定时还是周期定时,在tuya_timer_mode_t 枚举体中进行选择。

__CB 参数是定时器的回调函数,在超时后会调用该函数。

__ARG 参数是传入回调函数的参数值。

配置完成后就可以使用 tuya_timer_init() 函数对定时器进行初始化,初始化完成后定时器并没有开始运行,需要调用 tuya_timer_start() 函数后定时器才运行起来。


7.2 tuya_timer_start()


int tuya_timer_start(tuya_timer_t* timer, uint32_t us);

定时器启动函数。

Parameters:

  • timer: timer 句柄。
  • us: 超时时间,单位微秒。

Return:

  • OPRT_OK: 函数执行成功。

  • other: 函数执行失败。



7.3 tuya_timer_stop()


int tuya_timer_stop(tuya_timer_t* timer);

定时器停止函数。

Parameters:

  • timer: timer句柄。

Return:

  • OPRT_OK: 函数执行成功。

  • other: 函数执行失败。


这里停止定时器之后,定时器相关的资源并没有释放掉,可以再次直接调用 tuya_timer_start() 启动定时器,不需再次初始化定时器。


7.4 tuya_timer_deinit()


int tuya_timer_deinit(tuya_timer_t* timer);

定时器去初始化函数。

Parameters:

  • timer: timer句柄。

Return:

  • OPRT_OK: 函数执行成功。

  • other: 函数执行失败。



7.5 应用示例

该示例中,演示了如何初始化定时器,定时器超时时间设置为 1S,定时器模式为周期定时。每隔 1S 进入一次回调函数打印一条日志出来。

点击到 GitHub 查看完整工程代码

外设及示例