【联盛德W806上手笔记】四、PWM模块

Windows 10 20H2
HLK-W806-V1.0-KIT
WM_SDK_W806_v0.6.0


       摘自《W806 芯片设计指导书 V1.0》、《W806 MCU 芯片规格书 V2.0》

PWM 控制器

       5 通道 PWM 信号生成功能
       2 通道输入信号捕获功能(PWM0 和 PWM4 两个通路)
       频率范围:3Hz~160KHz
       占空比最大精度:1/256,插入死区的计数器宽度:8bit
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

库函数

函数

       打开wm_pwm.h,有如下的函数声明:

HAL_StatusTypeDef	HAL_PWM_Init(PWM_HandleTypeDef *hpwm);
//初始化PWM通道
HAL_StatusTypeDef	HAL_PWM_DeInit(PWM_HandleTypeDef *hpwm);
//将初始化之后的通道恢复成默认的状态–各个寄存器复位时的值
void				HAL_PWM_MspInit(PWM_HandleTypeDef *hpwm);
//用于开启对应的时钟和复用对应引脚
void				HAL_PWM_MspDeInit(PWM_HandleTypeDef *hpwm);
//将对应时钟和引脚恢复成默认的状态–各个寄存器复位时的值
HAL_StatusTypeDef	HAL_PWM_Start(PWM_HandleTypeDef *hpwm, uint32_t Channel);
//开始输出波形
HAL_StatusTypeDef	HAL_PWM_Stop(PWM_HandleTypeDef *hpwm, uint32_t Channel);
//停止输出波形
HAL_StatusTypeDef	HAL_PWM_Duty_Set(PWM_HandleTypeDef *hpwm, uint32_t Channel, uint32_t Duty);
//设置输出波形的占空比
HAL_StatusTypeDef	HAL_PWM_Freq_Set(PWM_HandleTypeDef *hpwm, uint32_t Channel, uint32_t Prescaler, uint32_t Period);
//设置输出波形的频率

参数

结构体和枚举类型

typedef struct
{
	uint32_t Prescaler;			/* Specifies the prescaler value used to divide the PWM clock(40MHz).
									This parameter can be a number between Min_Data = 0x0000 and Max_Data = 0xFFFF */
	
	uint32_t CounterMode;		/* Specifies the counter mode.
									This parameter can be a value of @ref PWM_Counter_Mode */
								   
	uint32_t Period;			/* Specifies the period value to be loaded into the PERIOD
									Register at the next update event.
									This parameter can be a number between Min_Data = 0x00 and Max_Data = 0xFF.  */
								   
	uint32_t Pulse;				/* Specifies the pulse value to be loaded into the Compare Register.
									This parameter can be a number between Min_Data = 0x00 and Max_Data = 0xFF */
							   
	uint32_t AutoReloadPreload;	/* Specifies the auto-reload preload.
                                   This parameter can be a value of @ref TIM_AutoReloadPreload */
								   
	uint32_t OutMode;			/* Specifies the output mode.
								   This parameter can be a value of @ref PWM_Out_Mode*/
	
	uint32_t OutInverse;		/* Specifies the output polarity.
								   This parameter can be a value of @ref PWM_Out_Inverse */
	
	uint32_t Dtdiv;				/* Specifies the prescaler value used to divide the dead zone clock(40MHz) when in complementary mode.
								   This parameter can be a value of @ref PWM_DT_DIV */
	
	uint32_t Dtcnt;				/* Specifies the number of dead time clocks when in complementary mode.
								   This parameter can be a number between Min_Data = 0x00 and Max_Data = 0xFF */
								   
} PWM_InitTypeDef;

typedef struct
{
	PWM_TypeDef			*Instance;
	
	PWM_InitTypeDef		Init;
	
	uint32_t			Channel; /* This parameter can be a value of @ref PWM_Channel */
	
} PWM_HandleTypeDef;

宏参数

#define PWM		((PWM_TypeDef *)PWM_BASE)

// PWM_Channel
#define PWM_CHANNEL_0	0x00
#define PWM_CHANNEL_1	0x01
#define PWM_CHANNEL_2	0x02
#define PWM_CHANNEL_3	0x03
#define PWM_CHANNEL_4	0x04
#define PWM_CHANNEL_ALL	0x01F

