>>可以查看资料手册,当前用的TIM2定时器挂在APB1上
、要得到CK_CNT,得知道CK_PSC,也就是TIMxCLK(CK_INT)是多少?
>>从上面知道TIM2是挂在APB1上,也就是PCLK1,再system_stm32f4xx.c ->static void SetSysClock(void)中
查看PCLK1和PCLK2分别是由HCLK 4分频和2分频得到,PCLK1=180/4=45M 和PCLK2=180/2 =90M, 分频系数PPRE1 = 4、PPRE2 =2, TIMxCLK(CK_INT) = 45M ?其实是不对的
搜索TIMxCLK关键字,可以找到这段文字. 从上面看可得知分频系数PPRE1 = 4、PPRE2 =2,所以 TIMxCLK = 2 * PCLKx ,即TIMxCLK = 2 * 45M =90M
TIMxCLK = 2x45M =90M ,为了便于计算,将定时器时钟设置为1M,也就是计一个数用1us的时间,可将预分频器值设置90-1=89,定时器时钟CK_CNT = (89-0+1)* 1 /(45*2) = 1M .注意:预分频器是从开始计数,所以是(89-0+1)
3、基本定时器没有预分频功能,此项会被忽略,故TIM_ClockDivision = 0,也可以设置几个参数看看是否变动。
4、计数方式TIM_CounterMode 设置为递增计数
1 void times_on(void)
2 {
3 TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
4
5 RCC_APB1PeriphClockCmd (RCC_APB1Periph_TIM2, ENABLE);
6
7 /* Time base configuration */
8 TIM_TimeBaseStructure.TIM_Period = 0xFFFFFFFF; //自动重装载寄存器的值 TIM2/TIM5定时器是32位计数器,计数器从0开始计数
9 TIM_TimeBaseStructure.TIM_Prescaler = (uint16_t) ((SystemCoreClock / 2) / 1000000) - 1; //预分频器从0开始计数,180M/2-1 = 89,故预分频器值是90,定时器时钟TIMx_clk = 90*1/(pclk1*2) = 90*1/(45*2)=1MHz
10 TIM_TimeBaseStructure.TIM_ClockDivision = 0; //可以忽略
11 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //递增计数
12
13 TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //结构体进行初始化
14 TIM_ARRPreloadConfig(TIM2, ENABLE); //使能自动加载
15
16 /* TIM Interrupts disable */
17 TIM_ITConfig(TIM2, TIM_IT_CC1 | TIM_IT_CC2 | TIM_IT_CC3 | TIM_IT_CC4, DISABLE);
18
19 /* TIM2 enable counter */
20 TIM_Cmd(TIM2, ENABLE);
21
22 }
23 void times_off(void)
24 {
25 TIM_Cmd(TIM2, DISABLE);
26
27 }
28
29 uint32_t get_cur_times() //获取计时器当前值,通过前后两次获取的值做差值,算出所得耗时时间
30 {
31 return TIM2->CNT;
32 }
四、利用IO上升沿中断方式触发,在中断里计数,比如计数10000次,也就是10000个时钟周期
IO配置:
void gpio_config(void)
{
//PA0外部中断触发
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
中断配置:
void EXTI_Config(void)
{
EXTI_InitTypeDef EXTI_InitStructure;
//PA0作为外部中断,得相连接
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource0);
EXTI_InitStructure.EXTI_Line = EXTI_Line0;//通道
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//中断
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;//上升沿
EXTI_InitStructure.EXTI_LineCmd = ENABLE;//使能
EXTI_Init(&EXTI_InitStructure);
}
void NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; //由于使用的是PA0,对应的是EXTI0通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //中断使能
NVIC_Init(&NVIC_InitStructure);
}
stm32f4xx_it.c 中断函数:
#define EXIT_CNT 10000 //测试10000个时钟周期计数
float T = 0.0;
float Fre = 0.0;
uint32_t exit_cnt = 0;
uint8_t exit_flg = 0;
__IO uint32_t time_1 = 0;
__IO uint32_t time_2 = 0;
void EXTI0_IRQHandler()
{
if(0 == exit_cnt)
{
time_1 = get_cur_times(); //首次触发进入中断,获取当前值
}
EXTI_ClearITPendingBit(EXTI_Line0);
exit_cnt ++;
if(EXIT_CNT == exit_cnt)
{
time_2 = get_cur_times();//计数达到设定值后,获取当前值
exit_cnt = 0;
T = (time_2 - time_1)*1.0/EXIT_CNT; //前后获取的值做差值,算出一个时钟周期时间
Fre = 1/T * 1000*1000; //换算出频率
exit_flg = 1;
}
}
主函数:
int main(void)
{
gpio_config();
Debug_USART_Config();
times_on(); //开启定时器
EXTI_Config();
NVIC_Config();
while(1)
{
demo_chipid_read();
if(1 == exit_flg)
{
exit_flg = 0;
printf("------------------------------------------\r\n");
printf("T = %lf(us)\r\n", T);
printf("Fre = %lf(Hz)\r\n", Fre);
printf("------------------------------------------\r\n");
}
Delay_ms(850);
}
}
测试2M源时钟、4分频、8分频、16分频结果如下: