五一之際,先祝你們五一快樂、其實快樂很簡單,工做的人有假放,學習的人也有假放,像我,有假放纔有更多的時間學本身想學的東西、51假期學51,惋惜沒有32假期呀、好了、、言歸正傳,你們聽過吸星大法吧、、在這裏、智商和情商比我高的人估計又知道我要說什麼了、、沒錯了、、今天咱們來了解「葵花寶典」第STM32篇之輸入捕獲,也就是上文所講的「吸星大法」,函數
那輸入捕獲能夠用來幹嗎呢??這個問題問的好,輸入捕獲能夠用來測量脈衝寬度或者測量頻率,假如要捕獲一個脈衝的高電平脈寬,咱們要怎麼作呢??別急哈、、接下來咱們從頭慢慢的分析到腳、、學習
據老夫所知:STM32的輸入捕獲,就是經過檢測通道上的邊沿信號,在邊沿信號發生跳變(好比說忽然來個上升沿或者降低沿),計數器就把此刻的計數值存放到對應通道的捕獲比較寄存器,就這樣、、就捕捉到了「美女」、話是這麼說、、可操做起來不只僅是幾句話、由於初始化和對捕獲的處理是不同的、因此,爲了作好迎接捕獲的準備,咱們來介紹下幾個比較陌生的位:ui
對於定時器的一些寄存器,在以前的博客都有涉及到,如spa
TIMx_CR1,code
捕獲/比較模式寄存器1(TIMx_CCMR1),blog
捕獲/比較使能寄存器(TIMx_CCER),事件
計數器(TIMx_CNT)ip
預分頻器(TIMx_PSC)ci
自動重裝載寄存器(TIMx_ARR)input
捕獲/比較寄存器1(TIMx_CCR1)
咱們再來看看捕獲/比較模式寄存器1(TIMx_CCMR1),因爲咱們是用TIM5_CH1,因此該寄存器中
CC1S[1:0]:捕獲/比較1選擇 (Capture/Compare 1 selection)咱們選擇01:CC1通道被配置爲輸入,IC1映射在TI1上;這個知道爲啥是TI1嗎??請看我那銷魂美麗的塗鴉:
這裏咱們檢測高電平的寬度,因此咱們檢測的時候只要遇到上升沿就觸發捕獲一次,可是咱們要怎麼設置呢,請看這幾位:
IC1PSC[1:0]:輸入/捕獲1預分頻器 (Input capture 1 prescaler)00:無預分頻器,捕獲輸入口上檢測到的每個邊沿都觸發一次捕獲;
神奇吧,好了,IC1F[3:0]:輸入捕獲1濾波器 (Input capture 1 filter)(這個就是上圖中的輸入濾波器,在這裏咱們不作濾波處理,爲何,請看如下解釋)
在這裏解釋下:數字濾波器由一個事件計數器組成,它記錄到N個事件後會產生一個輸出的跳變:這個N能夠取值具體參考中文手冊,意思是說:我採樣高電平,只有連續採樣到N個電平是高電平的話我才認爲是有效的高電平,低於N個我就認爲是無效的、在這篇博客裏,咱們只要是採樣到高電平就行,因此這裏就不採用數字濾波。
咱們來看看這個寄存器 捕獲/比較使能寄存器(TIMx_CCER),要使捕獲使能,咱們就須要設置使能位
CC1E:輸入/捕獲1輸出使能 (Capture/Compare 1 output enable)爲0;
對於咱們輸入捕獲後要處理的咱們交給咱們的中斷,因此在這裏咱們要開啓中斷使能位
DMA/中斷使能寄存器(TIMx_DIER) CC1IE:容許捕獲/比較1中斷 (Capture/Compare 1 interrupt enable)爲1;
介紹了以上幾位大神,接下來,咱們要怎麼個思路呢??==當咱們捕獲到上升沿時,咱們把此時的CNT中的值讀出來,而後等待降低沿的到來,這時候要分爲兩種狀況:
第一:降低沿來了,咱們就記錄此刻CNT的值,(捕獲值)而後重複以上動做
第二:降低沿沒來,但是這時候定時器的計數值已經到了,也就是要溢出了,這時候要特殊處理下,也就是直接把計數值返回
(注:在這裏,要注意捕獲值跟計數值的差異,他們是不同的、)至於爲何不同,你們能夠思考思考、、
因此咱們將兩次捕獲的值相減,(降低沿的值減去上升沿的值)就能夠獲得高電平的脈寬了、、而這些事,咱們都在中斷服務函數裏處理(中斷喔、、想起沒??要作什麼知道吧、、注意,這時候有兩個中斷觸發:更新中斷和捕獲中斷,更新中斷用來處理定時器計數溢出,捕獲中斷用來處理捕獲事件)
接下來,咱們看看咱們具體的實現步驟
1:開啓掛載在ABP1的TIM5時鐘,開啓掛載在ABP2的GPIOA的時鐘,並初始化TIM5和GPIOA,因爲這兩個初始化前幾篇博客有涉及到,故直接貼出代碼:
1 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); 2 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE); 3 4 KEY_Init(); //IO我已在按鍵的函數裏初始化了 5 6 TIM_TimeBaseStructure.TIM_Period = arr; 7 TIM_TimeBaseStructure.TIM_Prescaler = psc; 8 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; 9 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; 10 TIM_TimeBaseInit(TIM5, & TIM_TimeBaseStructure);
二、設置TIM_CH1的輸入捕獲功能,打開「stm3210x.tim.h」咱們能夠看到
1 typedef struct 2 { 3 4 uint16_t TIM_Channel; /*!< Specifies the TIM channel.設置通道 5 This parameter can be a value of @ref TIM_Channel */ 6 7 uint16_t TIM_ICPolarity; /*!< Specifies the active edge of the input signal.設置輸入信號的有效捕獲極性 8 This parameter can be a value of @ref TIM_Input_Capture_Polarity */ 9 10 uint16_t TIM_ICSelection; /*!< Specifies the input. 設置映射關係 11 This parameter can be a value of @ref TIM_Input_Capture_Selection */ 12 13 uint16_t TIM_ICPrescaler; /*!< Specifies the Input Capture Prescaler. 設置捕獲的分配係數 14 This parameter can be a value of @ref TIM_Input_Capture_Prescaler */ 15 16 uint16_t TIM_ICFilter; /*!< Specifies the input capture filter. 設置數字濾波器的長度 17 This parameter can be a number between 0x0 and 0xF */ 18 } TIM_ICInitTypeDef;
根據咱們以上的瞭解,咱們設置,請看如下代碼:
1 TIM_ICInitStructure.TIM_Channel = TIM_Channel_1; //通道1 2 TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕獲 3 TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到TI1 4 TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //不分頻 5 TIM_ICInitStructure.TIM_ICFilter = 0x0; //不濾波 6 TIM_ICInit(TIM5, &TIM_ICInitStructure);
三、設置中斷優先級、在這裏比較簡單,直接看代碼:
1 NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn; 2 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; 3 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; 4 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 5 NVIC_Init(&NVIC_InitStructure);
4.使能中斷並開啓定時器
1 2 TIM_ITConfig(TIM5, TIM_IT_Update | TIM_IT_CC1, ENABLE ); 3 4 TIM_Cmd(TIM5, ENABLE);
五、編寫中斷服務函數
1 u8 TM5_CH1_CAPTURE_STA = 0;//8位0x00~0x80 2 u16 TM5_CH1_CAPTURE_VAL; //捕獲高電平後定時器溢出的次數 3 4 void TIM5_IRQHandler(void) 5 { 6 if((TM5_CH1_CAPTURE_STA & 0x80) == 0 ) //未成功捕獲,0x80捕獲完成 7 { 8 if(TIM_GetITStatus(TIM5, TIM_IT_Update) == SET) //數據更新中斷產生 9 { 10 if(TM5_CH1_CAPTURE_STA & 0x40) //已經捕獲到高電平 11 { 12 if((TM5_CH1_CAPTURE_STA & 0x3f)==0x3f) //溢出 13 { 14 TM5_CH1_CAPTURE_STA |= 0x80; //強制捕獲成功 15 TM5_CH1_CAPTURE_VAL = 0xffff; //此時的計數值 16 } 17 else 18 { 19 TM5_CH1_CAPTURE_STA++; 20 } 21 22 } 23 } 24 if(TIM_GetITStatus(TIM5, TIM_IT_CC1) == SET)//發生捕獲 25 { 26 if(TM5_CH1_CAPTURE_STA & 0x40) //成功捕獲到一次降低沿,但不是第一次捕獲 27 { 28 TM5_CH1_CAPTURE_STA |= 0x80; //捕獲成功 29 TM5_CH1_CAPTURE_VAL = TIM_GetCapture1(TIM5);//獲取捕獲值 30 TIM_OC1PolarityConfig(TIM5, TIM_ICPolarity_Rising);//要設置爲上升沿,等待降低沿的來臨 31 } 32 else //第一次捕獲 33 { 34 TM5_CH1_CAPTURE_STA = 0; 35 TM5_CH1_CAPTURE_VAL = 0; 36 TIM_SetCounter(TIM5, 0); //還沒等到降低沿來時把全部的都清零 37 TM5_CH1_CAPTURE_STA |= 0x40; 38 TIM_OC1PolarityConfig(TIM5, TIM_ICPolarity_Falling);//要設置成降低沿,等到上升沿的來臨 39 } 40 41 } 42 } 43 TIM_ClearITPendingBit(TIM5, TIM_IT_CC1 | TIM_IT_Update); 44 45 }
六、注意紅色標註部分,好好理解剛開始說的計數值和捕獲值的區別、還有
TIM_SetCounter(TIM5, 0); //設置計數器寄存器值
TIM_OC1PolarityConfig(TIM5, TIM_ICPolarity_Falling);//設置通道1輸入捕獲極性
這兩個函數是庫函數爲咱們提升的能夠單獨對通道進行操做的函數,很是方便
七、到這裏,咱們須要在主函數裏稍微寫下:
1 if(TM5_CH1_CAPTURE_STA & 0x80) 2 { 3 temp = (TM5_CH1_CAPTURE_VAL & 0x3f); 4 temp *= 65536; //計數器爲0~65535,也就是65536一次 5 temp += TM5_CH1_CAPTURE_VAL; 6 printf("HIGH is %d\r\n",temp); 7 TM5_CH1_CAPTURE_STA = 0;//這裏由於咱們在以前的捕獲時,若捕獲成功則爲1,並無清0,因此要進行下一次捕獲的話,要在這裏進行清零 8 }
八、好了,至於我標題說的小應用,也就是把咱們上次PWM的輸出給此次的輸入捕獲,你們經過串口就能夠看到高電平的脈寬了。固然,在這篇博客的程序裏也須要保留上次PWM輸出的程序方可、、
九、你們肚子餓了吧、、吃飯去吧、、
今天五一,仍是宅在宿舍學32,也很開心,由於學到了東西、、有假放開心、、有學到知識也開心,即便在學的過程當中可能會被煩惱到、、其實快樂也很簡單、只是看你怎麼把握、、五月的開始、、將繼續學stm3二、、還有英語六級、、加油、、在這裏、有錯的地方但願能指教、、我也虛心的向您學習、、