// PWM_Counter_Mode
#define PWM_COUNTERMODE_EDGEALIGNED_UP					0x0	// edge-aligned up mode for capture
#define PWM_COUNTERMODE_EDGEALIGNED_DOWN				0x1	// edge-aligned up mode for out
#define PWM_COUNTERMODE_CENTERALIGNED					0x2 // center-aligned mode for out

// PWM_AutoReloadPreload
#define PWM_AUTORELOAD_PRELOAD_DISABLE                	0x00               // TIMx_ARR register is not buffered
#define PWM_AUTORELOAD_PRELOAD_ENABLE                 	0x01              // TIMx_ARR register is buffered

// PWM_Out_Mode
#define PWM_OUT_MODE_INDEPENDENT						0x00
#define PWM_OUT_MODE_2SYNC								0x01
#define PWM_OUT_MODE_2COMPLEMENTARY						0x02
#define PWM_OUT_MODE_5SYNC								0x03
#define PWM_OUT_MODE_BREAK								0x04

// PWM_Out_Inverse
#define PWM_OUT_INVERSE_DISABLE							0x00
#define PWM_OUT_INVERSE_ENABLE							0x01

// PWM_DT_DIV
#define PWM_DTDIV_NONE									PWM_DTCR_DTDIV_1
#define PWM_DTDIV_2										PWM_DTCR_DTDIV_2
#define PWM_DTDIV_4										PWM_DTCR_DTDIV_4
#define PWM_DTDIV_8										PWM_DTCR_DTDIV_8

#define IS_PWM_INSTANCE(INSTANCE)	(((INSTANCE) == PWM))

#define IS_PWM_CHANNELS(__CHANNEL__)       (((__CHANNEL__) == PWM_CHANNEL_0) || \
                                            ((__CHANNEL__) == PWM_CHANNEL_1) || \
                                            ((__CHANNEL__) == PWM_CHANNEL_2) || \
                                            ((__CHANNEL__) == PWM_CHANNEL_3) || \
                                            ((__CHANNEL__) == PWM_CHANNEL_4) || \
                                            ((__CHANNEL__) == PWM_CHANNEL_ALL))

#define IS_PWM_PRESCALER(__PRESCALER__) (((__PRESCALER__) >= 0x0000) && ((__PRESCALER__) <= 0x0FFFF))

#define IS_PWM_COUNTER_MODE(__MODE__)      (((__MODE__) == PWM_COUNTERMODE_EDGEALIGNED_UP)              || \
                                            ((__MODE__) == PWM_COUNTERMODE_EDGEALIGNED_DOWN)            || \
                                            ((__MODE__) == PWM_COUNTERMODE_CENTERALIGNED))

#define IS_PWM_PERIOD(__PERIOD__)	(((__PERIOD__) >= 0x00) && ((__PERIOD__) <= 0x0FF))

#define IS_PWM_PULSE(__PULSE__)	(((__PULSE__) >= 0x00) && ((__PULSE__) <= 0x0FF))

#define IS_PWM_AUTORELOADPRELOAD(__AUTORELOAD__) (((__AUTORELOAD__) == PWM_AUTORELOAD_PRELOAD_DISABLE) || \
												  ((__AUTORELOAD__) == PWM_AUTORELOAD_PRELOAD_ENABLE))

#define IS_PWM_OUTMODE(__MODE__) (((__MODE__) == PWM_OUT_MODE_INDEPENDENT) || \
								  ((__MODE__) == PWM_OUT_MODE_2SYNC) || \
								  ((__MODE__) == PWM_OUT_MODE_2COMPLEMENTARY) || \
								  ((__MODE__) == PWM_OUT_MODE_5SYNC))

#define IS_PWM_OUTINVERSE(__INVERSE__) (((__INVERSE__) == PWM_OUT_INVERSE_DISABLE) || \
									    ((__INVERSE__) == PWM_OUT_INVERSE_ENABLE))

#define IS_PWM_DTDIV(__DIV__) (((__DIV__) == PWM_DTDIV_NONE) || \
							   ((__DIV__) == PWM_DTDIV_2) || \
							   ((__DIV__) == PWM_DTDIV_4) || \
							   ((__DIV__) == PWM_DTDIV_8))

#define IS_PWM_DTCNT(__CNT__) (((__CNT__) >= 0) && ((__CNT__) <= 0x0FF))

测试程序

独立模式

main.c


#include <stdio.h>
#include "wm_hal.h"

PWM_HandleTypeDef hpwm;

static void PWM_Init(void);
void Error_Handler(void);

