所用開發板:MSP432P401R
今日在此更新一下編碼器測速的定時器捕獲寫法,之前學習時竟然忘記更新了~~
本文講如何用定時器的通道來 捕獲編碼器的脈沖信號數量,不提供速度路程的計算方式,
文章提供源碼,測試工程下載;
實踐內容:
1.使用定時器TA2捕獲四個輪子編碼器的信號
2.上升下降沿都捕獲
3.串口定時反饋捕獲值
程序編寫:
程序設計方面十分簡單,分為以下步驟,每個步驟有一些注意點:
一、初始化定時器:
??????????? 1.關閉定時溢出中斷,開啟捕獲事件的中斷
??????????? 2.選擇合適的定時器頻率,略高于編碼器最大頻率即可
??????? ? ? 3.四個通道除了引腳不同,初始化基本一樣,結構體名稱改改就行
??????????? 4.設置為上升沿、下降沿、上升下降沿,三種捕獲模式之一,(本文設置為上升下降都捕獲 ?? )
二、捕獲事件中斷服務函數:
??????????? 1.因為之前關閉了 定時溢出中斷,所以void TA2_N_IRQHandler(void)的進入條件只有捕獲事件到來時:(本文捕獲事件為:上升下降都是捕獲事件 ?? ),就會進一次中斷
???????????? 2.定時器配置捕獲后,可以通過讀取TAxIV寄存器來判斷是哪個通道傳來的捕獲事件,借此對其計數。(本文是定時器2,因此讀取TA2IV)
???????????? 3. ?? ?
?有關TAxIV寄存器介紹在801頁
?1.初始化定時器TA2四條通道的捕獲:
注意點在之前說過了:
開啟定時器計時,但關閉計時溢出中斷
選擇合適的計時溢出頻率,這決定了捕獲的采樣率,比編碼器脈沖頻率快就行,當然,直接定時器48M也是沒有問題的
四條通道初始化相同的
開啟TA2端口中斷 ??? MAP_Interrupt_enableInterrupt(INT_TA2_N);
//定時器TA2捕獲初始化:
void TA2_CAP_init(void)
{//四個通道初始化輸入MAP_GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5,GPIO_PIN6,GPIO_PRIMARY_MODULE_FUNCTION); MAP_GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5,GPIO_PIN7,GPIO_PRIMARY_MODULE_FUNCTION); MAP_GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P6,GPIO_PIN6,GPIO_PRIMARY_MODULE_FUNCTION); MAP_GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P6,GPIO_PIN7,GPIO_PRIMARY_MODULE_FUNCTION); //定時器連續計數模式初始化,關閉定時溢出中斷const Timer_A_ContinuousModeConfig continuousModeConfig ={TIMER_A_CLOCKSOURCE_SMCLK,TIMER_A_CLOCKSOURCE_DIVIDER_1, //1分頻,分辨率最高48MTIMER_A_TAIE_INTERRUPT_DISABLE, TIMER_A_SKIP_CLEAR};
//初始化通道1:const Timer_A_CaptureModeConfig captureModeConfig_1 ={TIMER_A_CAPTURECOMPARE_REGISTER_1, TIMER_A_CAPTUREMODE_RISING_AND_FALLING_EDGE,TIMER_A_CAPTURE_INPUTSELECT_CCIxA,TIMER_A_CAPTURE_SYNCHRONOUS,TIMER_A_CAPTURECOMPARE_INTERRUPT_ENABLE,TIMER_A_OUTPUTMODE_OUTBITVALUE};
//初始化通道2:const Timer_A_CaptureModeConfig captureModeConfig_2 ={TIMER_A_CAPTURECOMPARE_REGISTER_2, TIMER_A_CAPTUREMODE_RISING_AND_FALLING_EDGE,TIMER_A_CAPTURE_INPUTSELECT_CCIxA,TIMER_A_CAPTURE_SYNCHRONOUS,TIMER_A_CAPTURECOMPARE_INTERRUPT_ENABLE,TIMER_A_OUTPUTMODE_OUTBITVALUE};
//初始化通道3:const Timer_A_CaptureModeConfig captureModeConfig_3 ={TIMER_A_CAPTURECOMPARE_REGISTER_3, TIMER_A_CAPTUREMODE_RISING_AND_FALLING_EDGE,TIMER_A_CAPTURE_INPUTSELECT_CCIxA,TIMER_A_CAPTURE_SYNCHRONOUS,TIMER_A_CAPTURECOMPARE_INTERRUPT_ENABLE,TIMER_A_OUTPUTMODE_OUTBITVALUE};
//初始化通道4:const Timer_A_CaptureModeConfig captureModeConfig_4 ={TIMER_A_CAPTURECOMPARE_REGISTER_4, TIMER_A_CAPTUREMODE_RISING_AND_FALLING_EDGE,TIMER_A_CAPTURE_INPUTSELECT_CCIxA,TIMER_A_CAPTURE_SYNCHRONOUS,TIMER_A_CAPTURECOMPARE_INTERRUPT_ENABLE,TIMER_A_OUTPUTMODE_OUTBITVALUE}; MAP_Timer_A_initCapture(TIMER_A2_BASE, &captureModeConfig_1);MAP_Timer_A_initCapture(TIMER_A2_BASE, &captureModeConfig_2);MAP_Timer_A_initCapture(TIMER_A2_BASE, &captureModeConfig_3);MAP_Timer_A_initCapture(TIMER_A2_BASE, &captureModeConfig_4);MAP_Timer_A_configureContinuousMode(TIMER_A2_BASE, &continuousModeConfig);MAP_Interrupt_enableInterrupt(INT_TA2_N);MAP_Timer_A_startCounter(TIMER_A2_BASE, TIMER_A_CONTINUOUS_MODE);
}
?2.編寫定時器 中斷服務函數:
代碼中的 Wheel[x].CAPTURE 無須在意,是我給每個輪子定義的結構體,換成普通變量一樣用的,這種高速計數脈沖,需要大家時刻注意溢出問題,以下代碼段的意思就是防止數據溢出不被記錄:
if(Wheel[1].CAPTURE==62700){Wheel[1].CAPTURE=0;Wheel[1].CAT_OUT_TIME++;}
?
//這是捕獲事件中斷服務函數(因為定時器溢出中斷已關閉)
//注意對照引腳看通道,這里通道情況與PWM控制不一樣
void TA2_N_IRQHandler(void)
{uint16_t captureSource = TA2IV;
// 根據捕獲通道來源進行適當的處理
//脈沖計數到62700時剛好車輪轉95圈
//大電機減速比30編碼器11線switch (captureSource) {case 0x02:// 處理TA2 CCR1通道的捕獲中斷Wheel[1].CAPTURE++;if(Wheel[1].CAPTURE==62700){Wheel[1].CAPTURE=0;Wheel[1].CAT_OUT_TIME++;}break;case 0x04:// 處理TA2 CCR2通道的捕獲中斷Wheel[2].CAPTURE++;if(Wheel[2].CAPTURE==62700){Wheel[2].CAPTURE=0;Wheel[2].CAT_OUT_TIME++;} break;case 0x06:// 處理TA2 CCR3通道的捕獲中斷Wheel[3].CAPTURE++;if(Wheel[3].CAPTURE==62700){Wheel[3].CAPTURE=0;Wheel[3].CAT_OUT_TIME++;} break;case 0x08:// 處理TA2 CCR4通道的捕獲中斷Wheel[4].CAPTURE++;if(Wheel[4].CAPTURE==62700){Wheel[4].CAPTURE=0;Wheel[4].CAT_OUT_TIME++;} break;default: break;
}
}
3.32定時器初始化為1s周期,通過串口反饋捕獲情況:
//此句放在初始化,主函數開頭,初始化32定時器為1s周期Tim32_0_Int_Init(47999999,1);//32定時器初始化函數,傳入的aar psc決定了其周期
void Tim32_0_Int_Init(uint32_t aar, uint8_t psc)
{MAP_Timer32_initModule(TIMER32_0_BASE, psc, TIMER32_32BIT, TIMER32_PERIODIC_MODE);MAP_Timer32_setCount(TIMER32_0_BASE, aar);MAP_Timer32_enableInterrupt(TIMER32_0_BASE);MAP_Timer32_startTimer(TIMER32_0_BASE, false); //連續計數模式 falseMAP_Interrupt_enableInterrupt(INT_T32_INT1);
}/* Timer32 ISR 中斷服務函數,1s進一次*/
void T32_INT1_IRQHandler(void)
{MAP_Timer32_clearInterruptFlag(TIMER32_0_BASE);printf("W1_CAP=%d\r\n",Wheel[1].CAPTURE);printf("W2_CAP=%d\r\n",Wheel[2].CAPTURE);printf("W3_CAP=%d\r\n",Wheel[3].CAPTURE);printf("W4_CAP=%d\r\n",Wheel[4].CAPTURE);
}
整體代碼:
#include "main.h"//單個車輪狀態與參數結構體:
Wheel_dat Wheel[5];int main(void)
{inint_all(); //初始化所有模塊while (1){ }
}/* Timer32 ISR */
void T32_INT1_IRQHandler(void)
{MAP_Timer32_clearInterruptFlag(TIMER32_0_BASE);printf("W1_CAP=%d\r\n",Wheel[1].CAPTURE);printf("W2_CAP=%d\r\n",Wheel[2].CAPTURE);printf("W3_CAP=%d\r\n",Wheel[3].CAPTURE);printf("W4_CAP=%d\r\n",Wheel[4].CAPTURE);
}//初始化所有模塊
void inint_all(void)
{SysInit(); //時鐘配置 delay_init(); //delay_ms函數配置uart_init(115200); TA2_CAP_init();Tim32_0_Int_Init(47999999,1);printf("Hello,MSP432!\r\n"); //串口打印測試字符MAP_Interrupt_enableMaster(); // 開啟總中斷
}//串口0服務函數
//串口0接收命令,存在數組中
void EUSCIA0_IRQHandler(void)
{uint32_t status = UART_getEnabledInterruptStatus(EUSCI_A0_BASE);if(status & EUSCI_A_UART_RECEIVE_INTERRUPT_FLAG) //接收中斷{USART0_save[USART0_xb++]=MAP_UART_receiveData(EUSCI_A0_BASE);if(USART0_xb== 20){USART0_xb=0; } //下標最大不超過20if(USART0_save[USART0_xb-1]=='\0'){USART0_flag=1;} //命令以\0結尾}
}//這是捕獲事件中斷服務函數(因為定時器溢出中斷已關閉)
//注意對照引腳看通道,這里通道情況與PWM控制不一樣
void TA2_N_IRQHandler(void)
{uint16_t captureSource = TA2IV;
// 根據捕獲通道來源進行適當的處理
//脈沖計數到62700時剛好車輪轉95圈
//大電機減速比30編碼器11線switch (captureSource) {case 0x02:// 處理TA2 CCR1通道的捕獲中斷Wheel[1].CAPTURE++;if(Wheel[1].CAPTURE==62700){Wheel[1].CAPTURE=0;Wheel[1].CAT_OUT_TIME++;}break;case 0x04:// 處理TA2 CCR2通道的捕獲中斷Wheel[2].CAPTURE++;if(Wheel[2].CAPTURE==62700){Wheel[2].CAPTURE=0;Wheel[2].CAT_OUT_TIME++;} break;case 0x06:// 處理TA2 CCR3通道的捕獲中斷Wheel[3].CAPTURE++;if(Wheel[3].CAPTURE==62700){Wheel[3].CAPTURE=0;Wheel[3].CAT_OUT_TIME++;} break;case 0x08:// 處理TA2 CCR4通道的捕獲中斷Wheel[4].CAPTURE++;if(Wheel[4].CAPTURE==62700){Wheel[4].CAPTURE=0;Wheel[4].CAT_OUT_TIME++;} break;default: break;
}
} //定時器TA2捕獲初始化:
void TA2_CAP_init(void)
{//四個通道初始化輸入MAP_GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5,GPIO_PIN6,GPIO_PRIMARY_MODULE_FUNCTION); MAP_GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5,GPIO_PIN7,GPIO_PRIMARY_MODULE_FUNCTION); MAP_GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P6,GPIO_PIN6,GPIO_PRIMARY_MODULE_FUNCTION); MAP_GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P6,GPIO_PIN7,GPIO_PRIMARY_MODULE_FUNCTION); //定時器連續計數模式初始化,關閉定時溢出中斷const Timer_A_ContinuousModeConfig continuousModeConfig ={TIMER_A_CLOCKSOURCE_SMCLK,TIMER_A_CLOCKSOURCE_DIVIDER_1, //1分頻,分辨率最高48MTIMER_A_TAIE_INTERRUPT_DISABLE, TIMER_A_SKIP_CLEAR};
//初始化通道1:const Timer_A_CaptureModeConfig captureModeConfig_1 ={TIMER_A_CAPTURECOMPARE_REGISTER_1, TIMER_A_CAPTUREMODE_RISING_AND_FALLING_EDGE,TIMER_A_CAPTURE_INPUTSELECT_CCIxA,TIMER_A_CAPTURE_SYNCHRONOUS,TIMER_A_CAPTURECOMPARE_INTERRUPT_ENABLE,TIMER_A_OUTPUTMODE_OUTBITVALUE};
//初始化通道2:const Timer_A_CaptureModeConfig captureModeConfig_2 ={TIMER_A_CAPTURECOMPARE_REGISTER_2, TIMER_A_CAPTUREMODE_RISING_AND_FALLING_EDGE,TIMER_A_CAPTURE_INPUTSELECT_CCIxA,TIMER_A_CAPTURE_SYNCHRONOUS,TIMER_A_CAPTURECOMPARE_INTERRUPT_ENABLE,TIMER_A_OUTPUTMODE_OUTBITVALUE};
//初始化通道3:const Timer_A_CaptureModeConfig captureModeConfig_3 ={TIMER_A_CAPTURECOMPARE_REGISTER_3, TIMER_A_CAPTUREMODE_RISING_AND_FALLING_EDGE,TIMER_A_CAPTURE_INPUTSELECT_CCIxA,TIMER_A_CAPTURE_SYNCHRONOUS,TIMER_A_CAPTURECOMPARE_INTERRUPT_ENABLE,TIMER_A_OUTPUTMODE_OUTBITVALUE};
//初始化通道4:const Timer_A_CaptureModeConfig captureModeConfig_4 ={TIMER_A_CAPTURECOMPARE_REGISTER_4, TIMER_A_CAPTUREMODE_RISING_AND_FALLING_EDGE,TIMER_A_CAPTURE_INPUTSELECT_CCIxA,TIMER_A_CAPTURE_SYNCHRONOUS,TIMER_A_CAPTURECOMPARE_INTERRUPT_ENABLE,TIMER_A_OUTPUTMODE_OUTBITVALUE}; MAP_Timer_A_initCapture(TIMER_A2_BASE, &captureModeConfig_1);MAP_Timer_A_initCapture(TIMER_A2_BASE, &captureModeConfig_2);MAP_Timer_A_initCapture(TIMER_A2_BASE, &captureModeConfig_3);MAP_Timer_A_initCapture(TIMER_A2_BASE, &captureModeConfig_4);MAP_Timer_A_configureContinuousMode(TIMER_A2_BASE, &continuousModeConfig);MAP_Interrupt_enableInterrupt(INT_TA2_N);MAP_Timer_A_startCounter(TIMER_A2_BASE, TIMER_A_CONTINUOUS_MODE);
}
#ifndef _main_h_
#define _main_h_#include <ti/devices/msp432p4xx/driverlib/driverlib.h>
#include "string.h" //C標準庫、字符串處理庫
#include "sysinit.h" //時鐘配置
#include "delay.h" //滴答定時器初始化(提供delay_ms延時)
#include "Public.h"
#include "DATA.h"//單個車輪狀態與參數結構體:
typedef struct wheel_data
{uint16_t Sta; //正反轉狀態,0不轉,2正,1反uint16_t PWM_DIV; //車輪電機占空比6 - 99uint32_t CAT_OUT_TIME; //編碼器 脈沖溢出次數,溢出一次就加一,記錄有幾個65530uint32_t CAPTURE; //編碼器 外部中斷次數記錄最大65530次脈沖,溢出后CAT_OUT_TIME會加一,CAPTURE歸零uint32_t CAPTURE_LAST; //上一次外部中斷次數記錄uint32_t CAPTURE_NEW; //最新外部中斷次數記錄uint32_t DISTANCE; //單輪行駛總路程長度單位cm,最大65535cmuint32_t SPEED; //瞬時速度值存儲,單位cm/s
}Wheel_dat;void inint_all(void); //初始化所有模塊
//定時器TA2捕獲初始化:
void TA2_CAP_init(void);#endif
?測試工程下載:
https://download.csdn.net/download/qq_64257614/88214201?spm=1001.2014.3001.5503