终于成功的使用了外部时钟源来作为定时器3的时钟源了,其实操作过程并不难,但是因为自己没有经验,所以走了很多弯路,在这里写这篇博客除了为了给自己记录之外,也希望对大家有帮助。
首先简单介绍一下其功能,我们都知道,stm32中的通用定时器的计数时钟有三种,内部时钟(CK_INT)、外部时钟源(包括外部时钟模式1:外部输入脚(TIx) 和外部时钟模式2:外部触发输入(ETR) 两种模式)、内部触发输入(ITRx) 这三种,其中内部时钟(CK_INT)是大家都比较常用的,也是在应用中比较多的,我们现在主要来讲一下外部时钟源的模式2外部时钟模式2:外部触发输入(ETR) 。
关于这部分的内容在《stm32中文参考手册》中的264页有详细的配置介绍,我这里把其配置步骤粘贴出来:
例如,要配置在ETR下每2个上升沿计数一次的向上计数器,使用下列步骤:
1. 本例中不需要滤波器,置TIMx_SMCR寄存器中的ETF[3:0]=0000
2. 设置预分频器,置TIMx_SMCR寄存器中的ETPS[1:0]=01
3. 设置在ETR的上升沿检测,置TIMx_SMCR寄存器中的ETP=0
4. 开启外部时钟模式2,置TIMx_SMCR寄存器中的ECE=1
5. 启动计数器,置TIMx_CR1寄存器中的CEN=1
好了,以上就是操作步骤,但是我们在进行编程的时候考虑的因素要多一些。
1、配置TIM3_ETR引脚为输入引脚PD2(包括使能GPIOD的时钟、配置为GPIO_Mode_IN_FLOATING输入模式),硬件上需要将脉冲连接到该引脚(这是前提),我这里是使用6.78MHz的晶振;
2、配置定时器3:包括使能定时器3对应的时钟引脚,配置定时器3的周期、预分频...参数;
3、因为我们使用了定时器3中断,所以需要给定时器设置优先级,在timerx_nvic_init()中的关于TIM3部分操作;
4、以上都是常用的定时器配置,现在来到了我们的重点了,就是要对上述中我粘贴出来的内容进行配置:首先我们要配置SMCR中的ETF、ETPS、ETP和ECE进行配置,非常庆幸的是库函数已经将这几个配置都封装好在TIM_ETRClockMode2Config(TIM3, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_Inverted,0x00); 中了,我们只需要调用它并填入参数便可;
5、执行完了以上步骤之后,还未行,我们还需要操作triggle中断,因为我们还使用了定时器的update中断TIM_ITConfig(TIM3, TIM_IT_Trigger, ENABLE);,因此我们也需要使能该中断TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
6、接下来,设置定时器3的计数器为0TIM_SetCounter( TIM3, 0);并使能定时器3 TIM_Cmd(TIM3, ENABLE);
7、以上配置就完成了,同时我们需要在定时器3中断函数中进行对TIM_IT_Update进行操作,(TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET),然后在其中清除该标志并执行我们需要的操作就可以了,比如说可以让LED灯亮灭等等。
8、以上就是定时器3如何使用外部时钟模式2:外部触发输入(ETR)并开启一个TIM_IT_Update中断进行的简单操作。
我将以上操作的实现的源码会上传在我的资料中,可是我是在公司写的,公司的文件都有加密,我还是把相关的操作都张贴在下方吧,由于篇幅限制的原因,一些其他的外设相关操作我就不贴出来了,比如LED操作或者是串口操作。
第一部分:直接对寄存器操作的,这个我是在网上找的资料,已经忘记链接了,谢谢那位大哥。
#include "stm32f10x.h"
#include "gpio.h"
#include "delay.h"
#include "usart.h"
//#include "systick.h"
#include "timer.h"
int timercount = 0;
void NVIC_CON(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
//?????3 ??????? ???
//arr:????????
void TIM3_Int_Init(u16 arr)
{
//enable port D clock.
RCC->APB2ENR|=1<<5;
//set PD.2 as input.
GPIOD->CRL &= 0xfffff0ff;
GPIOD->CRL |= 0x00000400;
//enable TIM3 clock.
RCC->APB1ENR |= 1<<1;//??TIM3??
TIM3->ARR=arr; //??????????
TIM3->PSC=0; //???
//SMCR->ETF = 0000, no triggerl filter.
TIM3->SMCR &= ~(0xf<<8);
//SMCR->ETPS = 00, off prescaler.
TIM3->SMCR &= ~(3<<12);
//SMCR->ETP = 1, TIM_ExtTRGPolarity_Inverted
TIM3->SMCR |= 1<<15;
//SMCR->ECE external clock enabel.
TIM3->SMCR |= 1<<14;
//DIER->UID update interrupt enabel.
TIM3->DIER |= 1<<0;
//triggle intterupt enabel.
TIM3->DIER |= 1<<6;
NVIC_CON();
//clean counter.
TIM3->CNT = 0x0;
//counter enabel.
TIM3->CR1 |= 1<<0;
}
void TIM3_IRQHandler(void)
{
//check if is TIM_IT_Update interrupt.
if(TIM3->SR&0X0001)
{
timercount++;
if(timercount %2 == 0)
{
GPIO_SetBits(GPIOC,GPIO_Pin_9);
}
else
{
GPIO_ResetBits(GPIOC,GPIO_Pin_9);
}
}
//clear interrupt flag.
TIM3->SR&=~(1<<0);
}
int main(void)
{
gpio_init();
usartx_init(TS_UART4, TS_BAUDRATE_19200);
TIM3_Int_Init(20);
while(1);
}
第二部分的内容就主要是调用库函数实现的,其实操作过程和操作寄存器的一样:
void timerx_rcc_init(uint8_t timerx)
{
switch(timerx)
{
case TS_TIMER2:
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
break;
case TS_TIMER3:
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
break;
default:
break;
}
}
void timerx_gpio_init(uint8_t timerx)
{
GPIO_InitTypeDef GPIO_InitStructure;
switch(timerx)
{
case TS_TIMER3://PD2 init. PD2 is the pulse input of timer3.
//enabel GPIOD's clock.
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD,ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_Init(GPIOD, &GPIO_InitStructure);
break;
default:
break;
}
}
void timerx_nvic_init(uint8_t timerx)
{
NVIC_InitTypeDef NVIC_InitStructure;
switch(timerx)
{
case TS_TIMER3:
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
break;
default:
break;
}
}
void timerx_param_init(uint8_t timerx, uint16_t peri, uint16_t pres)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
uint16_t tmpccmrx = 0;
switch(timerx)
{
case TS_TIMER3:
TIM_DeInit(TIM3);
TIM_TimeBaseStructure.TIM_Period = peri; //peri
TIM_TimeBaseStructure.TIM_Prescaler =pres; //pres
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
//including set SMCR_ECE bit.
TIM_ETRClockMode2Config(TIM3, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_Inverted,0x00);
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
TIM_ITConfig(TIM3, TIM_IT_Trigger, ENABLE);
TIM_SetCounter( TIM3, 0);
TIM_Cmd(TIM3, ENABLE);
break;
default:
break;
}
}
void timerx_octoggle(uint8_t timerx)
{
TIM_OCInitTypeDef TIM_OCInitStructure;
switch(timerx)
{
case TS_TIMER3:
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = CCR1_Val;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC1Init(TIM3, &TIM_OCInitStructure);
TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Disable);
TIM_ITConfig(TIM3, TIM_IT_CC1, ENABLE);
TIM_Cmd(TIM3, ENABLE);
break;
default:
break;
}
}
void timerx_init(uint8_t timerx, uint16_t peri, uint16_t pres)
{
timerx_rcc_init(timerx);
timerx_gpio_init(timerx);
timerx_nvic_init(timerx);
timerx_param_init(timerx, peri, pres);
}
void TIM3_IRQHandler(void)
{
static u16 capturetimer3 = 0;
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)
{
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
//capturetimer3 = TIM_GetCapture1(TIM3);
//TIM_SetCompare1(TIM3, capturetimer3 + CCR1_Val);
//timercount = 1;
timercount++;
if(timercount %2 == 0)
{
GPIO_SetBits(GPIOC,GPIO_Pin_9);
}
else
{
GPIO_ResetBits(GPIOC,GPIO_Pin_9);
}
}
}
int main()
{
gpio_init();
usartx_init(TS_UART4, TS_BAUDRATE_19200);
timerx_init(TS_TIMER3, 20, 0);
while(1)
{
usartx_send_byte(TS_UART4, 0x88);
}
}
主要操作就是这些。