uint32_t ch = PWM_CHANNEL_1;
int main(void)
{
	int i = 0;
	
	SystemClock_Config(CPU_CLK_160M);
	printf("enter main\r\n");
	
	PWM_Init();
	HAL_PWM_Start(&hpwm, ch);
	
	while (1)
	{
		for (i = 0; i < 200; i++)
		{
			HAL_PWM_Duty_Set(&hpwm, ch, i);
			HAL_Delay(20);
		}
		for (i = 200 - 1; i >= 0; i--)
		{
			HAL_PWM_Duty_Set(&hpwm, ch, i);
			HAL_Delay(20);
		}
	}
}

/* 输出波形的频率: f = 40MHz / Prescaler / (Period + 1);
 * 输出波形的占空比: 
 *     沿对齐模式(递减):(Pulse + 1) / (Period + 1)
 *                         Pulse >= Period:PWM输出一直为高电平
 *                         Pulse < Period :PWM输出高电平宽度为(Pulse + 1),低电平宽度为(Period - Pulse)
 *                         Pulse = 0      :PWM输出高电平宽度为(1),低电平宽度为(Period)
 * 
 *    中间对齐模式       :(2 * Pulse + 1) / (2 * (Period + 1))
 *                         Pulse > Period :PWM输出一直为高电平
 *                         Pulse <= Period:PWM输出高电平宽度为(2 * Pulse + 1),低电平宽度为(2 * (Period - Pulse) + 1)
 *                         Pulse = 0      :PWM输出高电平宽度为(1),低电平宽度为(2 * Period + 1)
 */
static void PWM_Init(void)
{
	// 输出50Hz、占空比25%的波形
	hpwm.Instance = PWM;
	hpwm.Init.AutoReloadPreload = PWM_AUTORELOAD_PRELOAD_ENABLE;
	hpwm.Init.CounterMode = PWM_COUNTERMODE_EDGEALIGNED_DOWN;
	hpwm.Init.Prescaler = 4000;	//0~65535
	hpwm.Init.Period = 200 - 1;	//0~255 40MHz / 4000 / 200 = 50Hz (默认PWM时钟为40MHz)
	hpwm.Init.Pulse = 200 / 4 - 1;	//0~255 25% DUTY
	hpwm.Init.OutMode = PWM_OUT_MODE_INDEPENDENT;
	hpwm.Channel = ch;
	
	HAL_PWM_Init(&hpwm);
}

void Error_Handler(void)
{
	while (1)
	{
	}
}

void assert_failed(uint8_t *file, uint32_t line)
{
	printf("Wrong parameters value: file %s on line %d\r\n", file, line);
}

wm_hal_msp.c

       配置引脚复用。

#include "wm_hal.h"

void HAL_MspInit(void)
{

}

void HAL_PWM_MspInit(PWM_HandleTypeDef *hpwm)
{
	__HAL_RCC_PWM_CLK_ENABLE();
	__HAL_AFIO_REMAP_PWM1(GPIOB, GPIO_PIN_1);
}

void HAL_PWM_MspDeInit(PWM_HandleTypeDef *hpwm)
{
	__HAL_RCC_PWM_CLK_DISABLE();
	HAL_GPIO_DeInit(GPIOB, GPIO_PIN_1);
}

wm_it.c


#include "wm_hal.h"

#define readl(addr) ({unsigned int __v = (*(volatile unsigned int *) (addr)); __v;})
__attribute__((isr)) void CORET_IRQHandler(void)
{
	readl(0xE000E010);
	HAL_IncTick();
}

实验现象

       可见输出的PWM信号为50Hz,占空比在0~100%间变化。
在这里插入图片描述

多通道同步模式

需要注意的是
配置占空比的函数是没有关于PWM_CHANNEL_ALL的实现的:
在这里插入图片描述

要用PWM_CHANNEL_0才能跑出来

main.c


#include <stdio.h>
#include "wm_hal.h"

PWM_HandleTypeDef hpwm;

static void PWM_Init(void);
static void GPIO_Init(void);
void Error_Handler(void);

uint32_t ch = PWM_CHANNEL_0;

