1. 程式人生 > >基於stm32f103zet6的定時器的學習2(定時器上溢)

基於stm32f103zet6的定時器的學習2(定時器上溢)

使用普通定時器2來產生中斷,計數方式:增計數!

一、程式設計配置部分

1、首先進行中斷配置,定時器中斷肯定要配置的,程式碼如下:

void TIM2_NVIC_Configuration(void)
{
    NVIC_InitTypeDef NVIC_InitStructure; 
    
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);  													
    NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;	  
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;	
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}

這部分就不詳述了

2、定時器的配置才是重點

/*TIM_Period--1000   TIM_Prescaler--71 -->中斷週期為1ms*/
void TIM2_Configuration(void)
{
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 , ENABLE);
    TIM_DeInit(TIM2);
    TIM_TimeBaseStructure.TIM_Period=1000;		 		/* 自動重灌載暫存器週期的值(計數值) */
    /* 累計 TIM_Period個頻率後產生一個更新或者中斷 */
    TIM_TimeBaseStructure.TIM_Prescaler= (72 - 1);			/* 時鐘預分頻數 72M/72 */
    TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; 		/* 取樣分頻 */
    TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; /* 向上計數模式 */
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
    TIM_ClearFlag(TIM2, TIM_FLAG_Update);				/* 清除溢位中斷標誌 */
    TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
    TIM_Cmd(TIM2, ENABLE);	/* 開啟時鐘 */								
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 , DISABLE);		/*先關閉等待使用*/    
}
還是一樣,找到這個結構體
TIM_TimeBaseInitTypeDef{
uint16_t  TIM_ClockDivision 
uint16_t  TIM_CounterMode 
uint16_t  TIM_Period 
uint16_t  TIM_Prescaler 
uint8_t  TIM_RepetitionCounter 
}
#define  TIM_CKD_DIV1   ((uint16_t)0x0000)
#define  TIM_CKD_DIV2   ((uint16_t)0x0100)
#define  TIM_CKD_DIV4   ((uint16_t)0x0200)
2、TIM_CounterMode
用於設定計數模式 3、TIM_Period

Specifies the period value to be loaded into the active Auto-Reload Register at the next update event. This parameter must be a number between 0x0000 and 0xFFFF. 

就是一個重灌值而已!

Specifies the prescaler value used to divide the TIM clock. This parameter can be a number between 0x0000 and 0xFFFF

設定範圍比較廣,這裡有一個計算公式


Specifies the repetition counter value. Each time the RCR downcounter reaches zero, an update event is generated and counting restarts from the RCR value (N)

這是在PWM裡面用到的,這裡可以不作設定

6、配置中斷,清除中斷標誌位

    TIM_ClearFlag(TIM2, TIM_FLAG_Update);					/* 清除溢位中斷標誌 */
    TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);

至此整個TIM2就配置完畢!不難得出,最後出來的結果就是:

/*TIM_Period--1000   TIM_Prescaler--71 -->中斷週期為1ms*/

7、還漏了一個初始化函式,就是將TIMx設定為預設值!

void TIM_DeInit(TIM_TypeDef* TIMx)
{
  /* Check the parameters */
  assert_param(IS_TIM_ALL_PERIPH(TIMx)); 
 
  switch (*(uint32_t*)&TIMx)
  {
    case TIM1_BASE:
      RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM1, ENABLE);
      RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM1, DISABLE);  
      break; 
      
    case TIM2_BASE:
      RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM2, ENABLE);
      RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM2, DISABLE);
      break;
 
    case TIM3_BASE:
      RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM3, ENABLE);
      RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM3, DISABLE);
      break;
 
    case TIM4_BASE:
      RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM4, ENABLE);
      RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM4, DISABLE);
      break;
      
    case TIM5_BASE:
      RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM5, ENABLE);
      RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM5, DISABLE);
      break;
      
    case TIM6_BASE:
      RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM6, ENABLE);
      RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM6, DISABLE);
      break;
      
    case TIM7_BASE:
      RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM7, ENABLE);
      RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM7, DISABLE);
      break;
      
    case TIM8_BASE:
      RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM8, ENABLE);
      RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM8, DISABLE);  
      break; 
      
    default:
      break;
  }
}

可以看到這裡設定了各種定時器的預設值,我們只需要傳入一個引數就能自動的找到相應的分支進行初始化,非常明朗!

二、毫無疑問,我們既然產生了中斷,那麼我們的中斷函式怎麼實現呢?在哪裡實現呢?接著看我們在 it.c 檔案中實現的中斷函式!

void TIM2_IRQHandler(void)
{
	if ( TIM_GetITStatus(TIM2 , TIM_IT_Update) != RESET ) 
	{	
		TIM_ClearITPendingBit(TIM2 , TIM_FLAG_Update);    
  		 time++;
	}		 	
}
看看中斷裡面做了什麼,沒關係找手冊,可以看到這個
TIM_IT_Update: TIM update Interrupt source 
TIM_IT_CC1: TIM Capture Compare 1 Interrupt source 
TIM_IT_CC2: TIM Capture Compare 2 Interrupt source 
TIM_IT_CC3: TIM Capture Compare 3 Interrupt source 
TIM_IT_CC4: TIM Capture Compare 4 Interrupt source 
TIM_IT_COM: TIM Commutation Interrupt source 
TIM_IT_Trigger: TIM Trigger Interrupt source 
TIM_IT_Break: TIM Break Interrupt source 

這就是那個函式的傳入引數了,各種中斷方式,Checks whether the TIM interrupt has occurred or not.用於檢測是否產生對應的中斷,因為我們在設定中斷的時候就是設定的TIM_IT_Update中斷方式,也就是更新事件,過載初值吧,至少我是這樣理解的。

中斷裡面還清除了中斷標誌位,方便下一次進入中斷嘛,然後還有就是對全域性變數time自加1,方便主函式裡面的檢測!

好的,最後貼上主函式的程式碼,問題應該不大了。

/*******由於沒有做外設測試的程式是:按鍵PA0僅一個LED燈******/
/*******由於沒有做外設測試的程式是:串列埠採用的是PA9->(T<->T),PA9->(R<->R)*****/
#include "stm32f10x.h"    
#include "LED.h"
#include "SysTick.h"
#include "Delay.h"
#include "Usart.h"
#include "stdio.h"
#include "Timer3.h"

volatile u32 time; // ms 計時變數

int main(void)
{
	//初初始化GPIO
	LED_GPIO_Config();
	//初始化系統定時器
	SysTick_Init();
	USART1_Config();
		/* TIM2 定時配置 */
	TIM2_NVIC_Configuration();
  TIM2_Configuration();
	
	printf("\r\n ("__DATE__ " - " __TIME__ ") \r\n");
	START_TIME;
	while(1)
  {
    if ( time == 1000 ) /* 1s 時間到 */
    {
time = 0;
			/* LED1 取反 */      
GPIO_WriteBit(GPIOA, GPIO_Pin_0, (BitAction)((1-GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_0)))); 
    }        
  }
}