1. 程式人生 > >stm32通用定時器用做外部脈衝計數器的例程

stm32通用定時器用做外部脈衝計數器的例程

最近幾天要用到stm32對外部輸入脈衝進行計數,很自然想到定時器,可是手上資料沒有講解stm32定時器如何用作外部計數器的,在網上找例程,也沒找到幾個正確的,自己硬著頭皮仔細研究參考手冊,終於知道如何配置了,並寫了一個例程,希望將來對一些網友有用。

其實stm32通用定時器做計數器,對外部脈衝計數,還是比較簡單的,使用外部時鐘模式2即可輕鬆實現,但要注意,這種模式下,外部輸入脈衝訊號一定要接在相應TIM的ETR引腳上,不能接在TIMx_CHy引腳上。

使用stm32定時器的外部時鐘模式2,主要就是通過配置TIMx_SMCR暫存器相應位。步驟如下:

1. 若不需要濾波器,置TIMx_SMCR暫存器中的ETF[3:0]=0000 

2. 設定預分頻,TIMx_SMCR暫存器中的ETPS[1:0] 

3. 設定ETR的檢測極性,TIMx_SMCR暫存器中的ETP位 

4. 開啟外部時鐘模式2,置TIMx_SMCR暫存器中的ECE=1 

5. 啟動計數器,置TIMx_CR1暫存器中的CEN=1

我的例程是利用定時器2,定時產生週期1s的方波訊號,通過PB5(LED0)輸出,通過導線將PB5的方波訊號輸入到TIMER3的ETR引腳PD2上,通過TIMER3對該方波訊號計數,計數次數到了之後,更改LED1的狀態。

以下程式已經過測試,可行。

//timer2 ,定時器模式
void TIM2_Int_Init(u16 arr,u16 psc)
{
RCC->APB1ENR |= 1<<0;//TIM2時鐘使能


TIM2->ARR = arr;
TIM2->PSC = psc;


TIM2->DIER |= 1<<0;//允許更新中斷
TIM2->DIER |= 1<<6;//使能觸發中斷


MY_NVIC_Init(1,2,TIM2_IRQChannel,2);//搶佔1,子優先順序2,組2


TIM2->CR1 |= 1<<0;//使能定時器

}


//定時器2中斷服務程式 
void TIM2_IRQHandler(void)
{        
if(TIM2->SR&0X0001)//溢位中斷
{
LED0=!LED0; //PB5,硬體連線:將PB5連線至TIM3_ETR引腳PD2上            
}  
TIM2->SR&=~(1<<0);//清除中斷標誌位    
}

//通用定時器3 用作外部計數器 初始化
//arr:計數自動重灌值。
void TIM3_Int_Init(u16 arr)
{
RCC->APB2ENR|=1<<5;//開啟GPIOD埠時鐘
GPIOD->CRL &= 0xfffff0ff;
GPIOD->CRL |= 0x00000400;//PD.2 浮空輸入


RCC->APB1ENR |= 1<<1;//使能TIM3時鐘


TIM3->ARR=arr;  //設定計數器自動重灌值
TIM3->PSC=0;        //不分頻


   TIM3->SMCR &= ~(0xf<<8);//無濾波
TIM3->SMCR &= ~(3<<12);//關閉預分頻
TIM3->SMCR |= 1<<15;//ETR被反相,低電平或下降沿有效
TIM3->SMCR |= 1<<14;//使能外部時鐘模式2


TIM3->DIER |= 1<<0;//允許更新中斷
TIM3->DIER |= 1<<6;//允許觸發中斷


MY_NVIC_Init(1,3,TIM3_IRQChannel,2);//搶佔1,子優先順序3,組2


TIM3->CNT = 0x0;//清零計數器
TIM3->CR1 |= 1<<0;//使能定時器,開啟計數。
 
}

//定時器3中斷服務程式 
void TIM3_IRQHandler(void)
{        
if(TIM3->SR&0X0001)//溢位中斷
{
LED1=!LED1;             
}  
TIM3->SR&=~(1<<0);//清除中斷標誌位    
}

int main(void)
{  
Stm32_Clock_Init(9);//系統時鐘設定
uart_init(72,9600);//串列埠初始化為9600
delay_init(72);  //延時初始化 
LED_Init();  //初始化與LED連線的硬體介面
BEEP_Init();         //初始化蜂鳴器埠
KEY_Init();         //初始化與按鍵連線的硬體介面

TIM3_Int_Init(20); //計數次數
TIM2_Int_Init(4999,7199);//時鐘週期0.1ms,計數5000次=定時0.5s

   while(1);
}

實驗結果:LED0 :1s點亮一次,LED1:     20s點亮一次。