學習stm32已經有一段時間了,接到第一個項目的時候是關于stm32f051的ad配置和da配置,本科時候連51都沒接觸過的人一上來就是32位單片機,著實讓我蛋疼菊緊的很。還好慢慢的啃了中文手冊和網上的一些例程,總算是完成的功能。這些個有時間再整理上傳吧、
之后又弄了些103的東西,今天主要整理一下在進行信號頻率計算的時候遇到的一些問題和解決辦法,以便日后查看。也希望給碰到類似問題的童鞋一些啟發。
實驗要求:使用tim3_etr實現對高頻脈沖的頻率檢測
硬件要求:stm32f103為核心,頻率輸入管腳為PD2(uart5_rx/t3_etr)
剛拿到這個實驗的時候我連tim3是什么東西都不知道,然后查閱手冊對tim3的了解如下:(個人見解)
1.timx可以定時,可以進行輸入捕獲,輸入捕獲可以測頻率可測脈沖寬度,這就是這個實驗要用到的功能
2.timx_CCR1 捕獲/比較使能寄存器是一個比較重要的寄存器,該寄存器用來存儲捕獲發生時TIMx_CNT值,我們從TIMx_CCR1中就可以讀出通道一捕獲發生時刻的TIMx_CNT的值,通過兩次捕獲(上升沿一次,下降沿一次)的差值,就可以計算出高電平脈沖的寬度,f=1/脈寬。不過貌似這只適用于低頻脈沖。我沒有用這種方法。
3.TIMx_etr 是外部觸發的第二種模式,主要用于脈沖計數。我們要用的就是他
大體了解之后就開始在網上找各種代碼來看,大同小異,不過不修改的話都不太能直接用。測頻率無非就是兩個值,一個是基準時間t,一個是脈沖個數n。f = n/t 就OK了
現在要解決的問題,就是如何測量脈沖個數的問題。每一個TIM都一個自己的計數器,和一個自己的預裝載寄存器ARR.這里既然這是為了計數,那么設置ARR的值為0xFFFF,最大值。
配置代碼如下所示
TIM_DeInit(TIM3);
TIM_TimeBaseStructure.TIM_Period =0xFFFF;//當計數器從0記到FFF為一個周期,自動裝載寄存器ARR中的值
TIM_TimeBaseStructure.TIM_Prescaler = 0X00;
TIM_TimeBaseStructure.TIM_ClockDivision = 0x0;//設置時鐘系數 不分頻
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上計數模式
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); // Time base configuration
TIM_ITRxExternalClockConfig(TIM3,TIM_TS_ETRF); //配置外部觸發,否則不會計數
TIM_ETRClockMode2Config(TIM3, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_Inverted, 0);
TIM_SetCounter(TIM3, 0); //設置計數器為0
TIM_Cmd(TIM3, ENABLE);
至此tim3_etr配置完畢。
接下來要解決的問題是如何進行10ms精確定時。使用tim2實現,配置如下
void Tim2_Config(){
TIM_TimeBaseInitTypeDef TIM2_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_DeInit(TIM2);
TIM2_TimeBaseStructure.TIM_Period =10000;
TIM2_TimeBaseStructure.TIM_Prescaler = 71;
TIM2_TimeBaseStructure.TIM_ClockDivision = 0x0;//ÉèÖÃʱÖÓϵÊý ²»·ÖƵ
TIM2_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//ÏòÉϼÆÊýģʽ
TIM_TimeBaseInit(TIM2, &TIM2_TimeBaseStructure); // Time base configuration
TIM_ClearFlag(TIM2,TIM_FLAG_Update);//Çå³þ¸üбê־λ
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE );
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIM_Cmd(TIM2, ENABLE);
}
中斷函數配置如下
void TIM2_IRQHandler(void)
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_Update );
Frequency_value = TIM_GetCounter(TIM3)*10/0.01/1000;//單位khz
TIM_SetCounter(TIM3, 0);
}
}
通過串口發送出去,串口發送配置如下
void uart_Init(void){
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE );
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9|GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1, &USART_InitStructure);
USART_Cmd(USART1, ENABLE);
}
int fputc(int ch, FILE *f){
USART_SendData(USART1, (unsigned char) ch);
//while (!(USART1->SR & USART_FLAG_TXE));
while( USART_GetFlagStatus(USART1,USART_FLAG_TC)!= SET);
return (ch);
}
void UART_send_byte(uint8_t byte)
{
while(!((USART1->SR)&(1<<7)));
USART1->DR=byte;
}
void UART_Send(uint8_t *Buffer, uint32_t Length)
{
TIM_ITConfig(TIM2,TIM_IT_Update,DISABLE ); //此處一定要有否則串口會發送錯誤
while(Length != 0)
{
while(!((USART1->SR)&(1<<7)));//µÈ´ý·¢ËÍÍê
USART1->DR= *Buffer;
Buffer++;
Length--;
}
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE );
}
至此,實驗結束。驗證通過