00. 目录
文章目录
01. 概述
PWM(Pulse Width Modulation , 脉冲宽度调制) 是一种对模拟信号电平进行数字编码的方法,通过不同频率的脉冲使用方波的占空比用来对一个具体模拟信号的电平进行编码,使输出端得到一系列幅值相等的脉冲,用这些脉冲来代替所需要波形的设备。
上图是一个简单的 PWM 原理示意图,假定定时器工作模式为向上计数,当计数值小于阈值时,则输出一种电平状态,比如高电平,当计数值大于阈值时则输出相反的电平状态,比如低电平。当计数值达到最大值是,计数器从0开始重新计数,又回到最初的电平状态。高电平持续时间(脉冲宽度)和周期时间的比值就是占空比,范围为0~100%。上图高电平的持续时间刚好是周期时间的一半,所以占空比为50%。
一个比较常用的pwm控制情景就是用来调节灯或者屏幕的亮度,根据占空比的不同,就可以完成亮度的调节。PWM调节亮度并不是持续发光的,而是在不停地点亮、熄灭屏幕。当亮、灭交替够快时,肉眼就会认为一直在亮。在亮、灭的过程中,灭的状态持续时间越长,屏幕给肉眼的观感就是亮度越低。亮的时间越长,灭的时间就相应减少,屏幕就会变亮。
PWM_21">02. PWM相关类型
2.1 hi_pwm_clk_source
/*** @ingroup iot_pwm** Enumerates the PWM clock sources.CNcomment:PWM时钟源枚举。CNend*/
typedef enum {PWM_CLK_160M, /**< 160M APB clock.CNcomment:160M 工作时钟 CNend */PWM_CLK_XTAL, /**< 24M/40M crystal clock.CNcomment:24M或40M 晶体时钟 CNend */PWM_CLK_MAX /**< Maximum value, which cannot be used.CNcomment:最大值,不可使用CNend */
} hi_pwm_clk_source;
2.2 hi_pwm_port
/*** @ingroup iot_pwm** Enumerates the PWM ports.CNcomment:PWM端口枚举。CNend*/
typedef enum {HI_PWM_PORT_PWM0 = 0, /**< PWM port0. Register base address: 0x40040000, multiplexed with GPIOX.CNcomment:PWM0端口。寄存器基址:0x40040000,复用GPIOX。CNend */HI_PWM_PORT_PWM1 = 1, /**< PWM port1. Register base address: 0x40040100, multiplexed with GPIOX.CNcomment:PWM1端口。寄存器基址:0x40040100,复用GPIOX。CNend */HI_PWM_PORT_PWM2 = 2, /**< PWM port2. Register base address: 0x40040200, multiplexed with GPIOX.CNcomment:PWM2端口。寄存器基址:0x40040200,复用GPIOX。CNend */HI_PWM_PORT_PWM3 = 3, /**< PWM port3. Register base address: 0x40040300, multiplexed with GPIOX.CNcomment:PWM3端口。寄存器基址:0x40040300,复用GPIOX。CNend */HI_PWM_PORT_PWM4 = 4, /**< PWM port4. Register base address: 0x40040400, multiplexed with GPIOX.CNcomment:PWM4端口。寄存器基址:0x40040400,复用GPIOX。CNend */HI_PWM_PORT_PWM5 = 5, /**< PWM port5. Register base address: 0x40040500, multiplexed with GPIOX.CNcomment:PWM5端口。寄存器基址:0x40040500,复用GPIOX。CNend */HI_PWM_PORT_MAX /**< Maximum value, which cannot be used.CNcomment:最大值,不可使用CNend */
} hi_pwm_port;
PWMAPI_69">03. PWM相关API
3.1 hi_pwm_init
/**
* @ingroup iot_pwm
* @brief Initializes the PWM module.CNcomment:PWM初始化。CNend
*
* @par 描述:
* Initializes the PWM module.CNcomment:PWM初始化。CNend
* @attention
* @li Before using the PWM function, ensure that the GPIO multiplexing relationship has been configured.
CNcomment:使用PWM功能前需要确认已配置GPIO复用关系。CNend
* @li For details, see Hi3861 V100 API Development Guide.
CNcomment:具体配置方法请参见<Hi3861V100 API开发指南>Demo介绍小节相关说明。CNend
* @li For details about the multiplexed GPIO, see the Hi3861 V100 Data Sheet.
CNcomment:具体复用的GPIO请参见<Hi3861 芯片 硬件用户指南>。CNend
* @li Before using the PWM function, initialize the PWM.CNcomment:使用PWM功能前需要先初始化。CNend
*
* @param port [IN] type #hi_pwm_port PWM port number.CNcomment:PWM端口号。CNend
*
* @retval #HI_ERR_SUCCESS Success.
* @retval #Other Failure. For details, see hi_errno.h.
* @par 依赖:
* @li hi_pwm.h: Describes the APIs of the PWM module.CNcomment:文件用于描述PWM对外接口。CNend
* @see hi_pwm_deinit | hi_pwm_start | hi_pwm_stop。
*/
hi_u32 hi_pwm_init(hi_pwm_port port)
功能:初始化指定 PWM 端口
参数:port:指定的 PWM 端口。前面介绍芯片 GPIO 功能时,每个管脚都有对应的功能,在使用 PWM 时,需选择具有 PWM 功能的 IO 即可。
返回值:0 成功,1 失败
3.2 hi_pwm_deinit
/**
* @ingroup iot_pwm
* @brief Deinitializes the PWM module.CNcomment:PWM去初始化。CNend
*
* @par 描述:
* Deinitializes the PWM module.CNcomment:PWM去初始化。CNend
*
* @attention Deinitialize the PWM module when the function iss not used.
CNcomment:不使用PWM功能时去初始化。CNend
*
* @param port [IN] type #hi_pwm_port PWM port number.CNcomment:PWM端口号。CNend
*
* @retval #HI_ERR_SUCCESS Success.
* @retval #Other Failure. For details, see hi_errno.h.
* @par 依赖:
* @li hi_pwm.h: Describes the APIs of the PWM module.CNcomment:文件用于描述PWM对外接口。CNend
* @see hi_pwm_init。
*/
hi_u32 hi_pwm_deinit(hi_pwm_port port)
功能:不使用 PWM 功能时去初始化
参数:port:指定的 PWM 端口。
返回值:0 成功,1 失败
3.3 hi_pwm_start
/**
* @ingroup iot_pwm
* @brief Outputs the PWM signal according to the configured parameter.
* PWM signal duty cycle = duty/freq Frequency = Clock source frequency/freq.
CNcomment:按配置的参数输出PWM信号。PWM信号占空比=duty/freq。频率=时钟源频率/freq。CNend
*
* @par 描述:
* Starts the PWM signal output.CNcomment:启动PWM信号输出。CNend
*
* @attention This API cannot be called in an interrupt.CNcomment:不支持在中断中调用。CNend
*
* @param port [IN] type #hi_pwm_port PWM port number.CNcomment:PWM端口号。CNend
* @param duty [IN] type #hi_u16 PWM duty cycle count. Value range: [1, 65535]. The default value is 750.
CNcomment:PWM占空比计数值。取值范围为:[1, 65535]。默认值为750。CNend
* @param freq [IN] type #hi_u16 Frequency division multiple. Value range: [1, 65535]. The default value is 1500.
CNcomment:分频倍数。取值范围为:[1, 65535]。默认值为1500。CNend
*
* @retval #HI_ERR_SUCCESS Success.
* @retval #Other Failure. For details, see hi_errno.h.
* @par 依赖:
* @li hi_pwm.h: Describes the APIs of the PWM module.CNcomment:文件用于描述PWM对外接口。CNend
* @see hi_pwm_init | hi_pwm_stop。
*/
hi_u32 hi_pwm_start(hi_pwm_port port, hi_u16 duty, hi_u16 freq)
功能:启动 PWM 信号输出,不支持在中断中调用参数:port:指定的 PWM 端口。duty:PWM 占空比,范围 1-65535,默认值为 750。freq:分频系数,范围 1-65535,默认为 1500。PWM 频率默认为 160MHz。
返回值:0 成功,1 失败
说明
**freq:分频倍数。**该参数用于控制输出的 PWM 信号频率,具体输出的频率 Fout 等于时钟源频率 Fclk (160MHz)除以 freq 参数的值,即有以下对应关系:
Fout = Fclk / freq = 160 MHz / freq
**duty:PWM 占空比计数值。**该参数用于指定占空比,占空比的具体值为 duty 参数和 freq 参数的比例,即有以下对应关系:
占空比 = duty / freq
3.4 hi_pwm_stop
/**
* @ingroup iot_pwm
* @brief Stops the PWM signal output.CNcomment:停止PWM信号输出。CNend
*
* @par 描述:
* Stops the PWM signal output.CNcomment: 停止PWM信号输出。CNend
*
* @attention This API cannot be called in an interrupt.CNcomment:不支持在中断中调用。CNend
*
* @param port [IN] type #hi_pwm_port PWM port number.CNcomment:PWM端口号。CNend
*
* @retval #HI_ERR_SUCCESS Success.
* @retval #Other Failure. For details, see hi_errno.h.
* @par 依赖:
* @li hi_pwm.h: Describes the APIs of the PWM module.CNcomment:文件用于描述PWM对外接口。CNend
* @see hi_pwm_init | hi_pwm_start。
*/
hi_u32 hi_pwm_stop(hi_pwm_port port)
功能:停止 PWM 信号输出,不支持在中断中调用参数:port:指定的 PWM 端口。
返回值:0 成功,1 失败
04. 硬件设计
从网络标号可知,LED 与芯片的 IO2 管脚连接,当该引脚输出高电平时,LED点亮,输出低电平时,LED 熄灭。
05. 软件设计
bsp_pwm.h
#ifndef __BSP_PWM_H__#define __BSP_PWM_H__#include <unistd.h>
#include "cmsis_os2.h"#include "hi_io.h"
#include "hi_gpio.h"//pwm初始化
void pwm_init(void);//设置pwm占空比
void pwm_set_duty1(uint16_t duty);#endif /*__BSP_PWM_H__*/
bsp_pwm.c
#include <unistd.h>
#include "bsp_pwm.h"#include "bsp_led.h"
#include "hi_pwm.h"//pwm初始化
void pwm_init(void)
{//1. GPIO初始化hi_gpio_init();//3. 设置GPIO为PWM功能hi_io_set_func(LED_PIN, HI_IO_FUNC_GPIO_2_PWM2_OUT);//4. 设置GPIO为输出hi_gpio_set_dir(LED_PIN, HI_GPIO_DIR_OUT);//PWM初始化hi_pwm_init(HI_PWM_PORT_PWM2);}//设置pwm占空比
void pwm_set_duty1(uint16_t duty)
{hi_pwm_start(HI_PWM_PORT_PWM2, duty, 4000);
}
template.c
#include <stdio.h>
#include <unistd.h>#include "ohos_init.h"
#include "cmsis_os2.h"#include "hi_io.h"
#include "hi_gpio.h"#include "bsp_pwm.h"#define TASK_STACK_SIZE 1024//任务1ID
osThreadId_t task1_id;
osThreadId_t task2_id;//线程回调入口函数
void task1 (void *argument)
{int16_t i = 0;//PWM初始化pwm_init();while(1){for (i = 0; i <= 2000; i++){printf("i = %d\n", i);pwm_set_duty1(i);usleep(1000);}for (i = 2000; i >= 0; i--){printf("i = %d\n", i);pwm_set_duty1(i);usleep(1000);}}}/*** @description: 初始化并创建任务* @param {*}* @return {*}*/
static void template_demo(void)
{ osThreadAttr_t attr;attr.name = "task1"; //任务名称attr.attr_bits = osThreadDetached; //分离状态attr.cb_mem = NULL;attr.cb_size = 0;attr.stack_mem = NULL;attr.stack_size = TASK_STACK_SIZE;attr.priority = osPriorityNormal;//创建任务1task1_id = osThreadNew(task1, NULL, &attr);if (NULL != task1_id){printf("任务1创建OK task1_id = %d\n", task1_id);}}
SYS_RUN(template_demo);
06. 实验现象
实验现象:LED 指示灯亮度变化,由暗变亮,再由亮变暗的循环过程。