处理系统复位事件
MSP430提供多个系统复位中断事件。 这些事件包括欠压复位(BOR)、看门狗超时(WDTTO)或监控器高侧欠压(SVSH)等事件。
当一个复位发生时,MSP430 CPU 的系统外设(SYS)记录事件的原因。 与 MSP430上的其他分组中断一样、您可以通过读取相关的中断矢量寄存器来确定引起中断的事件;在这种情况下、该寄存器称为 SYSRSTIV (系统复位中断矢量)。
中断向量寄存器根据发生的最高优先级事件返回一个数字。 例如、对于 MSP430F5529上的 SYSRSTIV、事件(和相关的枚举)包括:
注意:请查看器件的相关用户指南和数据表、了解准确的 SYSRSTIV 寄存器说明。
读取 SYSRSTIV 寄存器
在 MSP430上处理分组中断的最常用方法是使用 switch 语句读取相关的中断矢量寄存器、以解密当前挂起的最高优先级事件。
‘F5529 SYSRSTIV 的示例如下:
switch (__even_in_range (SYSRSTIV、SYSRSTIV_PMMKEY) ){ 案例 SYSRSTIV_NONE: 中断; //无中断挂起 案例 SYSRSTIV_BOR: 中断; // SYSRSTIV:BOR 案例 SYSRSTIV_RSTNMI: 中断; // SYSRSTIV:RST/NMI 案例 SYSRSTIV_DOBOR: 中断; // SYSRSTIV:执行 BOR 案例 SYSRSTIV_LPM5WU: 中断; // SYSRSTIV:端口 LPM5唤醒 案例 SYSRSTIV_SECYV: 中断; // SYSRSTIV:安全违规 案例 SYSRSTIV_SVSL: 中断; // SYSRSTIV:SVSL 案例 SYSRSTIV_SVSH: 中断; // SYSRSTIV:SVSH 案例 SYSRSTIV_SVML_OVP: 中断; // SYSRSTIV:SVML_OVP 案例 SYSRSTIV_SVMH_OVP: 中断; // SYSRSTIV:SVMH_OVP 案例 SYSRSTIV_DOPOR: 中断; // SYSRSTIV:执行 POR 案例 SYSRSTIV_WDTTO: 中断; // SYSRSTIV:WDT 超时 案例 SYSRSTIV_WDTKEY: 中断; // SYSRSTIV:WDTKEY 冲突 案例 SYSRSTIV_KEYV: 中断; // SYSRSTIV:闪存密钥违反 案例 SYSRSTIV_FLLUL: 中断; // SYSRSTIV:FLL 解锁 案例 SYSRSTIV_PERF: 中断; // SYSRSTIV:外设/配置区域获取 案例 SYSRSTIV_PMMKEY: 中断; // SYSRSTIV:PMMKEY 违规 默认值: 中断; }
通过从'430f5529.h'文件复制/粘贴 SYSRSTIV_值来快速创建此切换语句。 每个 MSP430器件都有自己的相关头文件、该文件定义了该器件中的寄存器符号。
您在哪里使用 IV 切换用例语句?
如果您已经编写了 switch case 语句来处理中断,例如 GPIO 端口或计时器,那么您可能已经知道如何使用它们。 作为快速复习,下面是处理 GPIO 中断的示例。
您通常会在中断服务例程中找到切换情况语句。 您可以通过执行两项操作来创建中断服务例程:(1)使用_interrupt 关键字创建中断函数;(2) vector pragma 告知 MSP430代码生成工具将下一个函数的地址放入中断矢量表中。
#pragma vector=Port1_vector __interrupt void button_ISR (void){switch (__even_in_range (P1IV、10)) }{ 情况0x00:中断;//无 情况0x02:中断;//引脚0 情况0x04:中断;//引脚1 情况0x06:中断;//引脚2 案例0x08:中断;//引脚3 情况0x0A:中断;//引脚4 情况0x0C:中断;//引脚5 情况0x0E:中断;//引脚6 情况0x10:中断;//引脚7 默认值:_never_executed(); GPIO_toggleOutputOnPin (GPIO_PORT_P1、GPIO_PIN0); 中断; }
请注意、由于在运行中断服务例程(ISR)时禁用了中断(默认情况下)、因此当您的中断响应代码不仅仅是读取或写入寄存器(如上例所示)时、您需要小心谨慎。 如果您的代码涉及更多,我们强烈建议您在 ISR 函数中设置一个标志,并在 main()中处理事件。
应在何处处理 SYSRSTIV?
您的第一个反应可能是创建一个与上面显示的 GPIO 中断示例类似的复位 ISR 函数。 (…,这是我们试图做的事情 它失败了。)
问题最终是工具忽略以下行:
-
#pragma vector=reset_vector
-
即使器件头文件定义了 RESET_Vector、工具也会忽略 pragma… 这是一件好事。 复位矢量由 C 编译器使用函数 c_int00()自动处理。 此函数处理各种操作,如设置堆栈、初始化全局和静态变量以及分支到 main()。 由于您可能不想从头开始重写此函数,因此这些工具忽略了 RESET_Vector #pragma 是很好的。 (如果您真的很好奇,可以在编译器运行时支持(RTS)库附带的源文件 boot.c 中找到此函数。)
处理 SYSRSTIV 的最简单方法是将代码放置在 main()函数的开头。 在本例中,我们决定创建一个 Reset_ISR()函数并从 main()调用它,如下所示:
void main (void){ //停止看门狗计时器 WDT_A_HOLD (WDT_A_base); //确定先前复位事件 RESET_ISR()的原因; //初始化 GPIO initGPIO(); while (1) { __NO_OPERATION (); } }void Reset_ISR (void){ switch (__even_in_range (SYSRSTIV、SYSRSTIV_PMMKEY) }{ 案例 SYSRSTIV_NONE: //无中断挂起 __no_operation(); 中断; 案例 SYSRSTIV_BOR: // SYSRSTIV:BOR __no_operation(); 中断; 案例 SYSRSTIV_RSTNMI: // SYSRSTIV:RST/NMI __no_operation(); 中断; 案例 SYSRSTIV_DOBOR: // SYSRSTIV:执行 BOR __no_operation(); 中断; 案例 SYSRSTIV_LPM5WU: // SYSRSTIV:端口 LPM5唤醒 __no_operation(); 中断; 案例 SYSRSTIV_SECYV: // SYSRSTIV:安全违规 __no_operation(); 中断; 案例 SYSRSTIV_SVSL: // SYSRSTIV:SVSL __no_operation(); 中断; 案例 SYSRSTIV_SVSH: // SYSRSTIV:SVSH __no_operation(); 中断; 案例 SYSRSTIV_SVML_OVP: // SYSRSTIV:SVML_OVP __no_operation(); 中断; 案例 SYSRSTIV_SVMH_OVP: // SYSRSTIV:SVMH_OVP __no_operation(); 中断; 案例 SYSRSTIV_DOPOR: // SYSRSTIV:执行 POR __no_operation(); 中断; 案例 SYSRSTIV_WDTTO: // SYSRSTIV:WDT 超时 __no_operation(); 中断; 案例 SYSRSTIV_WDTKEY: // SYSRSTIV:WDTKEY 冲突 __no_operation(); 中断; 案例 SYSRSTIV_KEYV: // SYSRSTIV:闪存密钥违反 __no_operation(); 中断; 案例 SYSRSTIV_FLLUL: // SYSRSTIV:FLL 解锁 __no_operation(); 中断; 案例 SYSRSTIV_PERF: // SYSRSTIV:外设/配置区域获取 __no_operation(); 中断; 案例 SYSRSTIV_PMMKEY: // SYSRSTIV:PMMKEY 违规 __no_operation(); 中断; 默认值:中断; } }
当然,您需要用应用程序所需的代码替换上面的__no_operation()调用。
最后、编译器确实提供了一种将代码插入 c_int00()复位函数的方法。 如果已定义、复位函数会调用一个名为_system_pre_init ()的函数。 虽然我们的首选是显式处理 main()中的复位评估,但如果有迫切需要,使用 pre-init 函数可以更早地处理事件。