STM32F4的定时器时钟有点复杂,当APB1和APB2分频数为1的时候,TIM1、TIM8~TIM11的时钟为APB2的时钟,TIM2~TIM7、TIM12~TIM14的时钟为APB1的时钟;
而如果APB1和APB2分频数不为1,那么TIM1、TIM8~TIM11的时钟为APB2的时钟的两倍,TIM2~TIM7、TIM12~TIM14的时钟为APB1的时钟的两倍
因此专门写了一个函数,用于获取定时器时钟频率 u32 TIMER_GetTimeClockSpeed(TIMER_CH timerCh)
/*************************************************************************************************************
* 文件名 : stm32f4_timer.c
* 功能 : STM32F4 timer驱动
* 作者 : [email protected]
* 创建时间 : 2017-08-24
* 最后修改时间 : 2017-08-24
* 详细: 高级定时器:tim1,time8(16位)
通用定时器:tim3,tim4(16位),tim2,tim5(32位)
通用定时器:tim9-tim14(16位)
基本定时器:tim6-tim7(16位)
2019-10-24:增加 u32 Timer_GetTimeClockSpeed(TTIMER_CH timerCh) 支持
因为系统初始化SystemInit函数里初始化APB1总线时钟为4分频即42M,APB2总线时钟为2分频即84M,
所以TIM1、TIM8~TIM11的时钟为APB2时钟的两倍即168M,TIM2~TIM7、TIM12~TIM14的时钟为APB1的时钟的两倍即84M。
*************************************************************************************************************/
#include "stm32f4_timer.h"
#include "system.h"
//定时器结构体指针
static const TIM_TypeDef *TimerX[14] = {TIM1,TIM2,TIM3,TIM4,TIM5,TIM6,TIM7,TIM8,TIM9,TIM10,TIM11,TIM12,TIM13,TIM14};
/*************************************************************************************************************************
* 函数 : u32 TIMER_GetTimeClockSpeed(TIMER_CH timerCh)
* 功能 : STM32F4获取定时器时钟频率
* 参数 : timerCh:定时器选择,见TIMER_CH;
* 返回 : 定时器时钟频率,单位Hz
* 依赖 : 底层宏定义
* 作者 : [email protected]
* 时间 : 2019-10-24
* 最后修改时间 : 2019-10-24
* 说明 : 当APB1和APB2分频数为1的时候,TIM1、TIM8~TIM11的时钟为APB2的时钟,TIM2~TIM7、TIM12~TIM14的时钟为APB1的时钟;
而如果APB1和APB2分频数不为1,那么TIM1、TIM8~TIM11的时钟为APB2的时钟的两倍,TIM2~TIM7、TIM12~TIM14的时钟为APB1的时钟的两倍
*************************************************************************************************************************/
u32 TIMER_GetTimeClockSpeed(TIMER_CH timerCh)
{
u32 clock = 0;
u8 PPRE;
switch(timerCh)
{
case TIMER1:
case TIMER8:
case TIMER9:
case TIMER10:
case TIMER11: //来自APB2高速时钟总线
{
PPRE = (RCC->CFGR>>13)&0X7; //获取PPRE2 分频值
if(PPRE == 0) //分频数位0,直接等于APB2时钟
{
clock = SYS_GetAPB2ClockSpeed();
}
else //分频数不为1,时钟为APB2的2倍
{
clock = SYS_GetAPB2ClockSpeed()*2;
}
}break;
case TIMER2:
case TIMER3:
case TIMER4:
case TIMER5:
case TIMER6:
case TIMER7:
case TIMER12:
case TIMER13:
case TIMER14: //来自APB1低速时钟
{
PPRE = (RCC->CFGR>>10)&0X7; //获取PPRE1 分频值
if(PPRE == 0) //分频数位0,直接等于APB1时钟
{
clock = SYS_GetAPB1ClockSpeed();
}
else //分频数不为1,时钟为APB1的2倍
{
clock = SYS_GetAPB1ClockSpeed()*2;
}
}break;
default:
{
clock = 0;
}break;
}
return clock;
}
/*************************************************************************************************************************
* 函数 : void TimerPWM_Init(TIMER_CH timerCh, TIMER_PWM_CH pwmCh,u16 psc, u16 arr)
* 功能 : 初始化定时器PWM输出
* 参数 : timerCh:定时器选择,见TIMER_CH
pwmCh :PWM输出通道选择,见TIMER_PWM_CH
psc: 预分频器
arr: 重装值
* 返回 : 无
* 依赖 : 底层读写函数
* 作者 : [email protected]
* 时间 : 20130331
* 最后修改时间 : 20130331
* 说明 : 初始为边沿对齐模式,向上计数,更新时计数器不停止
此函数不初始化外部引脚,需要初始化对应的PWM输出脚为复用推挽输出即可
同一定时器产生的不同通道的PWM频率一样
*************************************************************************************************************************/
void TimerPWM_Init(TIMER_CH timerCh, TIMER_PWM_CH pwmCh,u16 psc, u16 arr)
{
TIM_TypeDef *TIMx;
const SYS_DEV_CLOCK DEV_TimeBuff[] = {DEV_TIM1,DEV_TIM2,DEV_TIM3,DEV_TIM4,DEV_TIM5,DEV_TIM6,DEV_TIM7,DEV_TIM8,DEV_TIM9,DEV_TIM10,
DEV_TIM11,DEV_TIM12,DEV_TIM13,DEV_TIM14};
if(timerCh == TIMER6 || timerCh == TIMER7) //定时器6和定时器7为基本定时器,不带PWM输出
return;
TIMx = (TIM_TypeDef *)TimerX[timerCh]; //获取指定定时器寄存器结构指针
SYS_DeviceClockEnable(DEV_TimeBuff[timerCh],TRUE); //使能定时器时钟
//初始化配置
TIMx->CR1 = 0; //关闭定时器,并复位相关设置
TIMx->CR2 = 0; //复位相关设置
TIMx->PSC = psc; //预分频器
TIMx->ARR = arr; //自动重装值
//配置PWM通道
switch (pwmCh)
{
case PWM_CH1:
{
TIMx->CCMR1 &= ~0xff; //清除之前设置
TIMx->CCMR1 |= 7 << 4; //PWM2模式
TIMx->CCMR1 |= 1 << 3; //CH1预装载使能
TIMx->CCER &= ~(0xf<<0); //清除之前设置
TIMx->CCER |= 1<<1; //OC1 低电平有效
TIMx->CCER |= 1<<0; //OC1 输出使能
}break;
case PWM_CH2:
{
TIMx->CCMR1 &= ~(0xff << 8); //清除之前设置
TIMx->CCMR1 |= (7 << 12); //PWM2模式
TIMx->CCMR1 |= 1 << 11; //CH2预装载使能
TIMx->CCER &= ~(0xf<<4); //清除之前设置
TIMx->CCER |= 1<<5; //OC2 低电平有效
TIMx->CCER |= 1<<4; //OC2 输出使能
}break;
case PWM_CH3:
{
TIMx->CCMR2 &= ~0xff; //清除之前设置
TIMx->CCMR2 |= 7 << 4; //PWM2模式
TIMx->CCMR2 |= 1 << 3; //CH3预装载使能
TIMx->CCER &= ~(0xf<<8); //清除之前设置
TIMx->CCER |= 1<<9; //OC3 低电平有效
TIMx->CCER |= 1<<8; //OC3 输出使能
}break;
case PWM_CH4:
{
TIMx->CCMR2 &= ~(0xff << 8); //清除之前设置
TIMx->CCMR2 |= 7 << 12; //PWM2模式
TIMx->CCMR2 |= 1 << 11; //CH4预装载使能
TIMx->CCER &= ~(0xf<<12); //清除之前设置
TIMx->CCER |= 1<<13; //OC4 低电平有效
TIMx->CCER |= 1<<12; //OC4 输出使能
}break;
default : break;
}
TIMx->CR1 |= BIT7; //定时器自动重装使能
TIMx->EGR |= BIT0; //更新
TIMx->BDTR |= BIT15; //主输出使能,只针对TIM1,TIM8
TIMx->CR1 |= BIT0; //使能定时器
}
/*************************************************************************************************************************
* 函数 : void TimerPWM_Set(TIMER_CH timerCh, TIMER_PWM_CH pwmCh,u16 pwm)
* 功能 : 设置PWM占空比
* 参数 : timerCh:定时器选择,见TIMER_CH
pwmCh :PWM输出通道选择,见TIMER_PWM_CH
pwm:PWM为高的时间
* 返回 : 无
* 依赖 : 底层读写函数
* 作者 : [email protected]
* 时间 : 20130331
* 最后修改时间 : 20130331
* 说明 : 需要先初始化定时器
值越大,占空比越大
*************************************************************************************************************************/
void TimerPWM_Set(TIMER_CH timerCh, TIMER_PWM_CH pwmCh,u16 pwm)
{
TIM_TypeDef *TIMx;
if(timerCh == TIMER6 || timerCh == TIMER7) //定时器6和定时器7为基本定时器,不带PWM输出
return;
TIMx = (TIM_TypeDef *)TimerX[timerCh]; //获取指定定时器寄存器结构指针
//设置捕获/比较寄存器的值,调节占空比
switch (pwmCh)
{
case PWM_CH1 : TIMx->CCR1 = pwm; break;
case PWM_CH2 : TIMx->CCR2 = pwm; break;
case PWM_CH3 : TIMx->CCR3 = pwm; break;
case PWM_CH4 : TIMx->CCR4 = pwm; break;
default : break;
}
}
/*************************************************************************************************************
* 文件名 : stm32f4_timer.h
* 功能 : STM32F4 timer驱动
* 作者 : [email protected]
* 创建时间 : 2017-08-24
* 最后修改时间 : 2017-08-24
* 详细: 高级定时器:tim1,time8(16位)
通用定时器:tim3,tim4(16位),tim2,tim5(32位)
通用定时器:tim9-tim14(16位)
基本定时器:tim6-tim7(16位)
*************************************************************************************************************/
#ifndef __STM32F4_TIMER_H_
#define __STM32F4_TIMER_H_
#include "system.h"
//定时器选择,定时器1,8高级定时器,2,3,4,5 9-14为通用定时器,6,7为基本定时器
typedef enum
{
TIMER1 = 0,
TIMER2 = 1,
TIMER3 = 2,
TIMER4 = 3,
TIMER5 = 4,
TIMER6 = 5,
TIMER7 = 6,
TIMER8 = 7,
TIMER9 = 8,
TIMER10 = 9,
TIMER11 = 10,
TIMER12 = 11,
TIMER13 = 12,
TIMER14 = 13,
} TIMER_CH;
//定时器PWM通道,每个定时器有4路PWM输出通道
typedef enum
{
PWM_CH1 = 0,
PWM_CH2 = 1,
PWM_CH3 = 2,
PWM_CH4 = 3,
} TIMER_PWM_CH;
//API
void TimerPWM_Init(TIMER_CH timerCh, TIMER_PWM_CH pwmCh,u16 psc, u16 arr); //初始化定时器PWM输出
void TimerPWM_Set(TIMER_CH timerCh, TIMER_PWM_CH pwmCh,u16 pwm); //设置PWM占空比
u32 TIMER_GetTimeClockSpeed(TIMER_CH timerCh); //STM32F4获取定时器时钟频率
#endif //__STM32F4_TIMER_H_
/*************************************************************************************************************************
* 函数 : u32 SYS_GetSystemClockSpeed(void)
* 功能 : STM32F4 获取系统时钟频率
* 参数 : 无
* 返回 : 系统时钟频率HZ
* 依赖 : 底层宏定义
* 作者 : [email protected]
* 时间 : 2016-03-13
* 最后修改时间 : 2016-03-13
* 说明 : 用于获取系统时钟,SYSCLK时钟
PLL使能后:SYSCLK=PLLOUT=VCO/PLLP
f(VCO 时钟) = f(PLL 时钟输入) × (PLLN / PLLM)
f(PLL 常规时钟输出) = f(VCO 时钟) / PLLP
*************************************************************************************************************************/
u32 SYS_GetSystemClockSpeed(void)
{
static const u8 PLLP[] = {2,4,6,8}; //PLL 分频系数。
u32 temp;
switch(SYS_GetSystemClockSource()) //获取时钟来源
{
case SYS_CLOCK_HSI: //HSI作为系统时钟
{
return HSI_CLOCK*1000000;
}
case SYS_CLOCK_HSE: //HSE作为系统时钟
{
return HSE_CLOCK*1000000;
}
default: //PLL
{
temp = (RCC->PLLCFGR>>6)&0x1ff; //获取PLLN,(PLL输入时钟/PLLM = 1MHZ)
temp /= PLLP[(RCC->PLLCFGR>>16)&0x3]; //除以PLLP
temp *= 1000000;
return temp;
}
}
}
/*************************************************************************************************************************
* 函数 : u32 SYS_GetAHBClockSpeed(void)
* 功能 : STM32F4 获取AHB时钟频率
* 参数 : 无
* 返回 : 时钟频率HZ
* 依赖 : 底层宏定义
* 作者 : [email protected]
* 时间 : 2016-03-13
* 最后修改时间 : 2016-03-13
* 说明 : AHB=SYSCLK/PRESC
*************************************************************************************************************************/
u32 SYS_GetAHBClockSpeed(void)
{
static const u16 HPRE[] = {1,1,1,1,1,1,1,1,2,4,8,16,64,128,256,512}; //AHB 时钟分频系数。
return SYS_GetSystemClockSpeed()/HPRE[((RCC->CFGR>>4)&0XF)];
}
/*************************************************************************************************************************
* 函数 : u32 SYS_GetAPB1ClockSpeed(void)
* 功能 : STM32F4 获取APB1时钟频率
* 参数 : 无
* 返回 : 时钟频率HZ
* 依赖 : 底层宏定义
* 作者 : [email protected]
* 时间 : 2016-03-13
* 最后修改时间 : 2016-03-13
* 说明 : APB1=AHB/PPRE1
*************************************************************************************************************************/
u32 SYS_GetAPB1ClockSpeed(void)
{
static const u8 PPRE1[] = {1,1,1,1,2,4,8,16};
return SYS_GetAHBClockSpeed()/PPRE1[((RCC->CFGR>>10)&0X7)];
}
/*************************************************************************************************************************
* 函数 : u32 SYS_GetAPB2ClockSpeed(void)
* 功能 : STM32F4 获取APB2时钟频率
* 参数 : 无
* 返回 : 时钟频率HZ
* 依赖 : 底层宏定义
* 作者 : [email protected]
* 时间 : 2016-03-13
* 最后修改时间 : 2016-03-13
* 说明 : APB1=AHB/PPRE2
*************************************************************************************************************************/
u32 SYS_GetAPB2ClockSpeed(void)
{
static const u8 PPRE2[] = {1,1,1,1,2,4,8,16};
return SYS_GetAHBClockSpeed()/PPRE2[((RCC->CFGR>>13)&0X7)];
}
这样就可以动态的去调节系统时钟频率而保障PWM频率不变。