1.定時器的輸入捕獲可以用來測量脈沖寬度或者測量頻率。輸入捕獲的原理圖如下:
?假設定時器是向上計數。在圖中,t1~t2之間的便是我們要測量的高電平的時間(脈沖寬度)。首先,設置定時器為上升沿捕獲,如此一來,在t1時刻可以捕獲到當前定時器的計數值CNT。然后,清零CNT,并設置定時器為下降沿捕獲,這樣,在t2時刻,又會發生捕獲事件,得到此時CNT的值,記為CCRx2。最后,根據定時器的計數頻率,便可以計數出t1~t2的時間,從而得到高電平的脈沖寬度。
這里的上升沿捕獲是指,當定時器復用的IO口,被輸入高電平時,即t1時刻產生捕獲。下降沿捕獲同理。
此外,在t1~t2之間,可能產生N次的定時器溢出。為了使數據準確,需要對定時器的溢出做出處理,防止高電平的時間過長。本次實驗中的處理方式為,當溢出的次數達到一定值時,強制認為已經捕獲完成(捕獲到上升沿、捕獲到下降沿)。
CNT的計數次數:N*ARR+CRRx2。
用CNT的計數次數乘以計數周期,便可以得到t1~t2的時間長度,即高電平持續的時間。
2.修改寄存器介紹:TIMx_ARR、 TIMx_PSC、TIMx_CCMR1、TIMx_CCER、TIMx_DIER、TIMx_CR1、TIMx_CCR1等寄存器的介紹可以在前面的博客中定時器介紹部分查看。此處只介紹TIMx_CCMR1寄存器和TIMx_CCER寄存器。
(1)捕獲/比較寄存器(TIMx_CCMR1):
?當在輸入捕獲模式下使用時,對于著圖中的第二行。低八位[7:0]用于捕獲/比較寄存器通道1的控制。高八位[15:8]用于捕獲/比較寄存器通道2的控制。本次實驗中使用的通道1,因此,只介紹TIMx_CCMR1的低八位。
[7:0]各位的描述如下:
?(2)捕獲/比較使能寄存器(TIMx_CCER):
?要想使能輸入捕獲,必須設置CC1E為1。
3.設計思路:
(1)使能TIM2時鐘,配置PA0為下拉輸入。(開發版中PA0與TIM2_CH1復用,并外接了按鍵。)
(2)初始化TIM2,設置TIM2的ARR和PSC。
(3)設置TIM2的輸入比較參數,開啟輸入捕獲。
4.代碼:通過按鍵的狀態獲取高低電平的時間,并將時間通過串口打印。同時,使用到了定時器2的中斷服務函數。
(1)usart:
#ifndef __USART_H
#define __USART_H#include "stm32f10x.h"
#include <stdio.h>#define RX_LEN 100 //?ü1??óêüμ?×?′ó×??úêyextern u8 RX_BUF[RX_LEN];
extern int len;
extern u8 RX_FLAG;void usart_init(u32 bound);#endif
#include "USART.h"int len = 0;
u8 data;
u8 RX_BUF[RX_LEN];
u8 RX_FLAG = 0;//′??ú3?ê??ˉoˉêy
void usart_init(u32 bound)
{//1.?¨ò?òy???¢USART?¢?D???á11ì?£oGPIO_InitTypeDef GPIO_Initstruct;USART_InitTypeDef USART_Initstruct;NVIC_InitTypeDef NVIC_Initstruct;//2.ê1?ü???úoíUSARTμ?ê±?ó£oRCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1,ENABLE);//RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1 | RCC_APB2Periph_AFIO,ENABLE);//3.????òy??£o//PA9£oGPIO_Initstruct.GPIO_Pin = GPIO_Pin_9;GPIO_Initstruct.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_Initstruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_Initstruct);//PA10:GPIO_Initstruct.GPIO_Pin = GPIO_Pin_10;GPIO_Initstruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_Initstruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_Initstruct);//4.????USART1:USART_Initstruct.USART_BaudRate = bound;USART_Initstruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;USART_Initstruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;USART_Initstruct.USART_Parity = USART_Parity_No;USART_Initstruct.USART_StopBits = USART_StopBits_1;USART_Initstruct.USART_WordLength = USART_WordLength_8b;USART_Init(USART1,&USART_Initstruct); //???à1?êy?YD′è?USARTμ???′??÷USART_Cmd(USART1,ENABLE); //ê1?üUSART??′??÷USART_ITConfig(USART1,USART_IT_RXNE,ENABLE); //ê1?ü?óê??D??//5.?????D??£oNVIC_Initstruct.NVIC_IRQChannel = USART1_IRQn;NVIC_Initstruct.NVIC_IRQChannelCmd = ENABLE;NVIC_Initstruct.NVIC_IRQChannelPreemptionPriority = 3;NVIC_Initstruct.NVIC_IRQChannelSubPriority = 3;NVIC_Init(&NVIC_Initstruct);}//void USART1_IRQHandler(void)
//{
// //uint16_t x[] = {1,2,3};
// //?D??ê?·?2úéú′??úêy?Y?óêü?D??
// if(USART_GetITStatus(USART1,USART_IT_RXNE) != RESET)
// {
// data = USART_ReceiveData(USART1);
// RX_BUF[len++] = data;
// RX_FLAG = 1;
// }
//}//???¨?òfputcoˉêy£o
//int fputc(int ch,FILE *f)
//{
// //1.?D??′??úê?·?·¢?ííê3é£o
// while((USART1->SR & 0x40) == 0);
//
// //2.·¢?íò???×??ú£???êy?YD′è?μ???′??÷£o
// USART1->DR = (u8) ch;
// return ch;
//}
int fputc(int ch, FILE *f)
{ while((USART1->SR&0X40)==0);//?-?··¢?í,?±μ?·¢?ííê±? USART1->DR = (u8) ch; return ch;
}
(2)delay:
#ifndef __DELAY_H
#define __DELAY_H#include "stm32f10x.h"void delay_us(uint32_t us); //?óê±?¢??
void delay_ms(uint32_t ms); //?óê±oá??#endif
#include "delay.h"void delay_us(uint32_t us)
{uint32_t i;//1.????HCLKê±?ó£?2¢éè??μ?′eê±?ó??êy?μSysTick_Config(72);for(i = 0;i < us;i++){while(!((SysTick->CTRL) & (1 << 16))); //μè′y??êyíê3é}SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; //????STCLKê±?ó?′£?2¢ê§?ü?¨ê±?÷
}void delay_ms(uint32_t ms)
{uint32_t i;//1.????HCLKê±?ó?′£?2¢éè??μ?′eê±?ó??êy?μSysTick_Config(72000);for(i = 0;i < ms;i++){while(!((SysTick->CTRL) & (1 << 16))); //μè′y??êyíê3é}SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; //????STCLKê±?ó?′£?2¢ê§?ü?¨ê±?÷
}
(3)?? time_capture:
#ifndef __TIME_CAPTURE_H
#define __TIME_CAPTURE_H#include "stm32f10x.h"extern u8 TIM2_CAPTURE_STATU; //ê?è?2???×′ì?
extern u16 TIM2_CAPTURE_VALUE;void TIME_CAPTURE_Init(u16 arr,u16 psc);#endif
#include "time_capture.h"/*TIM2_CAPTURE_STATUμ?μú7?a2???íê3é±ê??£?
μú6???a2???μ???μ???±ê??£?
μú0-5????2?????μ???oó?¨ê±?÷μ?ò?3?′?êy*/
u8 TIM2_CAPTURE_STATU = 0; //ê?è?2???×′ì?
u16 TIM2_CAPTURE_VALUE = 0; //ê?è?2????μvoid TIME_CAPTURE_Init(u16 arr,u16 psc)
{//?¨ò??à1??á11ì?£oGPIO_InitTypeDef GPIO_InitStrcture;TIM_TimeBaseInitTypeDef TIME_TimeBaseStructure;TIM_ICInitTypeDef TIM2_ICInitStructure;NVIC_InitTypeDef NVIC_InitStructure;//1.ê1?üê±?ó£oRCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//2.?????à1?μ??á11ì?D??¢£oGPIO_InitStrcture.GPIO_Mode = GPIO_Mode_IPD;GPIO_InitStrcture.GPIO_Pin = GPIO_Pin_0;GPIO_InitStrcture.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStrcture);GPIO_ResetBits(GPIOA,GPIO_Pin_0); //3?ê?ê±??PA0???a0//3.?????¨ê±?÷2£oTIME_TimeBaseStructure.TIM_Period = arr;TIME_TimeBaseStructure.TIM_Prescaler = psc;TIME_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;//éè??ê±?ó·???TIME_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Down;TIM_TimeBaseInit(TIM2,&TIME_TimeBaseStructure);//4.?????¨ê±?÷2μ?ê?è?2???2?êy£oTIM2_ICInitStructure.TIM_Channel = TIM_Channel_1; //éè??ê?è?í¨μàTIM2_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //éè??é?éy??2???TIM2_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //ó3é?μ?TI1é?TIM2_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //éè??ê?è?·??μTIM2_ICInitStructure.TIM_ICFilter = 0; //éè????2¨?÷TIM_ICInit(TIM2,&TIM2_ICInitStructure);//5.?D??1üàí????£oNVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;NVIC_Init(&NVIC_InitStructure);//6.ê1?ü?¨ê±?÷μ??üD??D???¢2????D??oí?¨ê±?÷£oTIM_ITConfig(TIM2,TIM_IT_Update | TIM_IT_CC1,ENABLE);TIM_Cmd(TIM2,ENABLE);}//??D′?¨ê±?÷2μ??D??·t??oˉêy£o
void TIM2_IRQHandler(void)
{if((TIM2_CAPTURE_STATU & 0x80) ==0) //?1?′2???íê3é{if(TIM_GetITStatus(TIM2,TIM_IT_Update) != RESET){if(TIM2_CAPTURE_STATU & 0x40) //2???μ???μ???{//′?′|ê?μ±á?D?2???μ???μ???μ?′?êy>= 0x3Fê±£?????è??a2???3é1|if((TIM2_CAPTURE_STATU & 0x3F) == 0x3F)//??μ???ì?3¤{TIM2_CAPTURE_STATU |= 0x80; //±ê??2???3é1|TIM2_CAPTURE_VALUE = 0xFFFF;}else{TIM2_CAPTURE_STATU ++;}}}}if(TIM_GetITStatus(TIM2,TIM_IT_CC1) != RESET) //·¢éú2???ê??t{if(TIM2_CAPTURE_STATU & 0x40) //2???μ?ò??????μ??{TIM2_CAPTURE_STATU |= 0X80; //±ê??2???3é1|TIM2_CAPTURE_VALUE = TIM_GetCapture1(TIM2); //??è???êycnt?μTIM_OC1PolarityConfig(TIM2,TIM_ICPolarity_Rising); //??′?2?×?é?éy??}else{TIM2_CAPTURE_STATU = 0;TIM2_CAPTURE_VALUE = 0;TIM_SetCounter(TIM2,0); //éè????êy??′??÷μ??μTIM2_CAPTURE_STATU |= 0x40; //±ê??2?×?μ?á?é?éy?? TIM_OC1PolarityConfig(TIM2,TIM_ICPolarity_Falling); //éè????′?2?×????μ??}}TIM_ClearITPendingBit(TIM2,TIM_IT_CC1 | TIM_IT_Update); //??3y?D??±ê????
}
(4)?? main:
#include "stm32f10x.h"
#include "USART.h"
#include "led.h"
#include "delay.h"
#include "time_capture.h"
#include <stdio.h>extern u8 data;int main(void)
{int i;u32 temp = 0;//?D??ó??è??·?×é£oNVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//3?ê??ˉ′??úUSART1:usart_init(9600);//LED_Init();//KEY_Init();TIME_CAPTURE_Init(0xFFFF,72 - 1);//GPIO_ResetBits(GPIOA,GPIO_Pin_8);//GPIO_ResetBits(GPIOD,GPIO_Pin_2);printf("?óêüμ?μ?êy?Y:\r\n");delay_ms(10);while(1){//printf("test\r\n");delay_ms(10);if(TIM2_CAPTURE_STATU & 0X80) //2?×?μ???μ???{//printf("test2.0\r\n");temp = TIM2_CAPTURE_VALUE & 0x3F;temp *= 65536;temp += TIM2_CAPTURE_VALUE;printf("high = %d us\r\n",temp);TIM2_CAPTURE_STATU = 0; //?a????ò?′?2???}}
}
5.運行結果:根據按鍵按鍵的時間,計數高電平的時間。
?6.總結:通過定時器捕獲可以測量脈沖寬度或者測量頻率。定時器的捕獲配置,主要是配置相關的寄存器,并重寫定時器中斷服務函數,在中斷服務函數中書寫數據捕獲的邏輯。