int main(void)
{
	int i = 0;
	
	SystemClock_Config(CPU_CLK_160M);
	printf("enter main\r\n");
	
	GPIO_Init();
	PWM_Init();
	HAL_PWM_Start(&hpwm, ch);
	
	while (1)
	{
		for (i = 0; i < 200; i++)
		{
			HAL_PWM_Duty_Set(&hpwm, ch, i);
			HAL_Delay(20);
		}
		for (i = 200 - 1; i >= 0; i--)
		{
			HAL_PWM_Duty_Set(&hpwm, ch, i);
			HAL_Delay(20);
		}
	}
}

static void GPIO_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStruct = {0};
	
	__HAL_RCC_GPIO_CLK_ENABLE();

	GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_16;
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_16, GPIO_PIN_SET);
}

/* 输出波形的频率: f = 40MHz / Prescaler / (Period + 1);
 * 输出波形的占空比: 
 *     沿对齐模式(递减):(Pulse + 1) / (Period + 1)
 *                         Pulse >= Period:PWM输出一直为高电平
 *                         Pulse < Period :PWM输出高电平宽度为(Pulse + 1),低电平宽度为(Period - Pulse)
 *                         Pulse = 0      :PWM输出高电平宽度为(1),低电平宽度为(Period)
 * 
 *    中间对齐模式       :(2 * Pulse + 1) / (2 * (Period + 1))
 *                         Pulse > Period :PWM输出一直为高电平
 *                         Pulse <= Period:PWM输出高电平宽度为(2 * Pulse + 1),低电平宽度为(2 * (Period - Pulse) + 1)
 *                         Pulse = 0      :PWM输出高电平宽度为(1),低电平宽度为(2 * Period + 1)
 */
static void PWM_Init(void)
{
	// 输出50Hz、占空比25%的波形
	hpwm.Instance = PWM;
	hpwm.Init.AutoReloadPreload = PWM_AUTORELOAD_PRELOAD_ENABLE;
	hpwm.Init.CounterMode = PWM_COUNTERMODE_EDGEALIGNED_DOWN;
	hpwm.Init.Prescaler = 4000;	//0~65535
	hpwm.Init.Period = 200 - 1;	//0~255 40MHz / 4000 / 200 = 50Hz (默认PWM时钟为40MHz)
	hpwm.Init.Pulse = 200 / 4 - 1;	//0~255 25% DUTY
	hpwm.Init.OutMode = PWM_OUT_MODE_5SYNC;
	hpwm.Channel = ch;
	
	HAL_PWM_Init(&hpwm);
}

void Error_Handler(void)
{
	while (1)
	{
	}
}

void assert_failed(uint8_t *file, uint32_t line)
{
	printf("Wrong parameters value: file %s on line %d\r\n", file, line);
}

wm_hal_msp.c

#include "wm_hal.h"

void HAL_MspInit(void)
{

}

void HAL_PWM_MspInit(PWM_HandleTypeDef *hpwm)
{
	__HAL_RCC_PWM_CLK_ENABLE();
	__HAL_AFIO_REMAP_PWM0(GPIOB, GPIO_PIN_0);
	__HAL_AFIO_REMAP_PWM1(GPIOB, GPIO_PIN_1);
	__HAL_AFIO_REMAP_PWM2(GPIOB, GPIO_PIN_2);
	__HAL_AFIO_REMAP_PWM3(GPIOB, GPIO_PIN_3);
	__HAL_AFIO_REMAP_PWM4(GPIOB, GPIO_PIN_16);
}

void HAL_PWM_MspDeInit(PWM_HandleTypeDef *hpwm)
{
	__HAL_RCC_PWM_CLK_DISABLE();
	HAL_GPIO_DeInit(GPIOB, GPIO_PIN_0);
	HAL_GPIO_DeInit(GPIOB, GPIO_PIN_1);
	HAL_GPIO_DeInit(GPIOB, GPIO_PIN_2);
	HAL_GPIO_DeInit(GPIOB, GPIO_PIN_3);
	HAL_GPIO_DeInit(GPIOB, GPIO_PIN_16);
}


wm_it.c


#include "wm_hal.h"

#define readl(addr) ({unsigned int __v = (*(volatile unsigned int *) (addr)); __v;})
__attribute__((isr)) void CORET_IRQHandler(void)
{
	readl(0xE000E010);
	HAL_IncTick();
}

实验现象

可见3个LED都实现了类似呼吸灯的效果
在这里插入图片描述

版权声明:本文为CSDN博主「乙酸氧铍」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_44457994/article/details/122597641

Windows 10 20H2
HLK-W806-V1.0-KIT
WM_SDK_W806_v0.6.0


       摘自《W806 芯片设计指导书 V1.0》、《W806 MCU 芯片规格书 V2.0》

