1高级定时器输出比较模式实验
1.1高级定时器输出比较模式实验原理
1.2高级定时器输出比较模式实验实验配置步骤
1,配置定时器基础工作参数 HAL_TIM_OC_Init()
2,定时器PWM输出MSP初始化 HAL_TIM_OC_MspInit() 配置NVIC、CLOCK、GPIO等
3,配置PWM模式/比较值等 HAL_TIM_OC_ConfigChannel()
4,使能通道预装载 __HAL_TIM_ENABLE_OCxPRELOAD()
5,使能输出、主输出、计数器 HAL_TIM_OC_Start()
6,修改捕获/比较寄存器的值 _HAL_TIM_SET_COMPARE()
1.3 高级定时器输出比较模式实验要求
1)通过定时器8通道1/2/3/4输出相位分别为25%、50%、75%、100%的PWM
2,配置输出比较模式为:翻转
通道输出极性为:高电平有效
2 高级定时器互补输出带死区控制实验
2.1互补输出 死区时间
2.3带死区控制的互补输出应用H桥
2.4捕获/比较通道的输出部分(通道1至3)
2.5死区时间计算
2.6 刹车(断路)功能
TIMx_BKIN: IO复用口
BI由BRK(输入信号极性)故障事件决定
2.7高级定时器互补输出带死区控制实验配置步骤
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()
2.8刹车死区时间结构体
typedef struct
{
uint32_t OffStateRunMode; /* 运行模式下的关闭状态选择 /
uint32_t OffStateIDLEMode; / 空闲模式下的关闭状态选择 /
uint32_t LockLevel; / 寄存器锁定设置 /
uint32_t DeadTime; / 死区时间设置 /
uint32_t BreakState; / 是否使能刹车功能 /
uint32_t BreakPolarity; / 刹车输入极性 /
uint32_t BreakFilter; / 刹车输入滤波器(F1/F4系列没有) /
uint32_t AutomaticOutput; / 自动恢复输出使能,即使能AOE位 */
} TIM_BreakDeadTimeConfigTypeDef;
2.9 高级定时器输出比较模式实验要求
1)通过定时器1通道1输出频率为1KHz,占空比为70%的PWM,使用PWM模式1
使能互补输出并设置死区时间控制:设置DTG为100(5.56us),进行验证死区时间是否正确
使能刹车功能:刹车输入信号高电平有效,配置输出空闲状态等,最后用示波器验证
2)H桥为例,配置通道输出极性以及互补输出极性
高级定时器输入原理
3 高级定时器输入模式实战
3.1 高级定时器输入模式工作原理
3.2 高级定时器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()
3.3 关键结构体
typedef struct
{
uint32_t ICPolarity; /* 输入捕获触发方式选择,比如上升、下降沿捕获 /
uint32_t ICSelection; / 输入捕获选择,用于设置映射关系 /
uint32_t ICPrescaler; / 输入捕获分频系数 /
uint32_t ICFilter; / 输入捕获滤波器设置 */
} TIM_IC_InitTypeDef;
typedef struct
{
uint32_t SlaveMode; /* 从模式选择 /
uint32_t InputTrigger; / 输入触发源选择 /
uint32_t TriggerPolarity; / 输入触发极性 /
uint32_t TriggerPrescaler; / 输入触发预分频 /
uint32_t TriggerFilter; / 输入滤波器设置 */
} TIM_SlaveConfigTypeDef;
3.4 高级定时器PWM输入模式实验要求
通过定时器3通道2(PB5)输出PWM
将PWM输入到定时器8通道1(PC6),测量PWM的频率/周期、占空比等信息
2.1 atim.c
/*******************************以下是高级定时器输出比较模式实验程序**************************************/TIM_HandleTypeDef g_timx_comp_pwm_handle; /* 定时器x句柄 *//*** @brief 高级定时器TIMX 输出比较模式 初始化函数(使用输出比较模式)* @note* 配置高级定时器TIMX 4路输出比较模式PWM输出,实现50%占空比,不同相位控制* 注意,本例程输出比较模式,每2个计数周期才能完成一个PWM输出,因此输出频率减半* 另外,我们还可以开启中断在中断里面修改CCRx,从而实现不同频率/不同相位的控制* 但是我们不推荐这么使用,因为这可能导致非常频繁的中断,从而占用大量CPU资源** 高级定时器的时钟来自APB2, 而PCLK2 = 168Mhz, 我们设置PPRE2不分频, 因此* 高级定时器时钟 = 168Mhz* 定时器溢出时间计算方法: Tout = ((arr + 1) * (psc + 1)) / Ft us.* Ft=定时器工作频率,单位:Mhz** @param arr: 自动重装值。* @param psc: 预分频系数* @retval 无*///1.声明定时器句柄
TIM_HandleTypeDef g_timx_com_pwm_handler;
//2.配置通用定时器基本工作参数
void atim_timx_com_pwm_init(uint16_t arr, uint16_t psc)
{//4.1定时器输出比较定时器结构体初始化TIM_OC_InitTypeDef tim_oc_com_pwm = {0};//2.1通用定时器PWM输出初始化g_timx_com_pwm_handler.Instance = ATIM_TIMX_NPWM; //定时器xg_timx_com_pwm_handler.Init.Period = arr;g_timx_com_pwm_handler.Init.Prescaler = psc;g_timx_com_pwm_handler.Init.CounterMode = TIM_COUNTERMODE_UP;g_timx_com_pwm_handler.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; /* 使能TIMx_ARR进行缓冲 */HAL_TIM_OC_Init(&g_timx_com_pwm_handler);//5.输出比较配置包,括PWM模式和比较值tim_oc_com_pwm.OCMode = TIM_OCMODE_TOGGLE; //输出比较模式 PWM1tim_oc_com_pwm.Pulse = 250-1; //设置比较值为自动加载值的一般,则占空比为50%tim_oc_com_pwm.OCPolarity = TIM_OCPOLARITY_HIGH; //设置输出比较的极性为高HAL_TIM_PWM_ConfigChannel(&g_timx_com_pwm_handler,&tim_oc_com_pwm,TIM_CHANNEL_1); //初始化定时器的输出比较通道1__HAL_TIM_ENABLE_OCxPRELOAD(&g_timx_com_pwm_handler,TIM_CHANNEL_1); //通道1 预装载使能tim_oc_com_pwm.Pulse = 500-1; //设置比较值为自动加载值的一般,则占空比为50%HAL_TIM_PWM_ConfigChannel(&g_timx_com_pwm_handler,&tim_oc_com_pwm,TIM_CHANNEL_2); //初始化定时器的输出比较通道1__HAL_TIM_ENABLE_OCxPRELOAD(&g_timx_com_pwm_handler,TIM_CHANNEL_2); //通道1 预装载使能tim_oc_com_pwm.Pulse = 750-1; //设置比较值为自动加载值的一般,则占空比为50%HAL_TIM_PWM_ConfigChannel(&g_timx_com_pwm_handler,&tim_oc_com_pwm,TIM_CHANNEL_3); //初始化定时器的输出比较通道1__HAL_TIM_ENABLE_OCxPRELOAD(&g_timx_com_pwm_handler,TIM_CHANNEL_3); //通道1 预装载使能tim_oc_com_pwm.Pulse = 1000-1; //设置比较值为自动加载值的一般,则占空比为50%HAL_TIM_PWM_ConfigChannel(&g_timx_com_pwm_handler,&tim_oc_com_pwm,TIM_CHANNEL_4); //初始化定时器的输出比较通道1__HAL_TIM_ENABLE_OCxPRELOAD(&g_timx_com_pwm_handler,TIM_CHANNEL_4); //通道1 预装载使能//5,开启对应PWM通道使能输出并启动计时器HAL_TIM_OC_Start(&g_timx_com_pwm_handler,TIM_CHANNEL_1);HAL_TIM_OC_Start(&g_timx_com_pwm_handler,TIM_CHANNEL_2);HAL_TIM_OC_Start(&g_timx_com_pwm_handler,TIM_CHANNEL_3);HAL_TIM_OC_Start(&g_timx_com_pwm_handler,TIM_CHANNEL_4);
}//3.定时器PWM输出底层初始化,定时器时钟、引脚时钟使能,引脚复用配置
void HAL_TIM_OC_MspInit(TIM_HandleTypeDef * htm)
{//3.1判断是否是TIM14if(htm->Instance == ATIM_TIMX_NPWM){GPIO_InitTypeDef gpio_init_struct;//3.3使能PF引脚口时钟ATIM_TIMX_COMP_CH1_GPIO_CLK_ENABLE();ATIM_TIMX_COMP_CH2_GPIO_CLK_ENABLE();ATIM_TIMX_COMP_CH3_GPIO_CLK_ENABLE();ATIM_TIMX_COMP_CH4_GPIO_CLK_ENABLE();//3.4使能定时器时钟ATIM_TIMX_COMP_CLK_ENABLE();//3.2通道y的GPIO初始化gpio_init_struct.Pin = ATIM_TIMX_COMP_CH1_GPIO_PIN; /* 通道1 GPIO口 */gpio_init_struct.Mode = GPIO_MODE_AF_PP; /* 复用推挽输出 */gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* 高速 */ gpio_init_struct.Alternate =ATIM_TIMX_NPWM_CHY_GPIO_AF; /* 端口复用到TIM8 */ HAL_GPIO_Init(ATIM_TIMX_COMP_CH1_GPIO_PORT, &gpio_init_struct); gpio_init_struct.Pin = ATIM_TIMX_COMP_CH2_GPIO_PIN; /* 通道2 GPIO口 */HAL_GPIO_Init(ATIM_TIMX_COMP_CH2_GPIO_PORT, &gpio_init_struct); gpio_init_struct.Pin = ATIM_TIMX_COMP_CH3_GPIO_PIN; /* 通道3 GPIO口 */HAL_GPIO_Init(ATIM_TIMX_COMP_CH3_GPIO_PORT, &gpio_init_struct); gpio_init_struct.Pin = ATIM_TIMX_COMP_CH4_GPIO_PIN; /* 通道4 GPIO口 */HAL_GPIO_Init(ATIM_TIMX_COMP_CH4_GPIO_PORT, &gpio_init_struct); }
}/*******************************以下是高级定时器互补输出带死区时间控制实验程序**************************************///1.定义句柄、定义死区时间
TIM_HandleTypeDef g_timx_cplm_pwm_handler; /* 定时器x句柄 */
TIM_BreakDeadTimeConfigTypeDef g_break_dead_time_config ={0};
/*** @brief 高级定时器TIMX 互补输出 初始化函数(使用PWM模式1)* @note* 配置高级定时器TIMX 互补输出, 一路OCy 一路OCyN, 并且可以设置死区时间** 高级定时器的时钟来自APB2, 而PCLK2 = 168Mhz, 我们设置PPRE2不分频, 因此* 高级定时器时钟 = 168Mhz* 定时器溢出时间计算方法: Tout = ((arr + 1) * (psc + 1)) / Ft us.* Ft=定时器工作频率, 单位 : Mhz** @param arr: 自动重装值。* @param psc: 预分频系数* @retval 无*/
//2,配置定时器基础工作参数
void atim_timx_cplm_pwm_init(uint16_t arr, uint16_t psc)
{//3.1GPIO结构体初始化GPIO_InitTypeDef gpio_init_struct = {0};//3.2定时器时钟使能、通道对应IO口时钟使能ATIM_TIMX_CPLM_CHY_CLK_ENABLE(); /* TIMx 时钟使能 */ATIM_TIMX_CPLM_CHY_GPIO_CLK_ENABLE(); /* 通道X对应IO口时钟使能 */ATIM_TIMX_CPLM_CHYN_GPIO_CLK_ENABLE(); /* 通道X互补通道对应IO口时钟使能 */ATIM_TIMX_CPLM_BKIN_GPIO_CLK_ENABLE(); /* 通道X刹车输入对应IO口时钟使能 *///4.1定时器输出结构体初始化TIM_OC_InitTypeDef tim_oc_cplm_pwm = {0};//2.1通用定时器PWM输出初始化g_timx_cplm_pwm_handler.Instance = ATIM_TIMX_CPLM; //定时器xg_timx_cplm_pwm_handler.Init.Period = arr;g_timx_cplm_pwm_handler.Init.Prescaler = psc;g_timx_cplm_pwm_handler.Init.CounterMode = TIM_COUNTERMODE_UP;g_timx_cplm_pwm_handler.Init.ClockDivision = TIM_CLOCKDIVISION_DIV4; //CKD[1:0]= 10,tDTS =4 * tCK_INT =Ft/4 =42Mhzg_timx_cplm_pwm_handler.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; /* 使能影子寄存器TIMx_ARR进行缓冲 */HAL_TIM_OC_Init(&g_timx_com_pwm_handler);//3 PE8/PE9/PE15引脚复用设置以及通道对应IO时钟使能与时钟使能gpio_init_struct.Pin = ATIM_TIMX_CPLM_BKIN_GPIO_PIN; /*刹车输入引脚*/ gpio_init_struct.Mode = GPIO_MODE_AF_PP; /* 复用推挽输出 */ gpio_init_struct.Pull = GPIO_PULLDOWN; /* 上拉 */gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* 高速 */gpio_init_struct.Alternate =ATIM_TIMX_CPLM_CHY_GPIO_AF; /* 端口复用到TIM1 */ HAL_GPIO_Init(ATIM_TIMX_CPLM_BKIN_GPIO_PORT, &gpio_init_struct);gpio_init_struct.Pin = ATIM_TIMX_CPLM_CHY_GPIO_PIN; /*输出通道引脚*/ HAL_GPIO_Init(ATIM_TIMX_CPLM_CHY_GPIO_PORT, &gpio_init_struct);gpio_init_struct.Pin = ATIM_TIMX_CPLM_CHYN_GPIO_PIN; /*互补通道引脚*/ HAL_GPIO_Init(ATIM_TIMX_CPLM_CHYN_GPIO_PORT, &gpio_init_struct);//4.配置PWM模式/比较值等tim_oc_cplm_pwm.OCMode = TIM_OCMODE_PWM1; //输出比较模式 PWM1tim_oc_cplm_pwm.OCPolarity = TIM_OCPOLARITY_HIGH; //OCy高电平有效tim_oc_cplm_pwm.OCNPolarity = TIM_OCPOLARITY_HIGH; //OCy高电平有效tim_oc_cplm_pwm.OCIdleState = TIM_OCIDLESTATE_SET; //当前MOE = 0,OCx=0tim_oc_cplm_pwm.OCNIdleState = TIM_OCIDLESTATE_SET; //当前MOE = 0,OCxN=0HAL_TIM_PWM_ConfigChannel(&g_timx_com_pwm_handler,&tim_oc_cplm_pwm,ATIM_TIMX_CPLM_CHY); //初始化定时器的输出比较通道1//5.配置刹车功能、死区参数,开启死区中断g_break_dead_time_config.OffStateRunMode = TIM_OSSR_DISABLE; //运行模式关闭输出状态g_break_dead_time_config.OffStateIDLEMode = TIM_OSSI_DISABLE; //空闲模式关闭输出状态g_break_dead_time_config.LockLevel = TIM_LOCKLEVEL_OFF; //不用寄存器锁功能g_break_dead_time_config.BreakState = TIM_BREAK_ENABLE; //使能刹车输入g_break_dead_time_config.BreakPolarity = TIM_BREAKPOLARITY_HIGH; //刹车输入有效信号为高g_break_dead_time_config.AutomaticOutput = TIM_AUTOMATICOUTPUT_ENABLE;//使能AOE位,允许刹车结束后自动恢复输出 HAL_TIMEx_ConfigBreakDeadTime(&g_timx_com_pwm_handler,&g_break_dead_time_config); //初始化刹车死区时间//6,开启对应PWM通道使能输出并启动计时器HAL_TIM_PWM_Start(&g_timx_com_pwm_handler,TIM_CHANNEL_1); //OCy 输出使能HAL_TIMEx_PWMN_Start(&g_timx_com_pwm_handler,TIM_CHANNEL_1); //OCyN 输出使能
}
/*** @brief 定时器TIMX 设置输出比较值 & 死区时间* @param ccr: 输出比较值* @param dtg: 死区时间* @arg dtg[7:5]=0xx时, 死区时间 = dtg[7:0] * tDTS* @arg dtg[7:5]=10x时, 死区时间 = (64 + dtg[6:0]) * 2 * tDTS* @arg dtg[7:5]=110时, 死区时间 = (32 + dtg[5:0]) * 8 * tDTS* @arg dtg[7:5]=111时, 死区时间 = (32 + dtg[5:0]) * 16 * tDTS* @note tDTS = 1 / (Ft / CKD[1:0]) = 1 / 42M = 23.8ns* @retval 无*///7 设置输出比较值与死区时间
void atim_timx_cplm_pwm_set(uint16_t ccr, uint8_t dtg)
{g_break_dead_time_config.DeadTime = dtg;HAL_TIMEx_ConfigBreakDeadTime(&g_timx_com_pwm_handler,&g_break_dead_time_config); //重设死区时间__HAL_TIM_MOE_ENABLE(&g_timx_com_pwm_handler); //MOE等于1,使能主输出ATIM_TIMX_CPLM_CHY_CCRX = ccr; //设置比较寄存器
}/*******************************高级定时器PWM输入模式程序**************************************/TIM_HandleTypeDef g_timx_pwmin_chy_handler; /* 定时器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的周期宽度 *//*** @brief 定时器TIMX 通道Y PWM输入模式 初始化函数* @note* 高级定时器的时钟来自APB2, 而PCLK2 = 168Mhz, 我们设置PPRE2不分频, 因此* 高级定时器时钟 = 168Mhz* 定时器溢出时间计算方法: Tout = ((arr + 1) * (psc + 1)) / Ft us.* Ft=定时器工作频率,单位:Mhz** @param 无* @retval 无*///2,配置定时器基础工作参数
void atim_timx_pwmin_chy_init(void) /* 高级定时器 PWM输入模式初始化 */
{//3.1GPIO结构体初始化GPIO_InitTypeDef gpio_init_struct = {0};//从模式初始化配置TIM_SlaveConfigTypeDef slave_config = {0};//4.1输入初始化配置TIM_IC_InitTypeDef tim_ic_pwmin_chy = {0};//3.2定时器时钟使能、通道对应IO口时钟使能ATIM_TIMX_PWMIN_CHY_GPIO_CLK_ENABLE(); /* IO口时钟使能 */ATIM_TIMX_PWMIN_CHY_CLK_ENABLE(); /* TIM8 时钟使能 *///2.1通用定时器PWM输出初始化g_timx_pwmin_chy_handler.Instance = ATIM_TIMX_PWMIN; //定时器8g_timx_pwmin_chy_handler.Init.Period = 65535;g_timx_pwmin_chy_handler.Init.Prescaler = 0;g_timx_pwmin_chy_handler.Init.CounterMode = TIM_COUNTERMODE_UP;HAL_TIM_IC_Init(&g_timx_pwmin_chy_handler);//3 PC6引脚复用设置以及通道对应IO时钟使能与时钟使能gpio_init_struct.Pin = ATIM_TIMX_PWMIN_CHY_GPIO_PIN; /*输出引脚*/ gpio_init_struct.Mode = GPIO_MODE_AF_PP; /* 复用推挽输出 */ gpio_init_struct.Pull = GPIO_PULLDOWN; /* 上拉 */gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* 高速 */gpio_init_struct.Alternate =ATIM_TIMX_PWMIN_CHY_GPIO_AF; /* 端口复用到TIM8 */ HAL_GPIO_Init(ATIM_TIMX_PWMIN_CHY_GPIO_PORT, &gpio_init_struct);/* 从模式配置,IT1触发更新 */slave_config.SlaveMode = TIM_SLAVEMODE_RESET; /* 从模式:复位模式 *///4.IC1捕获:上升沿触发TI1FP1tim_ic_pwmin_chy.ICPolarity = TIM_ICPOLARITY_RISING; //上升沿检测tim_ic_pwmin_chy.ICSelection = TIM_ICSELECTION_DIRECTTI; //选择输入端IC1映射到TI1tim_ic_pwmin_chy.ICPrescaler = TIM_ICPSC_DIV1; //不分频tim_ic_pwmin_chy.ICFilter = 0; //选择输入端IC1映射到TI1HAL_TIM_IC_ConfigChannel(&g_timx_pwmin_chy_handler, &tim_ic_pwmin_chy, ATIM_TIMX_PWMIN_CHY);//5.IC2捕获:上升沿触发TI1FP2tim_ic_pwmin_chy.ICPolarity = TIM_ICPOLARITY_FALLING; //上升沿检测tim_ic_pwmin_chy.ICSelection = TIM_ICSELECTION_INDIRECTTI; //选择输入端IC2映射到TI1HAL_TIM_IC_ConfigChannel(&g_timx_pwmin_chy_handler, &tim_ic_pwmin_chy, TIM_CHANNEL_2);HAL_NVIC_SetPriority(ATIM_TIMX_PWMIN_IRQn, 1, 3); /* 设置中断优先级,抢占优先级1,子优先级3 */HAL_NVIC_EnableIRQ( ATIM_TIMX_PWMIN_IRQn ); /* 开启TIMx中断 *//* TIM1/TIM8有独立的输入捕获中断服务函数 */if ( ATIM_TIMX_PWMIN == TIM1 || ATIM_TIMX_PWMIN == TIM8){HAL_NVIC_SetPriority(ATIM_TIMX_PWMIN_CC_IRQn, 1, 3); /* 设置中断优先级,抢占优先级1,子优先级3 */HAL_NVIC_EnableIRQ(ATIM_TIMX_PWMIN_CC_IRQn); /* 开启TIMx中断 */}//6,开启对应PWM通道使能输入并启动计时器__HAL_TIM_ENABLE_IT(&g_timx_pwmin_chy_handler, TIM_IT_UPDATE);HAL_TIM_IC_Start_IT(&g_timx_pwmin_chy_handler, TIM_CHANNEL_1);HAL_TIM_IC_Start_IT(&g_timx_pwmin_chy_handler, TIM_CHANNEL_2);
}
//7重启PWM输入模式
void atim_timx_pwmin_chy_restart(void) /* 高级定时器 重启PWM输入模式检测 */
{//7.1 关闭中断sys_intx_disable(); //关闭中断//7.2状态和分频系数清零g_timxchy_pwmin_sta = 0; //清零状态g_timxchy_pwmin_psc = 0; //分频系数清零//7.2设置最大计数频率,得到最好的精度,计数器值清零__HAL_TIM_SET_PRESCALER(&g_timx_pwmin_chy_handler,0); //以最大的计数频率采集,以得到最好的精度 __HAL_TIM_SET_COUNTER(&g_timx_pwmin_chy_handler,0); //计数器清零//7.3 使能通道1捕获中断、使能溢出中断、使能定时器__HAL_TIM_ENABLE_IT(&g_timx_pwmin_chy_handler,TIM_IT_CC1); //使能通道1捕获中断__HAL_TIM_ENABLE_IT(&g_timx_pwmin_chy_handler,TIM_IT_UPDATE); //使能溢出中断__HAL_TIM_ENABLE(&g_timx_pwmin_chy_handler); //使能定时器//7.4清零捕获/比较中断标志、更新中断标志__HAL_TIM_CLEAR_FLAG(&g_timx_pwmin_chy_handler,TIM_FLAG_CC1); //清零捕获/比较1中断标志__HAL_TIM_CLEAR_FLAG(&g_timx_pwmin_chy_handler,TIM_FLAG_CC2); //清零捕获/比较2中断标志__HAL_TIM_CLEAR_FLAG(&g_timx_pwmin_chy_handler,TIM_FLAG_UPDATE);//清零更新中断标志//7.5打开中断sys_intx_enable();}/*** @brief 定时器TIMX 通道Y PWM输入模式 中断处理函数* @note* 因为TIM1/TIM8等有多个中断服务函数,而TIM2~5/TIM12/TIM15等普通定时器只有1个中断服务* 函数,为了更好的兼容,我们对中断处理统一放到atim_timx_pwin_chy_process函数里面进行处理** @param 无* @retval 无*/
//10 统一中断处理函数
static void atim_timx_pwmin_chy_process(void)
{//10.1启动入口检测static uint8_t sflag = 0;//10.2 检测PWM输入状态if(g_timxchy_pwmin_sta) //若已输入{//分屏系数清零,清零捕获/比较标志,清零更新中断标志,计数器清零g_timxchy_pwmin_psc = 0;__HAL_TIM_CLEAR_FLAG(&g_timx_pwmin_chy_handler, TIM_FLAG_CC1); /* 清零捕获/比较1中断标志 */__HAL_TIM_CLEAR_FLAG(&g_timx_pwmin_chy_handler, TIM_FLAG_CC2); /* 清零捕获/比较2中断标志 */__HAL_TIM_CLEAR_FLAG(&g_timx_pwmin_chy_handler, TIM_FLAG_UPDATE); /* 清零更新中断标志 */__HAL_TIM_SET_COUNTER(&g_timx_pwmin_chy_handler, 0); /* 计数器清零 */return;}//10.3检测是否发生溢出中断if(__HAL_TIM_GET_FLAG(&g_timx_pwmin_chy_handler,TIM_FLAG_UPDATE)) //若发生溢出中断{//清除溢出中断标志__HAL_TIM_CLEAR_FLAG(&g_timx_pwmin_chy_handler, TIM_FLAG_UPDATE); /* 清零溢出中断标志 *///检测是否发生周期性捕获中断if(__HAL_TIM_GET_FLAG(&g_timx_pwmin_chy_handler,TIM_FLAG_CC1)== 0) //若没有发生周期性捕获中断,且捕获未完成{//PWM输入检测标志置0sflag= 0;if(g_timxchy_pwmin_psc == 0) //从0到1{g_timxchy_pwmin_psc++;}else{if(g_timxchy_pwmin_psc == 65535) /* 已经最大了,可能是无输入状态 */{g_timxchy_pwmin_psc = 0; /* 重新恢复不分频 */} else if (g_timxchy_pwmin_psc > 32767) /* 不能倍增了 */{g_timxchy_pwmin_psc = 65535; /* 直接等于最大分频系数 */}else{g_timxchy_pwmin_psc += g_timxchy_pwmin_psc; /* 倍增 */} }__HAL_TIM_SET_PRESCALER(&g_timx_pwmin_chy_handler, g_timxchy_pwmin_psc); /* 设置定时器预分频系数 */__HAL_TIM_SET_COUNTER(&g_timx_pwmin_chy_handler, 0); /* 计数器清零 */__HAL_TIM_CLEAR_FLAG(&g_timx_pwmin_chy_handler, TIM_FLAG_CC1); /* 清零捕获/比较1中断标志 */__HAL_TIM_CLEAR_FLAG(&g_timx_pwmin_chy_handler, TIM_FLAG_CC2); /* 清零捕获/比较2中断标志 */__HAL_TIM_CLEAR_FLAG(&g_timx_pwmin_chy_handler, TIM_FLAG_UPDATE); /* 清零更新中断标志 */return ;}}//10.4检测到是采集到更新捕获中断if(sflag == 0) //第一次采集到更新捕获中断{if (__HAL_TIM_GET_FLAG(&g_timx_pwmin_chy_handler, TIM_FLAG_CC1)) /* 检测到了第一次周期捕获中断 */{ sflag = 1; /* 标记第一次周期已经捕获, 第二次周期捕获可以开始了 */}__HAL_TIM_CLEAR_FLAG(&g_timx_pwmin_chy_handler, TIM_FLAG_CC1); /* 清零捕获/比较1中断标志 */__HAL_TIM_CLEAR_FLAG(&g_timx_pwmin_chy_handler, TIM_FLAG_CC2); /* 清零捕获/比较2中断标志 */__HAL_TIM_CLEAR_FLAG(&g_timx_pwmin_chy_handler, TIM_FLAG_UPDATE); /* 清零更新中断标志 */return;}//10.5 如果还没有成功捕获if(g_timxchy_pwmin_sta == 0){if (__HAL_TIM_GET_FLAG(&g_timx_pwmin_chy_handler, TIM_FLAG_CC1)) /* 检测到了周期捕获中断 */{ g_timxchy_pwmin_hval = HAL_TIM_ReadCapturedValue(&g_timx_pwmin_chy_handler, TIM_CHANNEL_2) + 1; /* PWM的高电平脉宽捕获值 */g_timxchy_pwmin_cval = HAL_TIM_ReadCapturedValue(&g_timx_pwmin_chy_handler, TIM_CHANNEL_1) + 1; /* PWM的周期宽度捕获值 */if(g_timxchy_pwmin_hval<g_timxchy_pwmin_cval) //高电平款比小于周期性宽{g_timxchy_pwmin_sta =1; //标记捕获成功g_timxchy_pwmin_psc = ATIM_TIMX_PWMIN->PSC; //获取PWM输入分频系数if (g_timxchy_pwmin_psc == 0) /* 分频系数为0的时候, 修正读取数据 */{g_timxchy_pwmin_hval++; /* 修正系数为1, 加1 */g_timxchy_pwmin_cval++; /* 修正系数为1, 加1 */}sflag = 0;//每次捕获成功后停止捕获,避免频繁中断影响系统正常运行ATIM_TIMX_PWMIN->CR1 &= ~(1<< 0); //关闭定时器TIMX__HAL_TIM_DISABLE_IT(&g_timx_pwmin_chy_handler,TIM_IT_CC1); //失能通道1捕获中断__HAL_TIM_DISABLE_IT(&g_timx_pwmin_chy_handler,TIM_IT_CC2); //失能通道2捕获中断__HAL_TIM_DISABLE_IT(&g_timx_pwmin_chy_handler,TIM_IT_UPDATE); //使能溢出中断__HAL_TIM_CLEAR_FLAG(&g_timx_pwmin_chy_handler, TIM_FLAG_CC1); /* 清零捕获/比较1中断标志 */__HAL_TIM_CLEAR_FLAG(&g_timx_pwmin_chy_handler, TIM_FLAG_CC2); /* 清零捕获/比较2中断标志 */__HAL_TIM_CLEAR_FLAG(&g_timx_pwmin_chy_handler, TIM_FLAG_UPDATE); /* 清零更新中断标志 */}else{atim_timx_pwmin_chy_restart();}}}/* 清除捕获/比较1中断标志\捕获/比较2中断标志/更新中断标志 */__HAL_TIM_CLEAR_FLAG(&g_timx_pwmin_chy_handler, TIM_FLAG_CC1);__HAL_TIM_CLEAR_FLAG(&g_timx_pwmin_chy_handler, TIM_FLAG_CC2);__HAL_TIM_CLEAR_FLAG(&g_timx_pwmin_chy_handler, TIM_FLAG_UPDATE);
}
/*** @brief 定时器TIMX 更新/溢出 中断服务函数* @note TIM1/TIM8的这个函数仅用于更新/溢出中断服务,捕获在另外一个函数!* 其他普通定时器则更新/溢出/捕获,都在这个函数里面处理!* @param 无* @retval 无*/
//8.更新/溢出中断服务
void ATIM_TIMX_PWMIN_IRQHandler(void)
{atim_timx_pwmin_chy_process();
}
/*** @brief 定时器TIMX 输入捕获 中断服务函数* @note 仅TIM1/TIM8有这个函数,其他普通定时器没有这个中断服务函数!* @param 无* @retval 无*/
//9.捕获中断服务
void ATIM_TIMX_PWMIN_CC_IRQHandler(void)
{atim_timx_pwmin_chy_process();
}
2.2 atim.h
#ifndef __ATIM_H
#define __ATIM_H#include "./SYSTEM/sys/sys.h"/* TIMX 输出比较模式 定义 * 这里通过TIM8的输出比较模式,控制PC6,PC7,PC8,PC9输出4路PWM,占空比50%,并且每一路PWM之间的相位差为25%* 修改CCRx可以修改相位.* 默认是针对TIM8* 注意: 通过修改这些宏定义,可以支持TIM1/TIM8任意一个定时器,任意一个IO口使用输出比较模式,输出PWM*/
#define ATIM_TIMX_COMP_CH1_GPIO_PORT GPIOC
#define ATIM_TIMX_COMP_CH1_GPIO_PIN GPIO_PIN_6
#define ATIM_TIMX_COMP_CH1_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOC_CLK_ENABLE(); }while(0) /* PC口时钟使能 */#define ATIM_TIMX_COMP_CH2_GPIO_PORT GPIOC
#define ATIM_TIMX_COMP_CH2_GPIO_PIN GPIO_PIN_7
#define ATIM_TIMX_COMP_CH2_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOC_CLK_ENABLE(); }while(0) /* PC口时钟使能 */#define ATIM_TIMX_COMP_CH3_GPIO_PORT GPIOC
#define ATIM_TIMX_COMP_CH3_GPIO_PIN GPIO_PIN_8
#define ATIM_TIMX_COMP_CH3_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOC_CLK_ENABLE(); }while(0) /* PC口时钟使能 */#define ATIM_TIMX_COMP_CH4_GPIO_PORT GPIOC
#define ATIM_TIMX_COMP_CH4_GPIO_PIN GPIO_PIN_9
#define ATIM_TIMX_COMP_CH4_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOC_CLK_ENABLE(); }while(0) /* PC口时钟使能 */#define ATIM_TIMX_COMP TIM8
#define ATIM_TIMX_COMP_CH1_CCRX TIM8->CCR1 /* 通道1的输出比较寄存器 */
#define ATIM_TIMX_COMP_CH2_CCRX TIM8->CCR2 /* 通道1的输出比较寄存器 */
#define ATIM_TIMX_COMP_CH3_CCRX TIM8->CCR3 /* 通道1的输出比较寄存器 */
#define ATIM_TIMX_COMP_CH4_CCRX TIM8->CCR4 /* 通道1的输出比较寄存器 */
#define ATIM_TIMX_COMP_CLK_ENABLE() do{ __HAL_RCC_TIM8_CLK_ENABLE(); }while(0) /* TIM8 时钟使能 */void atim_timx_com_pwm_init(uint16_t arr, uint16_t psc); /* 高级定时器 输出比较模式输出PWM 初始化函数 *//* TIMX 互补输出模式 定义 * 这里设置互补输出相关硬件配置, CHY即正常输出, CHYN即互补输出* 修改CCRx可以修改占空比.* 默认是针对TIM1* 注意: 通过修改这些宏定义,可以支持TIM1/TIM8定时器, 任意一个IO口输出互补PWM(前提是必须有互补输出功能)*//* 输出通道引脚 */
#define ATIM_TIMX_CPLM_CHY_GPIO_PORT GPIOE
#define ATIM_TIMX_CPLM_CHY_GPIO_PIN GPIO_PIN_9
#define ATIM_TIMX_CPLM_CHY_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOE_CLK_ENABLE(); }while(0) /* PE口时钟使能 *//* 互补通道引脚 */
#define ATIM_TIMX_CPLM_CHYN_GPIO_PORT GPIOE
#define ATIM_TIMX_CPLM_CHYN_GPIO_PIN GPIO_PIN_8
#define ATIM_TIMX_CPLM_CHYN_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOE_CLK_ENABLE(); }while(0) /* PE口时钟使能 *//* 刹车输入引脚 */
#define ATIM_TIMX_CPLM_BKIN_GPIO_PORT GPIOE
#define ATIM_TIMX_CPLM_BKIN_GPIO_PIN GPIO_PIN_15
#define ATIM_TIMX_CPLM_BKIN_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOE_CLK_ENABLE(); }while(0) /* PE口时钟使能 *//* TIMX REMAP设置* 因为PE8/PE9/PE15, 默认并不是TIM1的复用功能脚, 必须开启完全重映射, 才可以将: TIM1_CH1->PE9; TIM1_CH1N->PE8; TIM1_BKIN->PE15;* 这样, PE8/PE9/PE15, 才能用作TIM1的CH1N/CH1/BKIN功能.* 因此, 必须实现ATIM_TIMX_CPLM_CHYN_GPIO_AF, * 如果我们使用默认的复用功能输出, 则不用设置重映射, 是可以不需要该函数的! 根据具体需要来实现.*/
#define ATIM_TIMX_CPLM_CHY_GPIO_AF GPIO_AF1_TIM1/*互补输出使用定时器*/
#define ATIM_TIMX_CPLM TIM1
#define ATIM_TIMX_CPLM_CHY TIM_CHANNEL_1 /* 通道Y, 1<= Y <=4 */
#define ATIM_TIMX_CPLM_CHY_CCRX ATIM_TIMX_CPLM->CCR1 /* 通道Y的输出比较寄存器 */
#define ATIM_TIMX_CPLM_CHY_CLK_ENABLE() do{ __HAL_RCC_TIM1_CLK_ENABLE(); }while(0) /* TIM1 时钟使能 */void atim_timx_cplm_pwm_init(uint16_t arr, uint16_t psc); /* 高级定时器 互补输出 初始化函数 */
void atim_timx_cplm_pwm_set(uint16_t ccr, uint8_t dtg); /* 高级定时器 互补输出 设置比较值、死区时间 *//* TIMX PWM输入模式 定义 * 这里的输入捕获使用定时器TIM1_CH1,捕获WK_UP按键的输入* 默认是针对TIM1/TIM8等高级定时器* 注意: 通过修改这几个宏定义,可以支持TIM1~TIM8任意一个定时器的通道1/通道2*/
#define ATIM_TIMX_PWMIN_CHY_GPIO_PORT GPIOC
#define ATIM_TIMX_PWMIN_CHY_GPIO_PIN GPIO_PIN_6
#define ATIM_TIMX_PWMIN_CHY_GPIO_AF GPIO_AF3_TIM8
#define ATIM_TIMX_PWMIN_CHY_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOC_CLK_ENABLE(); }while(0) /* PC口时钟使能 */#define ATIM_TIMX_PWMIN TIM8
#define ATIM_TIMX_PWMIN_IRQn TIM8_UP_TIM13_IRQn
#define ATIM_TIMX_PWMIN_IRQHandler TIM8_UP_TIM13_IRQHandler
#define ATIM_TIMX_PWMIN_CHY TIM_CHANNEL_1 /* 通道Y,1<=Y<=2 */
#define ATIM_TIMX_PWMIN_CHY_CLK_ENABLE() do{ __HAL_RCC_TIM8_CLK_ENABLE(); }while(0) /* TIM8 时钟使能 *//* TIM1 / TIM8 有独立的捕获中断服务函数,需要单独定义,对于TIM2~5等,则不需要以下定义 */
#define ATIM_TIMX_PWMIN_CC_IRQn TIM8_CC_IRQn
#define ATIM_TIMX_PWMIN_CC_IRQHandler TIM8_CC_IRQHandlervoid atim_timx_pwmin_chy_init(void); /* 高级定时器 PWM输入模式初始化 */
void atim_timx_pwmin_chy_restart(void); /* 高级定时器 重启PWM输入模式检测 */#endif
2.3main.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"
#include "./BSP/TIMER/gtim.h"int main01(void)
{uint8_t key = 0;uint8_t t = 0;GPIO_InitTypeDef gpio_init_struct;HAL_Init(); /* 初始化HAL库 */sys_stm32_clock_init(336, 8, 2, 7); /* 设置时钟,168Mhz */delay_init(168); /* 延时初始化 */usart_init(115200); /* 串口初始化为115200 */led_init(); /* 初始化LED */key_init(); /* 初始化按键 *//* 将 LED1 引脚设置为输入模式, 避免和PC6冲突 */gpio_init_struct.Pin = LED1_GPIO_PIN; /* LED1引脚 */gpio_init_struct.Mode = GPIO_MODE_INPUT; /* 设置为输入 */gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */gpio_init_struct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; /* 高速模式 */HAL_GPIO_Init(LED1_GPIO_PORT, &gpio_init_struct); /* 初始化LED1引脚 */atim_timx_npwm_chy_init(10000 - 1, 8400 - 1); /* 20Khz的计数频率,2Hz的PWM频率. */ATIM_TIMX_NPWM_CHY_CCRX = 5000; /* 设置PWM占空比,50%,这样可以控制每一个PWM周期,LED1(GREEN)* 有一半时间是亮的,一半时间是灭的,LED1亮灭一次,表示一个PWM波*/atim_timx_npwm_chy_set(5); /* 输出5个PWM波(控制LED1(GREEN)闪烁5次) */while (1){key = key_scan(0);if (key == KEY0_PRES) /* KEY0按下 */{atim_timx_npwm_chy_set(5); /* 输出5个PWM波(控制TIM8_CH1, 即PC6输出5个脉冲) */}t++;delay_ms(10);if (t > 50) /* 控制LED0闪烁, 提示程序运行状态 */{t = 0;LED0_TOGGLE();}}
}int main02(void)
{uint8_t t = 0;GPIO_InitTypeDef gpio_init_struct;HAL_Init(); /* 初始化HAL库 */sys_stm32_clock_init(336, 8, 2, 7); /* 设置时钟,168Mhz */delay_init(168); /* 延时初始化 */usart_init(115200); /* 串口初始化为115200 */led_init(); /* 初始化LED */key_init(); /* 初始化按键 *//* 将 LED1 引脚设置为输入模式, 避免和PC6冲突 */gpio_init_struct.Pin = LED1_GPIO_PIN; /* LED1引脚 */gpio_init_struct.Mode = GPIO_MODE_INPUT; /* 设置为输入 */gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */gpio_init_struct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; /* 高速模式 */HAL_GPIO_Init(LED1_GPIO_PORT, &gpio_init_struct); /* 初始化LED1引脚 */atim_timx_npwm_chy_init(10000- 1, 168 - 1); /* 1Mhz的计数频率,1Khz的PWM周期. */ATIM_TIMX_COMP_CH1_CCRX = 250-1; /* 通道1 相位25%*/ATIM_TIMX_COMP_CH2_CCRX = 500-1; /* 通道1 相位50%*/ATIM_TIMX_COMP_CH3_CCRX = 750-1; /* 通道1 相位75%*/ATIM_TIMX_COMP_CH4_CCRX = 1000-1; /* 通道1 相位100%*/while (1){t++;delay_ms(10);if (t > 50) /* 控制LED0闪烁, 提示程序运行状态 */{t = 0;LED0_TOGGLE();}}
}
int main03(void)
{uint8_t t = 0;HAL_Init(); /* 初始化HAL库 */sys_stm32_clock_init(336, 8, 2, 7); /* 设置时钟,168Mhz */delay_init(168); /* 延时初始化 */usart_init(115200); /* 串口初始化为115200 */led_init(); /* 初始化LED */atim_timx_cplm_pwm_init(1000- 1, 168 - 1); /* 1Mhz的计数频率,1Khz波形输出. */atim_timx_cplm_pwm_set(300,250); /*占空比为7:3,死区时间 100*tDTS*/while (1){t++;delay_ms(10);if (t > 50) /* 控制LED0闪烁, 提示程序运行状态 */{t = 0;LED0_TOGGLE();}}
}extern uint16_t g_timxchy_pwmin_psc; /* PWM输入状态 */
extern uint16_t g_timxchy_pwmin_sta; /* PWM输入状态 */
extern uint32_t g_timxchy_pwmin_hval; /* PWM的高电平脉宽 */
extern uint32_t g_timxchy_pwmin_cval; /* PWM的周期宽度 */int main04(void)
{uint8_t t = 0;double ht,ct,f,tpsc;HAL_Init(); /* 初始化HAL库 */sys_stm32_clock_init(336, 8, 2, 7); /* 设置时钟,168Mhz */delay_init(168); /* 延时初始化 */usart_init(115200); /* 串口初始化为115200 */led_init(); /* 初始化LED */gtim_timx_pwm_chy_init(10- 1, 84 - 1); /* 1Mhz的计数频率,100Khz波形输出. */atim_timx_pwmin_chy_init(); /* 初始化PWM输入捕获 */GTIM_TIMX_PWM_CHY_CCRX = 2; /* 低电平宽度20,高电平宽度80 */while (1){t++;delay_ms(10);if (t > 20) /* 控制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) / 168; /* 得到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输入检测 */}t = 0;LED0_TOGGLE();}}
}