实验要求:
通过定时器8通道1实现指定个数PWM输出,用于控制LED1的亮灭
1,确定PWM波的周期/频率,2Hz为例,PSC=7199,ARR=4999
Tout= ((arr+1)*(psc+1))/Tclk= ((4999+1)*(7199+1))/72000000=0.5s
2,配置输出比较模式为:PWM模式1
通道输出极性为:高电平有效
占空比:50%
硬件知识:
由原理图可知 定时器8通道1 连接在PC6,LED1连接在PE5上,所以要在开发板上用杜邦线将PC6和PE5引脚连接起来。
配置步骤:
1,配置定时器基础工作参数
HAL_TIM_PWM_Init()
2,定时器PWM输出MSP初始化
HAL_TIM_PWM_MspInit() 配置NVIC、CLOCK、GPIO等
3,配置PWM模式/比较值等
HAL_TIM_PWM_ConfigChannel()
4,设置优先级,使能中断
HAL_NVIC_SetPriority()、 HAL_NVIC_EnableIRQ()
5,使能定时器更新中断
__HAL_TIM_ENABLE_IT()
6,使能输出、主输出、计数器
HAL_TIM_PWM_Start()
7,编写中断服务函数
TIMx_IRQHandler()等 HAL_TIM_IRQHandler()
8,编写更新中断回调函数
HAL_TIM_PeriodElapsedCallback()
源码
atim.c
#include "./BSP/TIMER/atim.h"
TIM_HandleTypeDef g_timx_npwm_chy_handle; //定时器8句柄
static uint8_t g_npwm_remain = 0;
//高级定时器TIMX 通道Y 输出指定个数PWM 初始化函数
void atim_timx_npwm_chy_init(uint16_t psc, uint16_t arr)
{
TIM_OC_InitTypeDef timx_oc_npwm_chy = {0};
g_timx_npwm_chy_handle.Instance = TIM8; //定时器8
g_timx_npwm_chy_handle.Init.Prescaler = psc; //定时器分频
g_timx_npwm_chy_handle.Init.Period = arr; //自动重装载值
g_timx_npwm_chy_handle.Init.CounterMode = TIM_COUNTERMODE_UP;//递增计数模式
g_timx_npwm_chy_handle.Init.RepetitionCounter = 0; //重复计数器初始值
HAL_TIM_PWM_Init(&g_timx_npwm_chy_handle);
timx_oc_npwm_chy.OCMode = TIM_OCMODE_PWM1; //模式选择PWM1
timx_oc_npwm_chy.OCPolarity = TIM_OCPOLARITY_HIGH; //输出比较极性为高
timx_oc_npwm_chy.Pulse = arr / 2; //设置比较值
//设置为arr的一半得到占空比为50%
HAL_TIM_PWM_ConfigChannel(&g_timx_npwm_chy_handle, &timx_oc_npwm_chy, TIM_CHANNEL_1);
__HAL_TIM_ENABLE_IT(&g_timx_npwm_chy_handle, TIM_IT_UPDATE); //使能定时器更新中断
HAL_TIM_PWM_Start(&g_timx_npwm_chy_handle, TIM_CHANNEL_1);
}
//定时器 PWM输出 MSP初始化函数
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM8)
{
GPIO_InitTypeDef gpio_init_struct;
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_TIM8_CLK_ENABLE();
gpio_init_struct.Pin = GPIO_PIN_6;
gpio_init_struct.Mode = GPIO_MODE_AF_PP; /* 推挽式复用 */
gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */
gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* 高速 */
HAL_GPIO_Init(GPIOC, &gpio_init_struct);
HAL_NVIC_SetPriority(TIM8_UP_IRQn, 1, 3);
HAL_NVIC_EnableIRQ(TIM8_UP_IRQn);
}
}
//高级定时器TIMX NPWM设置PWM个数函数
void atim_timx_npwm_chy_set(uint8_t npwm)
{
if(npwm == 0)
{
return ;
}
else
{
g_npwm_remain = npwm;
HAL_TIM_GenerateEvent(&g_timx_npwm_chy_handle, TIM_EVENTSOURCE_UPDATE);//软件的更新事件
__HAL_TIM_ENABLE(&g_timx_npwm_chy_handle); //使能定时器更新中断
}
}
//定时器8中断服务函数
void TIM8_UP_IRQHandler(void)
{
HAL_TIM_IRQHandler(&g_timx_npwm_chy_handle);
}
//定时器更新中断回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM8)
{
if(g_npwm_remain)
{
TIM8->RCR = g_npwm_remain - 1;
HAL_TIM_GenerateEvent(&g_timx_npwm_chy_handle, TIM_EVENTSOURCE_UPDATE);//软件的更新事件
__HAL_TIM_ENABLE(&g_timx_npwm_chy_handle); //使能定时器更新中断
g_npwm_remain = 0;
}
else
{
TIM8->CR1 &= ~(1 << 0); //关闭计数器
}
}
}
atim.h
#ifndef __TIMER_H
#define __TIMER_H
#include "./SYSTEM/sys/sys.h"
void atim_timx_npwm_chy_set(uint8_t npwm);
void atim_timx_npwm_chy_init(uint16_t psc, uint16_t arr);
#endif
main.c
#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/delay/delay.h"
#include "./SYSTEM/usart/usart.h"
#include "./BSP/LED/led.h"
#include "./BSP/KEY/key.h"
#include "./BSP/TIMER/atim.h"
int main(void)
{
uint8_t key;
uint8_t t = 0;
HAL_Init(); /* 初始化HAL库 */
sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟,72M */
delay_init(72); /* 初始化延时函数 */
led_init(); /* 初始化LED */
key_init();
usart_init(115200);
atim_timx_npwm_chy_init(7200 - 1, 5000 - 1);
atim_timx_npwm_chy_set(5);
//把PE5设置为输入,避免与PC6冲突
GPIO_InitTypeDef gpio_init_struct;
__HAL_RCC_GPIOE_CLK_ENABLE(); /* LED0时钟使能 */
gpio_init_struct.Pin = GPIO_PIN_5; /* LED0引脚 */
gpio_init_struct.Mode = GPIO_MODE_INPUT; /* 推挽输出 */
gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */
gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* 高速 */
HAL_GPIO_Init(GPIOE, &gpio_init_struct); /* 初始化LED0引脚 */
while(1)
{
key = key_scan(0);
if(key == KEY0_PRES)
{
atim_timx_npwm_chy_set(3);
}
t++;
delay_ms(10);
if(t > 50)
{
t = 0;
LED0_TOGGLE();
}
}
}