大学马上就要结束了,蓝牙项目也算是告一段落,这一路走来,辛酸与欢笑同在,当程序和PCB不再是主要的矛盾的时候,顿时感觉前方一片坦荡,哈哈~
最后一个寒假,无聊之际好好给自己的stm32补漏一下,写写程序顺便再画个stm32开发板什么的,为年后实习,fighting!!!
stm32 的定时器功能强大,stm32f103vet6芯片上的定时器很早的一篇博客上已经写得很明白了,但是回头一看,还没好好写过定时器配置,惭愧!!!~
后面的定时器配置仅仅是一个普通的定时器TIM3配置,每一秒进一次中断,实现定时和计数。倒不难,只是影子寄存器还是让我卡了一会儿,它的解释直接网上COPY了~
工程下载地址:http://download.csdn.net/detail/xiaoleiacm/8410521
影子寄存器是高级定时器框图的一部分,细心的人可以发现预分频器寄存器、自动重载寄存器和捕捉/比较寄存器下面有一个阴影,其他的寄存器有些也有阴影。 这表示在物理上这个寄存器对应2个寄存器:一个是我们可以可以写入或读出的寄存器,称为预装载寄存器,另一个是我们看不见的、无法真正对其读写操作的,但在使用中真正起作用的寄存器,称为影子寄存器. 数据手册介绍预装载寄存器的内容可以随时传送到影子寄存器,即两者是连通的(permanently),或者在每一次更新事件(UEV)时才把预装载寄存器的内容传送到影子寄存器。 原文如下: The auto-reload register is preloaded. Writing to or reading from the auto-reload register accesses the preload register. The content of the preload register are transferred into the shadow register permanently or at each update event (UEV), depending on the auto-reload preload enable bit (ARPE) in TIMx_CR1 register. The update event is sent when the counter reaches the overflow (or underflow when downcounting) and if the UDIS bit equals 0 in the TIMx_CR1 register. It can also be generated by software. The generation of the update event is described in detailed for each configuration. 在图中的,表示对应寄存器的影子寄存器可以在发生更新事件时,被更新为它的预装载寄存器的内容;而图中的部分,表示对应的自动重载寄存器可以产生一个更新事件(U)或更新事件中断(UI)。
作用:设计预装载寄存器和影子寄存器的好处是,所有真正需要起作用的寄存器(影子寄存器)可以在同一个时间(发生更新事件时)被更新为所对应的预装载寄存器的内容,这样可以保证多个通道的操作能够准确地同步。如果没有影子寄存器,软件更新预装载寄存器时,则同时更新了真正操作的寄存器,因为软件不可能在一个相同的时刻同时更新多个寄存器,结果造成多个通道的时序不能同步,如果再加上例如中断等其它因素,多个通道的时序关系有可能会混乱,造成是不可预知的结果。
下面是例子:
#ifndef _BSP_TIMER_H_ #define _BSP_TIMER_H_ /*************************************************************************************************** 当前文档 bsp_timer.h ***************************************************************************************************/ void NVIC_Configuration(void) ; void TIM3_Configuration(void); #endif
#include "bsp_timer.h" #include "misc.h" #include "stm32f10x_tim.h" /*************************************************************************************************** 当前文档 bsp_timer.c ***************************************************************************************************/ /*************************************************************************************************** *\Function TIM3_Configuration *\Description 配置定时器TM3 *\Parameter *\Return void *\Note *\Log 2015年1月30日 * 配置函数。 ***************************************************************************************************/ void TIM3_Configuration(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); // 使能时钟源 TIM_DeInit(TIM3); TIM_InternalClockConfig(TIM3); // 使用内部时钟 //溢出时间 T=(TIM_Period+1)*(TIM_Prescaler+1)/Ftosc TIM_TimeBaseStructure.TIM_Period = 2000 - 1; //设置自动重载计数周期值 TIM_TimeBaseStructure.TIM_Prescaler = 36000 - 1; //设置分频系数 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分频因子 当前为72Mhz TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //设置计数方式 TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); // 初始化 TIM_ClearFlag(TIM3, TIM_FLAG_Update); // 清除TIM3 溢出中断 TIM_ARRPreloadConfig(TIM3, ENABLE); //实际影响计数的是影子寄存器,可以通过TIM_ARRPreloadConfig设置为DISABLE 还是ENABLE确定内容是立即更新还是每次UEV事件发生的时候更新这个计数值。 TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE); // 开启TIM3中断 TIM_Cmd(TIM3, ENABLE); } /*************************************************************************************************** *\Function NVIC_Configuration *\Description 配置中断优先级 *\Parameter *\Return void *\Note *\Log 2015年1月30日 * 配置函数。 ***************************************************************************************************/ void NVIC_Configuration(void) //配置中断优先级 { NVIC_InitTypeDef NVIC_InitStructure; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); NVIC_InitStructure.NVIC_IRQChannel =TIM3_IRQn ; //配置定时器中断 TIM3 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); }
最后在中断文档stm32f10x_it.h中写入中断处理函数:
#include "stm32f10x_tim.h" static int flag=1; void TIM3_IRQHandler(void) { if(TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) { TIM_ClearITPendingBit(TIM3 , TIM_FLAG_Update); //do someting... if(flag==1) { GPIO_ResetBits(GPIOB, GPIO_Pin_5); flag=0; } else{ GPIO_SetBits(GPIOB, GPIO_Pin_5); flag=1; } } }