PWM 控制器

       5 通道 PWM 信号生成功能
       2 通道输入信号捕获功能(PWM0 和 PWM4 两个通路)
       频率范围:3Hz~160KHz
       占空比最大精度:1/256,插入死区的计数器宽度:8bit
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

库函数

函数

       打开wm_pwm.h,有如下的函数声明:

HAL_StatusTypeDef	HAL_PWM_Init(PWM_HandleTypeDef *hpwm);
//初始化PWM通道
HAL_StatusTypeDef	HAL_PWM_DeInit(PWM_HandleTypeDef *hpwm);
//将初始化之后的通道恢复成默认的状态–各个寄存器复位时的值
void				HAL_PWM_MspInit(PWM_HandleTypeDef *hpwm);
//用于开启对应的时钟和复用对应引脚
void				HAL_PWM_MspDeInit(PWM_HandleTypeDef *hpwm);
//将对应时钟和引脚恢复成默认的状态–各个寄存器复位时的值
HAL_StatusTypeDef	HAL_PWM_Start(PWM_HandleTypeDef *hpwm, uint32_t Channel);
//开始输出波形
HAL_StatusTypeDef	HAL_PWM_Stop(PWM_HandleTypeDef *hpwm, uint32_t Channel);
//停止输出波形
HAL_StatusTypeDef	HAL_PWM_Duty_Set(PWM_HandleTypeDef *hpwm, uint32_t Channel, uint32_t Duty);
//设置输出波形的占空比
HAL_StatusTypeDef	HAL_PWM_Freq_Set(PWM_HandleTypeDef *hpwm, uint32_t Channel, uint32_t Prescaler, uint32_t Period);
//设置输出波形的频率

参数

结构体和枚举类型

typedef struct
{
	uint32_t Prescaler;			/* Specifies the prescaler value used to divide the PWM clock(40MHz).
									This parameter can be a number between Min_Data = 0x0000 and Max_Data = 0xFFFF */
	
	uint32_t CounterMode;		/* Specifies the counter mode.
									This parameter can be a value of @ref PWM_Counter_Mode */
								   
	uint32_t Period;			/* Specifies the period value to be loaded into the PERIOD
									Register at the next update event.
									This parameter can be a number between Min_Data = 0x00 and Max_Data = 0xFF.  */
								   
	uint32_t Pulse;				/* Specifies the pulse value to be loaded into the Compare Register.
									This parameter can be a number between Min_Data = 0x00 and Max_Data = 0xFF */
							   
	uint32_t AutoReloadPreload;	/* Specifies the auto-reload preload.
                                   This parameter can be a value of @ref TIM_AutoReloadPreload */
								   
	uint32_t OutMode;			/* Specifies the output mode.
								   This parameter can be a value of @ref PWM_Out_Mode*/
	
	uint32_t OutInverse;		/* Specifies the output polarity.
								   This parameter can be a value of @ref PWM_Out_Inverse */
	
	uint32_t Dtdiv;				/* Specifies the prescaler value used to divide the dead zone clock(40MHz) when in complementary mode.
								   This parameter can be a value of @ref PWM_DT_DIV */
	
	uint32_t Dtcnt;				/* Specifies the number of dead time clocks when in complementary mode.
								   This parameter can be a number between Min_Data = 0x00 and Max_Data = 0xFF */
								   
} PWM_InitTypeDef;

typedef struct
{
	PWM_TypeDef			*Instance;
	
	PWM_InitTypeDef		Init;
	
	uint32_t			Channel; /* This parameter can be a value of @ref PWM_Channel */
	
} PWM_HandleTypeDef;

宏参数

#define PWM		((PWM_TypeDef *)PWM_BASE)

// PWM_Channel
#define PWM_CHANNEL_0	0x00
#define PWM_CHANNEL_1	0x01
#define PWM_CHANNEL_2	0x02
#define PWM_CHANNEL_3	0x03
#define PWM_CHANNEL_4	0x04
#define PWM_CHANNEL_ALL	0x01F

// PWM_Counter_Mode
#define PWM_COUNTERMODE_EDGEALIGNED_UP					0x0	// edge-aligned up mode for capture
#define PWM_COUNTERMODE_EDGEALIGNED_DOWN				0x1	// edge-aligned up mode for out
#define PWM_COUNTERMODE_CENTERALIGNED					0x2 // center-aligned mode for out

