c - 如何为以下 CCS IDE MSP432P401R Launchpad 微控制器代码启用 Timer_A0 模块?
问题描述
我有以下任务代码,该任务要求我使用以下代码来使用 CCS IDE 中的 Timer_A0 模块来控制使用 MSP432P401R 启动板作为控制单元的机器人的电机速度。如何在下面的 C 编程代码中初始化 Timer_A0 模块?:
#include "driverlib.h"
#include "mechrev.h"
/* Define macros and function prototypes if needed */
#define BTN1_PIN GPIO_PORT_P1,GPIO_PIN1
#define BTN2_PIN GPIO_PORT_P1,GPIO_PIN4
#define ENB1_PIN GPIO_PORT_P1,GPIO_PIN6
#define ENB2_PIN GPIO_PORT_P1,GPIO_PIN7
#define PWM1_PIN GPIO_PORT_P2,GPIO_PIN4
#define PWM2_PIN GPIO_PORT_P2,GPIO_PIN5
#define PWM3_PIN GPIO_PORT_P2,GPIO_PIN6
#define PWM4_PIN GPIO_PORT_P2,GPIO_PIN7
#define BMP0_PIN GPIO_PORT_P4,GPIO_PIN0
#define BMP7_PIN GPIO_PORT_P4,GPIO_PIN7
#define BMP2_PIN GPIO_PORT_P4,GPIO_PIN2
#define BMP6_PIN GPIO_PORT_P4,GPIO_PIN6
#define BMP3_PIN GPIO_PORT_P4,GPIO_PIN3
#define BMP5_PIN GPIO_PORT_P4,GPIO_PIN5
#define BTN3_PIN GPIO_PORT_P4, GPIO_PIN0 | GPIO_PIN7
#define BTN4_PIN GPIO_PORT_P4, GPIO_PIN2 | GPIO_PIN6
#define BTN5_PIN GPIO_PORT_P4, GPIO_PIN3 | GPIO_PIN5
/* Define configuration structs if needed */
/* Declare global variables if needed */
int i = 0;
uint32_t counter = 0;
/* Main program */
void main(void)
{
/* Stop Watchdog Timer */
WDT_A_holdTimer();
/* Call the mechrev_setup function included in the mechrev.h header file */
mechrev_setup();
/* Initialize GPIOs P1.1 and P1.4 for PushButtons (S1 and S2 switches) */
MAP_GPIO_setAsInputPinWithPullUpResistor(BTN1_PIN);
MAP_GPIO_setAsInputPinWithPullUpResistor(BTN2_PIN);
/* Initialize GPIOs P1.6 and P1.7 for Motor Driver IC Enable Pins */
MAP_GPIO_setAsOutputPin(ENB1_PIN);
MAP_GPIO_setAsOutputPin(ENB2_PIN);
/* Initialize GPIOs P2.4, P2.5, P2.6 and P2.7 for PWM functionality */
MAP_GPIO_setAsInputPin(PWM1_PIN);
MAP_GPIO_setAsInputPin(PWM2_PIN);
MAP_GPIO_setAsInputPin(PWM3_PIN);
MAP_GPIO_setAsInputPin(PWM4_PIN);
/* Initialize Timer A0 to generate PWM signals */
(Timer_A0 module needs to be initialized here)
/* Declare local variables if needed */
/* Call the initialization grading macro */
MACRO_LAB4_INIT();
while(1)
{
/* Design a Polling process to detect PushButtons press and adjust the PWM duty cycles
accordingly */
if (MAP_GPIO_getInputPinValue(BTN1_PIN) == GPIO_INPUT_PIN_LOW)
{
if(i == 1)
{
TA0CCR1 = 999;
TA0CCR2 = 0;
TA0CCR3 = 999;
TA0CCR4 = 0;
}
if(i == 2)
{
TA0CCR1 = 1998;
TA0CCR2 = 0;
TA0CCR3 = 1998;
TA0CCR4 = 0;
}
if(i == 3)
{
TA0CCR1 = 3000;
TA0CCR2 = 0;
TA0CCR3 = 3000;
TA0CCR4 = 0;
}
for (i=0; i<10000; i++); // switch debouncing
}
else if (MAP_GPIO_getInputPinValue(BTN2_PIN) == GPIO_INPUT_PIN_LOW)
{
if(i == 1)
{
TA0CCR1 = 0;
TA0CCR2 = 999;
TA0CCR3 = 0;
TA0CCR4 = 999;
}
if(i == 2)
{
TA0CCR1 = 0;
TA0CCR2 = 1998;
TA0CCR3 = 0;
TA0CCR4 = 1998;
}
if(i == 3)
{
TA0CCR1 = 0;
TA0CCR2 = 3000;
TA0CCR3 = 0;
TA0CCR4 = 3000;
}
for (i=0; i<10000; i++); // switch debouncing
}
else
{
TA0CCR1 = 0;
TA0CCR2 = 0;
TA0CCR3 = 0;
TA0CCR4 = 0;
}
/* Note: Call the event grading macro after changing PWMs */
MACRO_LAB4_EVENT();
}
}
void PORT4_IRQHandler(void)
{
/* Check the interrupt status */
uint32_t status;
status = MAP_GPIO_getEnabledInterruptStatus(GPIO_PORT_P4);
if (status)
{
if(MAP_GPIO_getInputPinValue(BMP0_PIN) == GPIO_INPUT_PIN_LOW ||
MAP_GPIO_getInputPinValue(BMP7_PIN) == GPIO_INPUT_PIN_LOW)
{
i = 1;
counter++;
}
else if (MAP_GPIO_getInputPinValue(BMP2_PIN) == GPIO_INPUT_PIN_LOW ||
MAP_GPIO_getInputPinValue(BMP6_PIN) == GPIO_INPUT_PIN_LOW)
{
i = 2;
counter++;
}
else if (MAP_GPIO_getInputPinValue(BMP3_PIN) == GPIO_INPUT_PIN_LOW ||
MAP_GPIO_getInputPinValue(BMP5_PIN) == GPIO_INPUT_PIN_LOW)
{
i = 3;
counter++;
}
}
else
{
counter++;
}
MACRO_LAB3_EVENT();
/* Clear the PORT4 interrupt flag */
MAP_GPIO_clearInterruptFlag(GPIO_PORT_P4, status);
}
解决方案
在配置定时器本身之前,您需要初始化一个用于配置定时器的结构(upmode、updownmode、连续模式所需的值略有不同)。您可以下载MSP432 器件的 Driverlib 手册 MSP432 DriverLib,其中包含定时器的详细使用。
另一个非常有用的教程是中断、定时器和调试
您在代码中混合了 Driverlib 名称和寄存器级名称。没关系,只要确保命名法正确,不要将寄存器访问名称与用户变量等混淆。
现在,要配置您的计时器Timer_A0
,您需要初始化一个结构以使用配置时间。在 up 模式下配置计时器的示例是:
/* TimerA0 UpMode Configuration Parameter */
const Timer_A_UpModeConfig upConfigTA0 =
{
TIMER_A_CLOCKSOURCE_ACLK, /* ACLK Clock 32 KHz (uint_fast16_t clockSource) */
TIMER_A_CLOCKSOURCE_DIVIDER_1, /* Rollover in 1 sec (uint_fast16_t clockSourceDivider) */
ACLKMAX, /* 32767 ticks (uint_fast16_t timerPeriod) */
TIMER_A_TAIE_INTERRUPT_DISABLE, /* Rollover TAIE (uint_fast16_t timerInterruptEnable_TAIE) */
TIMER_A_CCIE_CCR0_INTERRUPT_ENABLE, /* CCR0 CCR0IE (uint_fast16_t captureCompareInterruptEnable_CCR0_CCIE) */
TIMER_A_DO_CLEAR /* Clear Timer (uint_fast16_t timerClear) */
};
以上定时器配置为使用ACLK
(32KHz),但您也可以使用SMCLK
。
在您的代码中,您需要使用上面的结构配置计时器。例如:
/* Configuring TimerA0 for Up Mode */
MAP_Timer_A_configureUpMode (TIMER_A0_BASE, &upConfigTA0);
您还可以配置/设置您计划使用的任何其他定时器中断,例如
/* Set Capture/Compre Register 3 */
MAP_Timer_A_setCompareValue (TIMER_A0_BASE, MPUCCR, MPUCCRTICKS);
/* enable CCRn compare interrupt */
MAP_Timer_A_enableCaptureCompareInterrupt (TIMER_A0_BASE, MPUCCR);
至此,您已配置好定时器和中断并读取使用,但定时器尚未启动。在定时器和中断激活之前,您必须启动定时器本身。通常,您在进入程序循环(while (1) { ... }
循环)之前就执行此操作。这样,您可以配置其他外围设备,而不会在您完成所有配置之前开始触发中断。一切都配置好后,启动定时器:
/* Starting the Timer_A0 in up mode (just before while loop) */
MAP_Timer_A_startCounter (TIMER_A0_BASE, TIMER_A_UP_MODE);
对于每个定时器,您都有两个由 driverlib 提供的主要中断服务例程。第一个处理CCR0
并命名TA0_0_IRQHandler()
为Timer_A0
(或TA1_0_IRQHandler
为Timer_A1
等))。它的声明是:
/**
* Timer A0 CCR0 Interrupt
*/
void TA0_0_IRQHandler(void)
{
...
}
与定时器相关的所有其他中断都使用TA0_N_IRQHandler()
. 例如捕获/比较寄存器CCR1
-CCR5
和TAIE
翻转中断(一个时钟周期之后CCR0
)。它有一个声明
/**
* Timer A0 Interrupt Handler (remaining interrupts)
*/
void TA0_N_IRQHandler(void)
{
...
}
由于您要控制机械臂,我想您将使用定时器进行 PWM 控制。本教程很好地涵盖了这一点。
我在MSP432 PWM Control of Tri-Color LED上放置了使用 Timer_A 在 pastebin 上驱动 PWM 的完整示例。这显示了使用 upmode 来驱动 PWM。
不要使用函数调用或计算密集型代码重载中断函数。它们是有效的信号处理器。您希望避免在 ISR(中断服务请求)函数中进行耗时的处理。相反,最好的方法是在中断函数中设置一个标志来完成程序循环中的处理,例如
/* Starting the Timer_A0 in up mode */
MAP_Timer_A_startCounter (TIMER_A0_BASE, TIMER_A_UP_MODE);
while (1)
{
if (btn1pressed) { /* respond to button presses by calling button handlers */
btn1_handler();
}
if (btn2pressed) {
btn2_handler();
}
if (getmpudata) { /* retrieve data from MPU9250 */
get_MPU_data();
}
if (getmagdata) { /* retrieve data from AK8963 */
get_MAG_data();
}
...
上面,if (...)
语句中包含的每个变量名称只是bool
在中断函数中设置的变量,它们告诉您的程序是时候处理它们触发的任何函数了。处理main()
不是在中断函数中完成的。原因是中断函数中的大量计算可能会导致在处理完成之前再次触发中断(您的代码花费的时间比中断之间的时间长)。这是使您的程序崩溃的可靠方法。
driverlib 用户指南是配置所有外围设备的金矿。看看你是否可以让你的计时器工作并查看我上面提供的教程链接。如果您还有其他问题,请告诉我。
推荐阅读
- javascript - datalist 上的事件监听器 (html,css.javascript)
- graphql - 在 relay.refetch 之后 UI 没有改变
- python - 订阅者 ROS 节点上的数学运算
- arrays - 如何在scala中传递和返回一个数组
- apache - ProxyPass 到 2 个基于域名的不同本地网络机器
- assembly - FASM 可执行文件和 AV 误报
- python - python dispy 无法将我的函数分布在节点上
- reactjs - 从 docker 容器连接到 VPN 后面的服务
- node.js - 如何在快递中的多条路线之间传递数据?
- javascript - useState Hook 在 setState 上渲染整个组件