STM32 F103系列高级定时器的HAL库应用
高级定时器输出比较模式实验
高级定时器输出比较模式实验原理
实验要求:
通过定时器8通道1/2/3/4输出相位分别为25%、50%、75%、100%的PWM
1,确定PWM波的周期/频率 1KHz为例,PSC=71,ARR=999
2,配置输出比较模式为:翻转
通道输出极性为:高电平有效
定时器8通道1/2/3/4分别在PC6/7/8/9引脚上
配置步骤:
1,配置定时器基础工作参数
HAL_TIM_OC_Init()
2,定时器输出比较MSP初始化
HAL_TIM_OC_MspInit() 配置NVIC、CLOCK、GPIO等
3,配置输出比较模式等
HAL_TIM_OC_ConfigChannel()
4,使能通道预装载
__HAL_TIM_ENABLE_OCxPRELOAD()
5,使能输出、主输出、计数器
HAL_TIM_OC_Start()
6,修改捕获/比较寄存器的值
__HAL_TIM_SET_COMPARE()
源码
atim.c
#include "./BSP/TIMER/atim.h"
//定时器句柄
TIM_HandleTypeDef g_timx_comp_pwm_handle;
//高级定时器 输出比较模式 初始化函数
void atim_timx_comp_pwm_init(uint16_t arr, uint16_t psc)
{
TIM_OC_InitTypeDef timx_oc_comp_pwm = {0};
g_timx_comp_pwm_handle.Instance = TIM8;
g_timx_comp_pwm_handle.Init.CounterMode = TIM_COUNTERMODE_UP; //递增计数模式
g_timx_comp_pwm_handle.Init.Prescaler = psc; //定时器分频
g_timx_comp_pwm_handle.Init.Period = arr; //自动重装载值
HAL_TIM_OC_Init(&g_timx_comp_pwm_handle);
timx_oc_comp_pwm.OCMode = TIM_OCMODE_TOGGLE;
timx_oc_comp_pwm.OCPolarity = TIM_OCPOLARITY_HIGH;
HAL_TIM_OC_ConfigChannel(&g_timx_comp_pwm_handle, &timx_oc_comp_pwm, TIM_CHANNEL_1);
HAL_TIM_OC_ConfigChannel(&g_timx_comp_pwm_handle, &timx_oc_comp_pwm, TIM_CHANNEL_2);
HAL_TIM_OC_ConfigChannel(&g_timx_comp_pwm_handle, &timx_oc_comp_pwm, TIM_CHANNEL_3);
HAL_TIM_OC_ConfigChannel(&g_timx_comp_pwm_handle, &timx_oc_comp_pwm, TIM_CHANNEL_4);
__HAL_TIM_ENABLE_OCxPRELOAD(&g_timx_comp_pwm_handle, TIM_CHANNEL_1);
__HAL_TIM_ENABLE_OCxPRELOAD(&g_timx_comp_pwm_handle, TIM_CHANNEL_2);
__HAL_TIM_ENABLE_OCxPRELOAD(&g_timx_comp_pwm_handle, TIM_CHANNEL_3);
__HAL_TIM_ENABLE_OCxPRELOAD(&g_timx_comp_pwm_handle, TIM_CHANNEL_4);
HAL_TIM_OC_Start(&g_timx_comp_pwm_handle, TIM_CHANNEL_1);
HAL_TIM_OC_Start(&g_timx_comp_pwm_handle, TIM_CHANNEL_2);
HAL_TIM_OC_Start(&g_timx_comp_pwm_handle, TIM_CHANNEL_3);
HAL_TIM_OC_Start(&g_timx_comp_pwm_handle, TIM_CHANNEL_4);
}
//定时器 输出比较 msp初始化函数
void HAL_TIM_OC_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; /* LED0引脚 */
gpio_init_struct.Mode = GPIO_MODE_AF_PP; /* 推挽式复用 */
gpio_init_struct.Pull = GPIO_NOPULL; /* 上拉 */
gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* 高速 */
HAL_GPIO_Init(GPIOC, &gpio_init_struct); /* 初始化LED0引脚 */
gpio_init_struct.Pin = GPIO_PIN_7;
HAL_GPIO_Init(GPIOC, &gpio_init_struct);
gpio_init_struct.Pin = GPIO_PIN_8;
HAL_GPIO_Init(GPIOC, &gpio_init_struct);
gpio_init_struct.Pin = GPIO_PIN_9;
HAL_GPIO_Init(GPIOC, &gpio_init_struct);
}
}
atim.h
#ifndef __TIMER_H
#define __TIMER_H
#include "./SYSTEM/sys/sys.h"
void atim_timx_comp_pwm_init(uint16_t arr, uint16_t psc);
#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/TIMER/atim.h"
extern TIM_HandleTypeDef g_timx_comp_pwm_handle;
int main(void)
{
uint8_t t = 0;
HAL_Init(); /* 初始化HAL库 */
sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟,72M */
delay_init(72); /* 初始化延时函数 */
led_init(); /* 初始化LED */
atim_timx_comp_pwm_init(1000 - 1, 72 - 1);
usart_init(115200);
__HAL_TIM_SET_COMPARE(&g_timx_comp_pwm_handle, TIM_CHANNEL_1, 250 - 1);
__HAL_TIM_SET_COMPARE(&g_timx_comp_pwm_handle, TIM_CHANNEL_2, 500 - 1);
__HAL_TIM_SET_COMPARE(&g_timx_comp_pwm_handle, TIM_CHANNEL_3, 750 - 1);
__HAL_TIM_SET_COMPARE(&g_timx_comp_pwm_handle, TIM_CHANNEL_4, 1000 - 1);
while(1)
{
delay_ms(10);
t++;
if(t >= 20)
{
LED0_TOGGLE();
t = 0;
}
}
}
高级定时器互补输出带死区控制实验
实验要求:
通过定时器1通道1输出频率为1KHz,占空比为70%的PWM,使用PWM模式1
使能互补输出并设置死区时间控制:设置DTG为100(5.56us),进行验证死区时间是否正确
使能刹车功能:刹车输入信号高电平有效,配置输出空闲状态等,最后用示波器验证
1,确定PWM波的周期/频率 1KHz为例,PSC=71,ARR=999
2,以4.5.2小节的H桥为例,配置通道输出极性以及互补输出极性
NPN型三极管高电平有效
死区实验计算
硬件知识了解
定时器1通道1映射在PE8引脚上,互补输出映射在PE9引脚上,刹车功能映射在PE15上
配置步骤:
1,配置定时器基础工作参数
HAL_TIM_PWM_Init()
2,定时器PWM输出MSP初始化
HAL_TIM_PWM_MspInit() 配置NVIC、CLOCK、GPIO等
3,配置PWM模式/比较值等
HAL_TIM_PWM_ConfigChannel()
4,配置刹车功能、死区时间等
HAL_TIMEx_ConfigBreakDeadTime()
5,使能输出、主输出、计数器
HAL_TIM_PWM_Start()
6,使能互补输出、主输出、计数器
HAL_TIMEx_PWMN_Start()
源码
atim.c
#include "./BSP/TIMER/atim.h"
TIM_HandleTypeDef g_timx_cplm_pwm_handle; /* 定时器x句柄 */
TIM_BreakDeadTimeConfigTypeDef g_sbreak_dead_time_config; /* 死区时间设置 */
/* 高级定时器 互补输出 初始化函数(使用PWM模式1) */
void atim_timx_cplm_pwm_init(uint16_t arr, uint16_t psc)
{
TIM_OC_InitTypeDef tim_oc_cplm_pwm = {0};
g_timx_cplm_pwm_handle.Instance = TIM1; /* 定时器x */
g_timx_cplm_pwm_handle.Init.Prescaler = psc; /* 定时器预分频系数 */
g_timx_cplm_pwm_handle.Init.CounterMode = TIM_COUNTERMODE_UP; /* 递增计数模式 */
g_timx_cplm_pwm_handle.Init.Period = arr; /* 自动重装载值 */
g_timx_cplm_pwm_handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV4; /* CKD[1:0] = 10, tDTS = 4 * tCK_INT = Ft / 4 = 18Mhz */
HAL_TIM_PWM_Init(&g_timx_cplm_pwm_handle);
tim_oc_cplm_pwm.OCMode = TIM_OCMODE_PWM1; /* PWM模式1 */
tim_oc_cplm_pwm.OCPolarity = TIM_OCPOLARITY_HIGH; /* OCy 高电平有效 */
tim_oc_cplm_pwm.OCNPolarity = TIM_OCNPOLARITY_HIGH; /* OCyN 高电平有效 */
tim_oc_cplm_pwm.OCIdleState = TIM_OCIDLESTATE_RESET; /* 当MOE=0,OCx=0 */
tim_oc_cplm_pwm.OCNIdleState = TIM_OCNIDLESTATE_RESET; /* 当MOE=0,OCxN=0 */
HAL_TIM_PWM_ConfigChannel(&g_timx_cplm_pwm_handle, &tim_oc_cplm_pwm, TIM_CHANNEL_1);
/* 设置死区参数,开启死区中断 */
g_sbreak_dead_time_config.OffStateRunMode = TIM_OSSR_DISABLE; /* 运行模式的关闭输出状态 */
g_sbreak_dead_time_config.OffStateIDLEMode = TIM_OSSI_DISABLE; /* 空闲模式的关闭输出状态 */
g_sbreak_dead_time_config.LockLevel = TIM_LOCKLEVEL_OFF; /* 不用寄存器锁功能 */
g_sbreak_dead_time_config.BreakState = TIM_BREAK_ENABLE; /* 使能刹车输入 */
g_sbreak_dead_time_config.BreakPolarity = TIM_BREAKPOLARITY_HIGH; /* 刹车输入有效信号极性为高 */
g_sbreak_dead_time_config.AutomaticOutput = TIM_AUTOMATICOUTPUT_ENABLE; /* 使能AOE位,允许刹车结束后自动恢复输出 */
HAL_TIMEx_ConfigBreakDeadTime(&g_timx_cplm_pwm_handle, &g_sbreak_dead_time_config);
HAL_TIM_PWM_Start(&g_timx_cplm_pwm_handle, TIM_CHANNEL_1); /* OCy 输出使能 */
HAL_TIMEx_PWMN_Start(&g_timx_cplm_pwm_handle,TIM_CHANNEL_1); /* OCyN 输出使能 */
}
/* 定时器 PWM输出 MSP初始化函数 */
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
{
if (htim->Instance == TIM1)
{
GPIO_InitTypeDef gpio_init_struct = {0};
__HAL_RCC_TIM1_CLK_ENABLE();
__HAL_RCC_GPIOE_CLK_ENABLE();
gpio_init_struct.Pin = GPIO_PIN_9;
gpio_init_struct.Mode = GPIO_MODE_AF_PP;
gpio_init_struct.Pull = GPIO_PULLDOWN;
gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH ;
HAL_GPIO_Init(GPIOE, &gpio_init_struct);
gpio_init_struct.Pin = GPIO_PIN_8;
HAL_GPIO_Init(GPIOE, &gpio_init_struct);
gpio_init_struct.Pin = GPIO_PIN_15;
HAL_GPIO_Init(GPIOE, &gpio_init_struct);
__HAL_RCC_AFIO_CLK_ENABLE();
__HAL_AFIO_REMAP_TIM1_ENABLE();
}
}
void atim_timx_cplm_pwm_set(uint16_t ccr, uint8_t dtg)
{
__HAL_TIM_SET_COMPARE(&g_timx_cplm_pwm_handle, TIM_CHANNEL_1, ccr); //修改捕获/比较寄存器的值
g_sbreak_dead_time_config.DeadTime = dtg;
HAL_TIMEx_ConfigBreakDeadTime(&g_timx_cplm_pwm_handle, &g_sbreak_dead_time_config);
}
atim.h
#ifndef __TIMER_H
#define __TIMER_H
#include "./SYSTEM/sys/sys.h"
void atim_timx_cplm_pwm_init(uint16_t arr, uint16_t psc);
void atim_timx_cplm_pwm_set(uint16_t ccr, uint8_t dtg);
#endif
main.c
#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/KEY/key.h"
#include "./BSP/TIMER/atim.h"
int main(void)
{
uint8_t t = 0;
HAL_Init(); /* 初始化HAL库 */
sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
delay_init(72); /* 延时初始化 */
usart_init(115200); /* 串口初始化为115200 */
led_init(); /* 初始化LED */
atim_timx_cplm_pwm_init(1000 - 1, 72 - 1);
atim_timx_cplm_pwm_set(700 - 1, 100);
while (1)
{
delay_ms(10);
t++;
if (t >= 20)
{
LED0_TOGGLE(); /* LED0(RED)闪烁 */
t = 0;
}
}
}
高级定时器PWM输入模式实验
实验要求:
通过定时器3通道2(PB5)输出PWM(这次试验需要用到通用定时器实验中的atim.c atim.h)
将PWM输入到定时器8通道1(PC6),测量PWM的频率/周期、占空比等信息
定时器8的采样时钟频率固定72MHz
72MHz采样频率( 精度约13.8ns ),PSC=0,ARR=65535
不考虑溢出情况下,测量的最长PWM周期为910.2us
PWM输入模式工作原理
PWM输入模式时序
配置步骤:
1,配置定时器基础工作参数
HAL_TIM_IC_Init()
2,定时器捕获输入MSP初始化
HAL_TIM_IC_MspInit() 配置NVIC、CLOCK、GPIO等
3,配置IC1/2映射、捕获边沿等
HAL_TIM_IC_ConfigChannel()
4,配置从模式,触发源等
HAL_TIM_SlaveConfigSynchro()
5,设置优先级,使能中断
HAL_NVIC_SetPriority()、 HAL_NVIC_EnableIRQ()
6,使能捕获、捕获中断及计数器
HAL_TIM_IC_Start_IT()、 HAL_TIM_IC_Start()
7,编写中断服务函数
TIMx_IRQHandler()等 HAL_TIM_IRQHandler()
8,编写输入捕获回调函数
HAL_TIM_IC_CaptureCallback()
源码
atim.c
#include "./BSP/TIMER/atim.h"
TIM_HandleTypeDef g_timx_pwmin_chy_handle; /* 定时器x句柄 */
/* PWM输入状态(g_timxchy_cap_sta)
* 0,没有成功捕获.
* 1,已经成功捕获了
*/
uint8_t g_timxchy_pwmin_sta = 0; /* PWM输入状态 */
uint16_t g_timxchy_pwmin_psc = 0; /* PWM输入分频系数 */
uint32_t g_timxchy_pwmin_hval = 0; /* PWM的高电平脉宽 */
uint32_t g_timxchy_pwmin_cval = 0; /* PWM的周期宽度 */
/* PWM输入模式 初始化函数,采样时钟频率为72Mhz,精度约13.8ns */
void atim_timx_pwmin_chy_init(void)
{
TIM_SlaveConfigTypeDef slave_config = {0};
TIM_IC_InitTypeDef tim_ic_pwmin_chy = {0};
g_timx_pwmin_chy_handle.Instance = TIM8; /* 定时器8 */
g_timx_pwmin_chy_handle.Init.Prescaler = 0; /* 定时器预分频系数 */
g_timx_pwmin_chy_handle.Init.CounterMode = TIM_COUNTERMODE_UP; /* 递增计数模式 */
g_timx_pwmin_chy_handle.Init.Period = 65535; /* 自动重装载值 */
HAL_TIM_IC_Init(&g_timx_pwmin_chy_handle);
/* 从模式配置,IT1触发更新 */
slave_config.SlaveMode = TIM_SLAVEMODE_RESET; /* 从模式:复位模式 */
slave_config.InputTrigger = TIM_TS_TI1FP1; /* 定时器输入触发源:TI1FP1 */
slave_config.TriggerPolarity = TIM_TRIGGERPOLARITY_RISING; /* 上升沿检测 */
slave_config.TriggerFilter = 0; /* 不滤波 */
HAL_TIM_SlaveConfigSynchro(&g_timx_pwmin_chy_handle, &slave_config);
/* IC1捕获:上升沿触发TI1FP1 */
tim_ic_pwmin_chy.ICPolarity = TIM_ICPOLARITY_RISING; /* 上升沿检测 */
tim_ic_pwmin_chy.ICSelection = TIM_ICSELECTION_DIRECTTI; /* 选择输入端IC1映射到TI1 */
tim_ic_pwmin_chy.ICPrescaler = TIM_ICPSC_DIV1; /* 不分频 */
tim_ic_pwmin_chy.ICFilter = 0; /* 不滤波 */
HAL_TIM_IC_ConfigChannel(&g_timx_pwmin_chy_handle, &tim_ic_pwmin_chy, TIM_CHANNEL_1);
/* IC2捕获:下降沿触发TI1FP2 */
tim_ic_pwmin_chy.ICPolarity = TIM_ICPOLARITY_FALLING; /* 下降沿检测 */
tim_ic_pwmin_chy.ICSelection = TIM_ICSELECTION_INDIRECTTI; /* 选择输入端IC2映射到TI1 */
HAL_TIM_IC_ConfigChannel(&g_timx_pwmin_chy_handle, &tim_ic_pwmin_chy, TIM_CHANNEL_2);
HAL_TIM_IC_Start_IT(&g_timx_pwmin_chy_handle, TIM_CHANNEL_1);
HAL_TIM_IC_Start(&g_timx_pwmin_chy_handle, TIM_CHANNEL_2);
}
/* 定时器 输入捕获 MSP初始化函数 */
void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM8)
{
GPIO_InitTypeDef gpio_init_struct = {0};
__HAL_RCC_TIM8_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
gpio_init_struct.Pin = GPIO_PIN_6;
gpio_init_struct.Mode = GPIO_MODE_AF_PP;
gpio_init_struct.Pull = GPIO_PULLDOWN;
gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOC, &gpio_init_struct);
/* TIM1/TIM8有独立的输入捕获中断服务函数 */
HAL_NVIC_SetPriority(TIM8_CC_IRQn, 1, 3);
HAL_NVIC_EnableIRQ(TIM8_CC_IRQn);
}
}
/* 定时器8 输入捕获 中断服务函数,仅TIM1/TIM8有这个函数,其他普通定时器没有这个中断服务函数! */
void TIM8_CC_IRQHandler(void)
{
HAL_TIM_IRQHandler(&g_timx_pwmin_chy_handle); /* 定时器共用处理函数 */
}
/* PWM输入模式 重新启动捕获 */
void atim_timx_pwmin_chy_restart(void)
{
sys_intx_disable(); /* 关闭中断 */
g_timxchy_pwmin_sta = 0; /* 清零状态,重新开始检测 */
g_timxchy_pwmin_hval=0;
g_timxchy_pwmin_cval=0;
sys_intx_enable(); /* 打开中断 */
}
/* 定时器输入捕获中断处理回调函数 */
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM8)
{
if(g_timxchy_pwmin_sta == 0)
{
if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
{
g_timxchy_pwmin_hval = HAL_TIM_ReadCapturedValue(&g_timx_pwmin_chy_handle, TIM_CHANNEL_2) + 1 + 1;
g_timxchy_pwmin_cval = HAL_TIM_ReadCapturedValue(&g_timx_pwmin_chy_handle, TIM_CHANNEL_1) + 1 + 1;
g_timxchy_pwmin_sta = 1;
}
}
}
}
atim.h
#ifndef __TIMER_H
#define __TIMER_H
#include "./SYSTEM/sys/sys.h"
void atim_timx_pwmin_chy_init(void);
void atim_timx_pwmin_chy_restart(void);
#endif
main.c
#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/TIMER/atim.h"
#include "./BSP/TIMER/gtim.h"
extern uint16_t g_timxchy_pwmin_sta; /* PWM输入状态 */
extern uint16_t g_timxchy_pwmin_psc; /* PWM输入分频系数 */
extern uint32_t g_timxchy_pwmin_hval; /* PWM的高电平脉宽 */
extern uint32_t g_timxchy_pwmin_cval; /* PWM的周期宽度 */
int main(void)
{
uint8_t t = 0;
double ht, ct, f, tpsc;
HAL_Init(); /* 初始化HAL库 */
sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
delay_init(72); /* 延时初始化 */
usart_init(115200); /* 串口初始化为115200 */
led_init(); /* 初始化LED */
gtim_timx_pwm_chy_init(10 - 1, 72 - 1);
TIM3->CCR2 = 3;
atim_timx_pwmin_chy_init();
while (1)
{
delay_ms(10);
t++;
if (t >= 20) /* 每200ms输出一次结果,并闪烁LED0,提示程序运行 */
{
if (g_timxchy_pwmin_sta) /* 捕获了一次数据 */
{
printf("\r\n"); /* 输出空,另起一行 */
printf("PWM PSC :%d\r\n", g_timxchy_pwmin_psc); /* 打印分频系数 */
printf("PWM Hight:%d\r\n", g_timxchy_pwmin_hval); /* 打印高电平脉宽 */
printf("PWM Cycle:%d\r\n", g_timxchy_pwmin_cval); /* 打印周期 */
tpsc = ((double)g_timxchy_pwmin_psc + 1) / 72; /* 得到PWM采样时钟周期时间 */
ht = g_timxchy_pwmin_hval * tpsc; /* 计算高电平时间 */
ct = g_timxchy_pwmin_cval * tpsc; /* 计算周期长度 */
f = (1 / ct) * 1000000; /* 计算频率 */
printf("PWM Hight time:%.3fus\r\n", ht); /* 打印高电平脉宽长度 */
printf("PWM Cycle time:%.3fus\r\n", ct); /* 打印周期时间长度 */
printf("PWM Frequency :%.3fHz\r\n", f); /* 打印频率 */
atim_timx_pwmin_chy_restart(); /* 重启PWM输入检测 */
}
LED1_TOGGLE(); /* LED1(GREEN)闪烁 */
t = 0;
}
}
}
作者:从糕手变成高手