// PWM_AutoReloadPreload
#define PWM_AUTORELOAD_PRELOAD_DISABLE                	0x00               // TIMx_ARR register is not buffered
#define PWM_AUTORELOAD_PRELOAD_ENABLE                 	0x01              // TIMx_ARR register is buffered

// PWM_Out_Mode
#define PWM_OUT_MODE_INDEPENDENT						0x00
#define PWM_OUT_MODE_2SYNC								0x01
#define PWM_OUT_MODE_2COMPLEMENTARY						0x02
#define PWM_OUT_MODE_5SYNC								0x03
#define PWM_OUT_MODE_BREAK								0x04

// PWM_Out_Inverse
#define PWM_OUT_INVERSE_DISABLE							0x00
#define PWM_OUT_INVERSE_ENABLE							0x01

// PWM_DT_DIV
#define PWM_DTDIV_NONE									PWM_DTCR_DTDIV_1
#define PWM_DTDIV_2										PWM_DTCR_DTDIV_2
#define PWM_DTDIV_4										PWM_DTCR_DTDIV_4
#define PWM_DTDIV_8										PWM_DTCR_DTDIV_8

#define IS_PWM_INSTANCE(INSTANCE)	(((INSTANCE) == PWM))

#define IS_PWM_CHANNELS(__CHANNEL__)       (((__CHANNEL__) == PWM_CHANNEL_0) || \
                                            ((__CHANNEL__) == PWM_CHANNEL_1) || \
                                            ((__CHANNEL__) == PWM_CHANNEL_2) || \
                                            ((__CHANNEL__) == PWM_CHANNEL_3) || \
                                            ((__CHANNEL__) == PWM_CHANNEL_4) || \
                                            ((__CHANNEL__) == PWM_CHANNEL_ALL))

#define IS_PWM_PRESCALER(__PRESCALER__) (((__PRESCALER__) >= 0x0000) && ((__PRESCALER__) <= 0x0FFFF))

#define IS_PWM_COUNTER_MODE(__MODE__)      (((__MODE__) == PWM_COUNTERMODE_EDGEALIGNED_UP)              || \
                                            ((__MODE__) == PWM_COUNTERMODE_EDGEALIGNED_DOWN)            || \
                                            ((__MODE__) == PWM_COUNTERMODE_CENTERALIGNED))

#define IS_PWM_PERIOD(__PERIOD__)	(((__PERIOD__) >= 0x00) && ((__PERIOD__) <= 0x0FF))

#define IS_PWM_PULSE(__PULSE__)	(((__PULSE__) >= 0x00) && ((__PULSE__) <= 0x0FF))

#define IS_PWM_AUTORELOADPRELOAD(__AUTORELOAD__) (((__AUTORELOAD__) == PWM_AUTORELOAD_PRELOAD_DISABLE) || \
												  ((__AUTORELOAD__) == PWM_AUTORELOAD_PRELOAD_ENABLE))

#define IS_PWM_OUTMODE(__MODE__) (((__MODE__) == PWM_OUT_MODE_INDEPENDENT) || \
								  ((__MODE__) == PWM_OUT_MODE_2SYNC) || \
								  ((__MODE__) == PWM_OUT_MODE_2COMPLEMENTARY) || \
								  ((__MODE__) == PWM_OUT_MODE_5SYNC))

#define IS_PWM_OUTINVERSE(__INVERSE__) (((__INVERSE__) == PWM_OUT_INVERSE_DISABLE) || \
									    ((__INVERSE__) == PWM_OUT_INVERSE_ENABLE))

#define IS_PWM_DTDIV(__DIV__) (((__DIV__) == PWM_DTDIV_NONE) || \
							   ((__DIV__) == PWM_DTDIV_2) || \
							   ((__DIV__) == PWM_DTDIV_4) || \
							   ((__DIV__) == PWM_DTDIV_8))

#define IS_PWM_DTCNT(__CNT__) (((__CNT__) >= 0) && ((__CNT__) <= 0x0FF))

测试程序

独立模式

main.c


#include <stdio.h>
#include "wm_hal.h"

PWM_HandleTypeDef hpwm;

static void PWM_Init(void);
void Error_Handler(void);

