考虑一个简单的数字手表,它被编程为只显示时间,现在想象你想改变它的时区。你会怎么做?您只需按下一个按钮,即可更改为使您能够更改时区的菜单。在这里,系统无法预测您对其计时过程的外部中断,也无法要求您等待,因为它正忙于增加您手表上的秒值。这就是中断派上用场的地方。
中断不一定是外部的;它也可以是内部的。大多数情况下,嵌入式中断还有助于 CPU 的两个外设之间的通信。考虑一个预设定时器被复位,当时间达到定时器寄存器中的值时触发中断。中断处理程序可用于启动其他外设,如 DMA。
在本教程中,我们使用了MSP430 上的外部中断来切换不同的 LED。当使用按钮通过状态改变给出外部中断时,控制权被转移(抢占)到 ISR 并且它完成了必要的工作。
为什么我们需要中断?
需要中断来节省嵌入式系统中的轮询开销。当需要通过抢占当前正在运行的任务来执行优先级较高的任务时调用它们。它也可用于将 CPU 从低功耗模式唤醒。当通过 GPIO 端口被外部信号的边沿转换唤醒时,执行 ISR 并且 CPU 再次返回低功耗模式。
MSP430 中的中断类型
MSP430 中的中断分为以下类型-
系统重置
不可屏蔽中断
可屏蔽中断
向量和非向量中断
系统重置:
它可能由于电源电压 (Vcc) 和选择了复位模式的 RST/NMI 引脚中的低信号而发生,也可能由于看门狗定时器溢出和安全密钥违规等原因而发生。
不可屏蔽中断:
这些中断不能被 CPU 指令屏蔽。一旦启用了通用中断,不可屏蔽的中断就不能从处理中转移。这是由振荡器故障和手动提供给 RST/NMI(在 NMI 模式下)的边沿等源产生的。
可屏蔽中断:
当中断发生时,如果它可以被 CPU 指令屏蔽,那么它就是可屏蔽中断。它们不必总是外部的。它们还依赖于外围设备及其功能。这里使用的外部端口中断属于这一类。
向量中断和非向量中断:
Vectored:在这种情况下,中断设备通过传递中断向量地址为我们提供中断源。这里ISR 的地址是固定的,控制权转移到该地址,ISR 负责其余的工作。
Non-Vectored: 这里所有的中断都有共同的 ISR。当来自非向量源的中断发生时,控制权被转移到所有非向量中断共享的公共地址。
MSP430 中的中断程序控制
当中断发生时,MCLK 开启,CPU 从关闭状态回调。由于在中断发生后程序的控制权被转移到 ISR 地址,程序计数器和状态寄存器中的值被移入堆栈。
连续清除状态寄存器,从而清除 GIE 并终止低功耗模式。通过将中断向量地址放入程序计数器来选择并执行具有最高优先级的中断。在我们了解MSP430 GPIO 中断示例代码之前,了解其中涉及的端口寄存器的工作非常重要。
MSP430 上用于 GPIO 控制的端口寄存器:
PxDIR:端口方向控制寄存器。它允许程序员通过写入 0 或 1 来专门选择其功能。如果一个引脚被选择为 1,则它充当输出。将端口 1 视为 8 位端口,如果将引脚 2 和 3 分配为输出端口,则必须将 P1DIR 寄存器的值设置为 0x0C。
PxIN:它是一个只读寄存器,可以使用该寄存器读取端口中的当前值。
PxOUT:此特定寄存器可用于将值直接写入端口。这只有在上拉/下拉寄存器被禁用时才有可能。
PxREN:它是一个 8 位寄存器,用于启用或禁用上拉/下拉寄存器。当一个引脚在 PxREN 和 PxOUT 寄存器中都设置为 1 时,特定引脚被上拉。
PxSEL 和 PxSEL2:由于 MSP430 中的所有引脚都是多路复用的,因此在使用它之前必须选择特定的功能。当特定引脚的 PxSEL 和 PxSEL2 寄存器都设置为 0 时,则选择通用 I/O。当 PxSEL 设置为 1 时,选择主要外围功能,依此类推。
PxIE:它启用或禁用端口 x 中特定引脚的中断。
PxIES:它选择产生中断的边沿。为 0,选择上升沿,为 1,选择下降沿。
用于测试 GPIO 中断的 MSP430 电路
用于测试我们的MSP430 中断示例代码的 MSP430 电路如下所示。
电路板的接地用于将 LED 和按钮接地。按钮的对角两侧为常开端子,按下按钮时连接。在 LED 之前连接一个电阻器,以避免 LED 的高电流消耗。通常,使用 100 欧姆 - 220 欧姆范围内的低电阻。
我们使用 3 种不同的代码来更好地理解端口中断。前两个代码使用与电路图 1 中相同的电路。让我们深入研究代码。建立连接后,我的设置如下所示。
对 MSP430 进行中断编程
完整的MSP430 中断程序可以在本页底部找到,代码解释如下。
下面的行使看门狗定时器停止运行。看门狗定时器通常执行两个操作。一种是通过重置控制器来防止控制器无限循环,另一种是使用内置计时器触发周期性事件。当微控制器复位(或上电)时,它处于定时器模式,并倾向于在 32 毫秒后复位 MCU。此行阻止控制器执行此操作。
WDTCTL = WDTPW + WDTHOLD;
将P1DIR寄存器设置为值 0x07 将 pin0、pin1 和 pin2 的方向设置为输出。将P1OUT设置为 0x30 可将其配置为在 pin4 和 pin5 上启用内部上拉电阻的输入。将P1REN设置为 0x30 会启用这些引脚上的内部上拉电阻。P1IE使能中断,其中 P1IES 选择从高到低的转换作为这些引脚上的中断沿。
P1DIR |= 0x07;
P1OUT = 0x30;
P1REN |= 0x30;
P1IE |= 0x30;
P1IES |= 0x30;
P1IFG &= ~0x30;
下一行启用低功耗模式并启用状态寄存器中的GIE,以便可以接收中断。
__bis_SR_register(LPM4bits+GIE)
程序计数器使用宏设置为端口 1 向量的地址。
PORT1_VECTOR。
#pragma vector=PORT1_VECTOR
__interrupt void Port_1(void)
下面的代码一个接一个地切换连接到 pin0、pin1、pin2 的每个 LED。
if(count%3==0)
{
P1OUT ^= BIT1;
P1IFG &= ~0x30;
计数++;
}
else if(count%3==1) { P1OUT ^= BIT1; P1IFG &= ~0x30; 计数++; } 其他 { P1OUT ^= BIT2; P1IFG &= ~0x30; 计数++; }
电路图2:
同样,让我们尝试一个不同的引脚来更好地理解这个概念。所以这里的按钮连接到针脚 2.0 而不是针脚 1.5。修改后的电路如下。该电路再次用于测试MSP430 按钮中断程序。
这里的端口 2 用于输入。所以必须使用不同的中断向量。P1.4和P2.0接受输入。
由于端口 2 仅用于输入,P2DIR 设置为 0。要将端口 2 的 pin0 设置为输入并启用内部上拉电阻,寄存器 P2OUT 和 P2REN 必须设置为 1。要启用端口 2 的 pin0 上的中断以及选择中断的边沿,P2IE 和 P2IES 的值设置为 1。要重置端口 2 中的标志,P2IFG 被清除,这样标志可以再次设置在中断的发生。
P2DIR |= 0x00;
P2OUT = 0x01;
P2REN |= 0x01;
P2IE |= 0x01;
P2IES |= 0x01;
P2IFG &= ~0x01;
当中断源来自端口 1 时,连接到端口 1 引脚 1 的 LED 会发光。当中断源属于端口 2 时,连接到端口 1 的 pin2 的 LED 会发光。
#pragma vector=PORT1_VECTOR
__interrupt void Port_1(void)
{
P1OUT ^= BIT1;
P1IFG &= ~0x10;
for(i=0;i《20000;i++)
{
}
P1OUT ^= BIT1;
}
#pragma vector=PORT2_VECTOR
__interrupt void Port_2(void)
{
P1OUT ^= BIT2;
P2IFG &= ~0x01;
for(j=0;j《20000;j++)
{
}
P1OUT ^= BIT2;
}
从 CCS 上传程序到 MSP430
要将项目加载到启动板并对其进行调试,请选择项目,然后单击工具栏中的调试图标。或者,按 F11 或单击 RunàDebug 进入调试模式。
进入调试模式后,按下绿色运行按钮即可在 MCU 中自由运行加载的代码。现在,当按下按钮时,边沿的变化触发中断,从而提示 LED 状态的变化。
MSP430 上的中断程序
代码上传成功后,我们可以通过简单的按钮进行测试。每当使用按钮发出中断时,LED 模式将根据我们的程序发生变化。
#项目1:
#include
整数计数 = 0;
诠释主要(无效)
{
WDTCTL = WDTPW + WDTHOLD;
P1DIR |= 0x07;
P1OUT = 0x30;
P1REN |= 0x30;
P1IE |= 0x30;
P1IES |= 0x30;
P1IFG &= ~0x30;
__bis_SR_register(LPM4_bits + GIE); // 进入带中断的 LPM4
}
// 端口 1 中断服务程序
#pragma 向量=PORT1_VECTOR
__interrupt 无效端口_1(无效)
{
如果(计数%3==0)
{
P1OUT ^= BIT1;
P1IFG &= ~0x30;
计数++;
}
否则 if(count%3==1)
{
P1OUT ^= BIT1;
P1IFG &= ~0x30;
计数++;
}
别的
{
P1OUT ^= BIT2;
P1IFG &= ~0x30;
计数++;
}
}
#项目2:
#include
整数 i, j;
诠释主要(无效)
{
WDTCTL = WDTPW + WDTHOLD;
P1DIR |= 0x06;
P1OUT = 0x10;
P1REN |= 0x10;
P1IE |= 0x10;
P1IES |= 0x10;
P1IFG &= ~0x10;
P2DIR |= 0x00;
P2OUT = 0x01;
P2REN |= 0x01;
P2IE |= 0x01;
P2IES |= 0x01;
P2IFG &= ~0x01;
__bis_SR_register(LPM4_bits + GIE); // 进入带中断的 LPM4
}
// 端口 1 中断服务程序
#pragma 向量=PORT1_VECTOR
__interrupt 无效端口_1(无效)
{
P1OUT ^= BIT1;
P1IFG &= ~0x10;
for(i=0;i<20000;i++)
{
}
P1OUT ^= BIT1;
}
#pragma 向量=PORT2_VECTOR
__interrupt 无效端口_2(无效)
{
P1OUT ^= BIT2;
P2IFG &= ~0x01;
对于(j=0;j<20000;j++)
{
}
P1OUT ^= BIT2;
}
-
led
+关注
关注
240文章
23134浏览量
658375 -
msp430
+关注
关注
180文章
2393浏览量
229185 -
外部中断
+关注
关注
1文章
131浏览量
15801
发布评论请先 登录
相关推荐
评论