所用开发板:MSP432P401R
今日在此更新一下编码器测速的定时器捕获写法,之前学习时竟然忘记更新了~~
本文讲如何用定时器的通道来 捕获编码器的脉冲信号数量,不提供速度路程的计算方式,
文章提供源码,测试工程下载;
1.使用定时器TA2捕获四个轮子编码器的信号
2.上升下降沿都捕获
3.串口定时反馈捕获值
程序设计方面十分简单,分为以下步骤,每个步骤有一些注意点:
一、初始化定时器:
1.关闭定时溢出中断,开启捕获事件的中断
2.选择合适的定时器频率,略高于编码器最大频率即可
3.四个通道除了引脚不同,初始化基本一样,结构体名称改改就行
4.设置为上升沿、下降沿、上升下降沿,三种捕获模式之一,(本文设置为上升下降都捕获 )
二、捕获事件中断服务函数:
1.因为之前关闭了 定时溢出中断,所以void TA2_N_IRQHandler(void)的进入条件只有捕获事件到来时:(本文捕获事件为:上升下降都是捕获事件 ),就会进一次中断
2.定时器配置捕获后,可以通过读取TAxIV寄存器来判断是哪个通道传来的捕获事件,借此对其计数。(本文是定时器2,因此读取TA2IV)
3.
注意点在之前说过了:
开启定时器计时,但关闭计时溢出中断
选择合适的计时溢出频率,这决定了捕获的采样率,比编码器脉冲频率快就行,当然,直接定时器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分频,分辨率最高48M
TIMER_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);
}
代码中的 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;
}
}
//此句放在初始化,主函数开头,初始化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); //连续计数模式 false
MAP_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; } //下标最大不超过20
if(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分频,分辨率最高48M
TIMER_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
#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 - 99
uint32_t CAT_OUT_TIME; //编码器 脉冲溢出次数,溢出一次就加一,记录有几个65530
uint32_t CAPTURE; //编码器 外部中断次数记录最大65530次脉冲,溢出后CAT_OUT_TIME会加一,CAPTURE归零
uint32_t CAPTURE_LAST; //上一次外部中断次数记录
uint32_t CAPTURE_NEW; //最新外部中断次数记录
uint32_t DISTANCE; //单轮行驶总路程长度单位cm,最大65535cm
uint32_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