uint32_t ch = PWM_CHANNEL_1;
int main(void)
{
	int i = 0;
	
	SystemClock_Config(CPU_CLK_160M);
	printf("enter main\r\n");
	
	PWM_Init();
	HAL_PWM_Start(&hpwm, ch);
	
	while (1)
	{
		for (i = 0; i < 200; i++)
		{
			HAL_PWM_Duty_Set(&hpwm, ch, i);
			HAL_Delay(20);
		}
		for (i = 200 - 1; i >= 0; i--)
		{
			HAL_PWM_Duty_Set(&hpwm, ch, i);
			HAL_Delay(20);
		}
	}
}

/* 输出波形的频率: f = 40MHz / Prescaler / (Period + 1);
 * 输出波形的占空比: 
 *     沿对齐模式(递减):(Pulse + 1) / (Period + 1)
 *                         Pulse >= Period:PWM输出一直为高电平
 *                         Pulse < Period :PWM输出高电平宽度为(Pulse + 1),低电平宽度为(Period - Pulse)
 *                         Pulse = 0      :PWM输出高电平宽度为(1),低电平宽度为(Period)
 * 
 *    中间对齐模式       :(2 * Pulse + 1) / (2 * (Period + 1))
 *                         Pulse > Period :PWM输出一直为高电平
 *                         Pulse <= Period:PWM输出高电平宽度为(2 * Pulse + 1),低电平宽度为(2 * (Period - Pulse) + 1)
 *                         Pulse = 0      :PWM输出高电平宽度为(1),低电平宽度为(2 * Period + 1)
 */
static void PWM_Init(void)
{
	// 输出50Hz、占空比25%的波形
	hpwm.Instance = PWM;
	hpwm.Init.AutoReloadPreload = PWM_AUTORELOAD_PRELOAD_ENABLE;
	hpwm.Init.CounterMode = PWM_COUNTERMODE_EDGEALIGNED_DOWN;
	hpwm.Init.Prescaler = 4000;	//0~65535
	hpwm.Init.Period = 200 - 1;	//0~255 40MHz / 4000 / 200 = 50Hz (默认PWM时钟为40MHz)
	hpwm.Init.Pulse = 200 / 4 - 1;	//0~255 25% DUTY
	hpwm.Init.OutMode = PWM_OUT_MODE_INDEPENDENT;
	hpwm.Channel = ch;
	
	HAL_PWM_Init(&hpwm);
}

void Error_Handler(void)
{
	while (1)
	{
	}
}

void assert_failed(uint8_t *file, uint32_t line)
{
	printf("Wrong parameters value: file %s on line %d\r\n", file, line);
}

wm_hal_msp.c

       配置引脚复用。

#include "wm_hal.h"

void HAL_MspInit(void)
{

}

void HAL_PWM_MspInit(PWM_HandleTypeDef *hpwm)
{
	__HAL_RCC_PWM_CLK_ENABLE();
	__HAL_AFIO_REMAP_PWM1(GPIOB, GPIO_PIN_1);
}

void HAL_PWM_MspDeInit(PWM_HandleTypeDef *hpwm)
{
	__HAL_RCC_PWM_CLK_DISABLE();
	HAL_GPIO_DeInit(GPIOB, GPIO_PIN_1);
}

wm_it.c


#include "wm_hal.h"

#define readl(addr) ({unsigned int __v = (*(volatile unsigned int *) (addr)); __v;})
__attribute__((isr)) void CORET_IRQHandler(void)
{
	readl(0xE000E010);
	HAL_IncTick();
}

实验现象

       可见输出的PWM信号为50Hz,占空比在0~100%间变化。
在这里插入图片描述

多通道同步模式

需要注意的是
配置占空比的函数是没有关于PWM_CHANNEL_ALL的实现的:
在这里插入图片描述

要用PWM_CHANNEL_0才能跑出来

main.c


#include <stdio.h>
#include "wm_hal.h"

PWM_HandleTypeDef hpwm;

static void PWM_Init(void);
static void GPIO_Init(void);
void Error_Handler(void);

uint32_t ch = PWM_CHANNEL_0;

int main(void)
{
	int i = 0;
	
	SystemClock_Config(CPU_CLK_160M);
	printf("enter main\r\n");
	
	GPIO_Init();
	PWM_Init();
	HAL_PWM_Start(&hpwm, ch);
	
	while (1)
	{
		for (i = 0; i < 200; i++)
		{
			HAL_PWM_Duty_Set(&hpwm, ch, i);
			HAL_Delay(20);
		}
		for (i = 200 - 1; i >= 0; i--)
		{
			HAL_PWM_Duty_Set(&hpwm, ch, i);
			HAL_Delay(20);
		}
	}
}

