MSP432自主开发笔记6:定时器多通道捕获多条编码器线脉冲数

29 篇文章 16 订阅 ¥59.90 ¥99.00

所用开发板: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分频,分辨率最高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);
}

 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); //连续计数模式 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 <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 - 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

  • 15
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 14
    评论
MSP432 低功耗高性能并存10.1 Digital I/O Introduction The digital I/O features include: • Independently programmable individual I/Os • Any combination of input or output • Individually configurable interrupts for ports (available for certain ports only) • Independent input and output data registers • Individually configurable pullup or pulldown resistors • Wake-up capability from ultra-low power modes (available for certain ports only) • Individually configurable high drive I/Os (available for certain I/Os only) Devices within the family may have up to eleven digital I/O ports implemented (P1 to P10 and PJ). Most ports contain eight I/O lines; however, some ports may contain less (see the device-specific data sheet for ports available). Each I/O line is individually configurable for input or output direction, and each can be individually read or written. Each I/O line is individually configurable for pullup or pulldown resistors. Certain ports have interrupt and wake-up capability from ultra-low power modes (see device specific data sheet for ports with interrupt and wake-up capability). Each interrupt can be individually enabled and configured to provide an interrupt on a rising or falling edge of an input signal. All interrupts are fed into an encoded Interrupt Vector register, allowing the application to determine which sub-pin of a port has generated the event. Individual ports can be accessed as byte-wide ports or can be combined into half-word-wide ports. Port pairs P1 and P2, P3 and P4, P5 and P6, P7 and P8, and so on, are associated with the names PA, PB, PC, PD, and so on, respectively. All port registers are handled in this manner with this naming convention. The main exception are the interrupt vector registers, for example, interrupts for ports P1 and P2 must be handled through P1IV and P2IV, PAIV does not exist. When writing to port PA with half-word operations, all 16 bits are written to the port. When writing to the lower byte of port PA using byte operations,

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

NULL指向我

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值