Other Parts Discussed in Thread:MSP430F5529
MSP430提供了许多系统复位中断事件,包括掉电复位(BOR),看门狗超时(WDTTO)或高侧电源电压监控(SVSH)等。
发生复位时,复位原因由MSP430 CPU的系统System peripheral (SYS)来记录。像MSP430上的其他分组中断一样,您可以通过读取相关的中断向量寄存器来确定是哪个事件导致了中断,即查看寄存器称为SYSRSTIV(系统复位中断向量)。
中断向量寄存器根据发生的最高优先级事件返回一个数字。例如,对于MSP430F5529上的SYSRSTIV,事件(和关联的枚举)包括:
注意:请查看设备的相关用户指南和数据表,以获取准确的SYSRSTIV寄存器描述。
1. 读取SYSRSTIV寄存器
在MSP430上处理分组中断的最常见方法是使用switch-case语句读取关联的中断向量寄存器,以获取当前待处理的最高优先级事件。
MSP430F5529 的SYSRSTIV如下所示:
switch ( __even_in_range( SYSRSTIV, SYSRSTIV_PMMKEY ) )
{
case SYSRSTIV_NONE: break; // No Interrupt pending
case SYSRSTIV_BOR: break; // SYSRSTIV : BOR
case SYSRSTIV_RSTNMI: break; // SYSRSTIV : RST/NMI
case SYSRSTIV_DOBOR: break; // SYSRSTIV : Do BOR
case SYSRSTIV_LPM5WU: break; // SYSRSTIV : Port LPM5 Wake Up
case SYSRSTIV_SECYV: break; // SYSRSTIV : Security violation
case SYSRSTIV_SVSL: break; // SYSRSTIV : SVSL
case SYSRSTIV_SVSH: break; // SYSRSTIV : SVSH
case SYSRSTIV_SVML_OVP: break; // SYSRSTIV : SVML_OVP
case SYSRSTIV_SVMH_OVP: break; // SYSRSTIV : SVMH_OVP
case SYSRSTIV_DOPOR: break; // SYSRSTIV : Do POR
case SYSRSTIV_WDTTO: break; // SYSRSTIV : WDT Time out
case SYSRSTIV_WDTKEY: break; // SYSRSTIV : WDTKEY violation
case SYSRSTIV_KEYV: break; // SYSRSTIV : Flash Key violation
case SYSRSTIV_FLLUL: break; // SYSRSTIV : FLL unlock
case SYSRSTIV_PERF: break; // SYSRSTIV : peripheral/config area fetch
case SYSRSTIV_PMMKEY: break; // SYSRSTIV : PMMKEY violation
default: break;
}
2. 在何处使用IV switch-case语句?
如果您已经编写了switch-case语句来处理诸如GPIO端口或计时器之类的中断,那么您应该已经知道如何使用它们。下面是处理GPIO中断的示例。
通常,可以在中断服务程序内部找到switch-case语句。您可以通过执行以下两项操作来创建中断服务程序:
(1)使用__interrupt关键字创建中断函数;
(2) vector pragma会告知MSP430代码生成工具将下一个函数的地址放入中断向量表中。
#pragma vector=PORT1_VECTOR
__interrupt void pushbutton_ISR (void) { switch(__even_in_range( P1IV, 10 ))
{
case 0x00: break; // None
case 0x02: break; // Pin 0
case 0x04: break; // Pin 1
case 0x06: break; // Pin 2
case 0x08: break; // Pin 3
case 0x0A: break; // Pin 4
case 0x0C: break; // Pin 5
case 0x0E: break; // Pin 6
case 0x10: break; // Pin 7
default: _never_executed();
GPIO_toggleOutputOnPin( GPIO_PORT_P1, GPIO_PIN0 );
break;
}
另外由于在运行中断服务程序(ISR)时会禁用中断(默认情况下),因此当您的中断响应代码不仅仅是简单地读取或写入寄存器时,您需要格外小心。如果您的代码涉及更多功能,我们强烈建议您在
ISR函数中设置一个标志,并在main()中处理该事件。
3. 在何处处理SYSRSTIV?
一般来说,第一反应可能是创建一个复位ISR功能,类似于上面显示的GPIO中断示例。但实际上这是不能成功的,主要是因为编译器会忽略下面的语句:
#pragma vector=RESET_VECTOR
即使设备头文件定义了RESET_VECTOR,编译器仍会忽略编译指示。复位向量由C编译器使用函数c_int00()自动处理。该函数会处理各种事情,例如设置堆栈和堆,初始化全局变量和静态变量以及branch到main()。由于用户不会重写此功能,因此最好让编译器忽略RESET_VECTOR #pragma。(您可以在编译器的运行时支持(RTS)库附带的源文件boot.c中找到此函数)
处理SYSRSTIV的最简单方法是将代码放在main()函数的开头。在例子中创建了一个Reset_ISR()函数并从main()调用,如下所示:
void main (void) {
// Stop watchdog timer
WDT_A_hold(WDT_A_BASE);
// Determine the cause of previous reset event
RESET_ISR();
// Initialize GPIO
initGPIO();
while( 1 )
{
__no_operation();
}
}
void Reset_ISR(void) {
switch (__even_in_range(SYSRSTIV, SYSRSTIV_PMMKEY))
{
case SYSRSTIV_NONE: // No Interrupt pending
__no_operation();
break;
case SYSRSTIV_BOR: // SYSRSTIV : BOR
__no_operation();
break;
case SYSRSTIV_RSTNMI: // SYSRSTIV : RST/NMI
__no_operation();
break;
case SYSRSTIV_DOBOR: // SYSRSTIV : Do BOR
__no_operation();
break;
case SYSRSTIV_LPM5WU: // SYSRSTIV : Port LPM5 Wake Up
__no_operation();
break;
case SYSRSTIV_SECYV: // SYSRSTIV : Security violation
__no_operation();
break;
case SYSRSTIV_SVSL: // SYSRSTIV : SVSL
__no_operation();
break;
case SYSRSTIV_SVSH: // SYSRSTIV : SVSH
__no_operation();
break;
case SYSRSTIV_SVML_OVP: // SYSRSTIV : SVML_OVP
__no_operation();
break;
case SYSRSTIV_SVMH_OVP: // SYSRSTIV : SVMH_OVP
__no_operation();
break;
case SYSRSTIV_DOPOR: // SYSRSTIV : Do POR
__no_operation();
break;
case SYSRSTIV_WDTTO: // SYSRSTIV : WDT Time out
__no_operation();
break;
case SYSRSTIV_WDTKEY: // SYSRSTIV : WDTKEY violation
__no_operation();
break;
case SYSRSTIV_KEYV: // SYSRSTIV : Flash Key violation
__no_operation();
break;
case SYSRSTIV_FLLUL: // SYSRSTIV : FLL unlock
__no_operation();
break;
case SYSRSTIV_PERF: // SYSRSTIV : peripheral/config area fetch
__no_operation();
break;
case SYSRSTIV_PMMKEY: // SYSRSTIV : PMMKEY violation
__no_operation();
break;
default: break;
}
}
您可以在上面的__no_operation()处来替换为具体应用程序所需的代码。
注意:编译器提供了一种将代码插入c_int00()重置函数的方法。如果定义的话,则重置函数将调用名为_system_pre_init()的函数。尽管我们的首选是显式地处理main()中的reset event,但是如果有必要,使用pre-init函数可以使您更早地处理事件。
Annie Liu:
我们建议您在发布新问题之前先搜索 E2E支持论坛,E2E支持论坛已经拥有数十万个已得到解答的话题。 这通常是解决问题的最快方法。