STM32F103的标准库、HAL、LL三种库定时器外部时钟模式2(TIMx_ETR)
STM32F103的定时器外部时钟模式2
前言:STM32的定时器时钟来源整体分为三种内部时钟RCC、外部时钟模式1、外部时钟模式2。(主要讲述以标准库为讲解实例,HAL也是相同原理(详情看网盘内代码内容),后续会在博文中继续更新LL库设置)
实验代码目的:由PA0引脚输入外部时钟脉冲(取代内部时钟RCC),达到定时器TIM2预设ARR值产生定时器2更新中断。(以往都是由内部RCC时钟产生脉冲,当脉冲个数CNT=ARR,定时器产生更新中断)
外部时钟模式2工作原理过程
TIMX_ETR引脚在F103CB是PA0引脚,当PA0引脚输入外部时钟方波,配置内部的极性选择、边沿检测和预分频,输入滤波电路(去除外部电路输入的毛刺),一路ETRF进入触发控制器,可以选择作为时基单元时钟,可以把ETR外部引脚输入的脉冲方波作为时钟,或也可以对ETR引脚输入的脉冲计数,此时可以把定时器作为计数器使用。当外部时钟方波来一个脉冲,CNT就会累加(CNT++),当CNT等于预设的ARR值(CNT=ARR),就会产生一个更新事件(Update Event)或者更新中断(Update IT)。(一路进入TRGI(成为从模式的触发源),走TRGI这一路会多占用一个通道,且外部时钟模式变为外部时钟模式1。)
解释说明:产生更新事件一般是配合主从模式使用,触发DAC或者其他定时器,实现硬件自动化设置。此次实验就是产生更新中断
产生更新事件配置
手动软件产生
标准库配置:TIM_GenerateEvent(TIM2, TIM_EventSource_Update);
HAL库:HAL_TIM_GenerateEvent(&htim2,TIM_EVENTSOURCE_UPDATE);
更新中断配置
标准库配置:TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); //开启TIM2的更新中断
HAL库:HAL_TIM_Base_Start_IT(&htim2);
LL库:还未具体实验
代码配置步骤以及思路
1.配置GPIO GPIO_Init(GPIOA, &GPIO_InitStructure)
2.配置ETR外部时钟
3.配置外部时钟模式2
(TIM_ETRClockMode2Config(TIM2, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0x0F))此函数将步骤2、3合在一起
4.配置时基单元TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure)
5.配置中断输出控制TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
6.配置NVIC NVIC_Init(&NVIC_InitStructure);
7.运行控制 TIM_Cmd(TIM2, ENABLE);
具体HAL库以及标准库代码已经放在百度网盘,后续LL库配置会在本篇博文中继续更新。
链接:https://pan.baidu.com/s/1_rLx7xUJPTtEiY0nrce3zQ
提取码:k3p9
需要注意
1.RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
/开启时钟/是为了开启APBI时钟上外设TIMER2,从而允许CPU和其他外设模块通过APB1访问和控制TIM2,并不是给TIM2提供CNT++的时钟源,CNT++时钟源来源于PA0引脚的脉冲个数;
2.TIM_ClearFlag(TIM2, TIM_FLAG_Update);
/中断输出配置/
初始化时基单元后又增加TIM_ClearFlag函数,是因为清除定时器更新标志位,因为TIM_TimeBaseInit函数末尾,手动产生了更新事件,若不清除此标志位,则开启中断后,会立刻进入一次中断,如果不介意此问题,则不清除此标志位也可。
HAL库也是一样,初始化后,会立即进入中断,示例代码中也放入 __HAL_TIM_CLEAR_FLAG(&htim2,TIM_FLAG_UPDATE)清楚更新标志位;
具体过程如代码所示:
/**
* 函 数:定时中断初始化
* 参 数:无
* 返 回 值:无
* 注意事项:此函数配置为外部时钟,定时器相当于计数器
*/
void Timer_Init(void)
{
/*开启时钟*/
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //开启TIM2的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟
/*GPIO初始化*/
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure); //将PA0引脚初始化为上拉输入
/*外部时钟配置*/
TIM_ETRClockMode2Config(TIM2, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0x0F);
//选择外部时钟模式2,时钟从TIM_ETR引脚输入
//注意TIM2的ETR引脚固定为PA0,无法随意更改
//最后一个滤波器参数加到最大0x0F,可滤除时钟信号抖动
/*时基单元初始化*/
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; //定义结构体变量
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //时钟分频,选择不分频,此参数用于配置滤波器时钟,不影响时基单元功能
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数器模式,选择向上计数
TIM_TimeBaseInitStructure.TIM_Period = 10 - 1; //计数周期,即ARR的值
TIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 1; //预分频器,即PSC的值
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; //重复计数器,高级定时器才会用到
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure); //将结构体变量交给TIM_TimeBaseInit,配置TIM2的时基单元
/*中断输出配置*/
TIM_ClearFlag(TIM2, TIM_FLAG_Update); //清除定时器更新标志位
//TIM_TimeBaseInit函数末尾,手动产生了更新事件
//若不清除此标志位,则开启中断后,会立刻进入一次中断
//如果不介意此问题,则不清除此标志位也可
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); //开启TIM2的更新中断
/*NVIC中断分组*/
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //配置NVIC为分组2
//即抢占优先级范围:0~3,响应优先级范围:0~3
//此分组配置在整个工程中仅需调用一次
//若有多个中断,可以把此代码放在main函数内,while循环之前
//若调用多次配置分组的代码,则后执行的配置会覆盖先执行的配置
/*NVIC配置*/
NVIC_InitTypeDef NVIC_InitStructure; //定义结构体变量
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; //选择配置NVIC的TIM2线
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //指定NVIC线路使能
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //指定NVIC线路的抢占优先级为2
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //指定NVIC线路的响应优先级为1
NVIC_Init(&NVIC_InitStructure); //将结构体变量交给NVIC_Init,配置NVIC外设
/*TIM使能*/
TIM_Cmd(TIM2, ENABLE); //使能TIM2,定时器开始运行
}
作者:@#~~孙