static void GPIO_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStruct = {0};
	
	__HAL_RCC_GPIO_CLK_ENABLE();

	GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_16;
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_16, GPIO_PIN_SET);
}

/* 输出波形的频率: f = 40MHz / Prescaler / (Period + 1);
 * 输出波形的占空比: 
 *     沿对齐模式(递减):(Pulse + 1) / (Period + 1)
 *                         Pulse >= Period:PWM输出一直为高电平
 *                         Pulse < Period :PWM输出高电平宽度为(Pulse + 1),低电平宽度为(Period - Pulse)
 *                         Pulse = 0      :PWM输出高电平宽度为(1),低电平宽度为(Period)
 * 
 *    中间对齐模式       :(2 * Pulse + 1) / (2 * (Period + 1))
 *                         Pulse > Period :PWM输出一直为高电平
 *                         Pulse <= Period:PWM输出高电平宽度为(2 * Pulse + 1),低电平宽度为(2 * (Period - Pulse) + 1)
 *                         Pulse = 0      :PWM输出高电平宽度为(1),低电平宽度为(2 * Period + 1)
 */
static void PWM_Init(void)
{
	// 输出50Hz、占空比25%的波形
	hpwm.Instance = PWM;
	hpwm.Init.AutoReloadPreload = PWM_AUTORELOAD_PRELOAD_ENABLE;
	hpwm.Init.CounterMode = PWM_COUNTERMODE_EDGEALIGNED_DOWN;
	hpwm.Init.Prescaler = 4000;	//0~65535
	hpwm.Init.Period = 200 - 1;	//0~255 40MHz / 4000 / 200 = 50Hz (默认PWM时钟为40MHz)
	hpwm.Init.Pulse = 200 / 4 - 1;	//0~255 25% DUTY
	hpwm.Init.OutMode = PWM_OUT_MODE_5SYNC;
	hpwm.Channel = ch;
	
	HAL_PWM_Init(&hpwm);
}

void Error_Handler(void)
{
	while (1)
	{
	}
}

void assert_failed(uint8_t *file, uint32_t line)
{
	printf("Wrong parameters value: file %s on line %d\r\n", file, line);
}

wm_hal_msp.c

#include "wm_hal.h"

void HAL_MspInit(void)
{

}

void HAL_PWM_MspInit(PWM_HandleTypeDef *hpwm)
{
	__HAL_RCC_PWM_CLK_ENABLE();
	__HAL_AFIO_REMAP_PWM0(GPIOB, GPIO_PIN_0);
	__HAL_AFIO_REMAP_PWM1(GPIOB, GPIO_PIN_1);
	__HAL_AFIO_REMAP_PWM2(GPIOB, GPIO_PIN_2);
	__HAL_AFIO_REMAP_PWM3(GPIOB, GPIO_PIN_3);
	__HAL_AFIO_REMAP_PWM4(GPIOB, GPIO_PIN_16);
}

void HAL_PWM_MspDeInit(PWM_HandleTypeDef *hpwm)
{
	__HAL_RCC_PWM_CLK_DISABLE();
	HAL_GPIO_DeInit(GPIOB, GPIO_PIN_0);
	HAL_GPIO_DeInit(GPIOB, GPIO_PIN_1);
	HAL_GPIO_DeInit(GPIOB, GPIO_PIN_2);
	HAL_GPIO_DeInit(GPIOB, GPIO_PIN_3);
	HAL_GPIO_DeInit(GPIOB, GPIO_PIN_16);
}


wm_it.c


#include "wm_hal.h"

#define readl(addr) ({unsigned int __v = (*(volatile unsigned int *) (addr)); __v;})
__attribute__((isr)) void CORET_IRQHandler(void)
{
	readl(0xE000E010);
	HAL_IncTick();
}

实验现象

可见3个LED都实现了类似呼吸灯的效果
在这里插入图片描述

版权声明:本文为CSDN博主「乙酸氧铍」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_44457994/article/details/122597641

生成海报
点赞 0

乙酸氧铍

我还没有学会写个人说明!

暂无评论

相关推荐

X-bot

X-bot 前言 这个项目是我在稚辉君的视频里面看见的,是一个完全开源的项目,而且对他来说是一个比较简单的项目,但对于我这种没有什么DIY经验的同学来说,还是有点难的,不过