假设设计一个简单的数字手表,它的功能只是显示时间,假如您想更改其时区。你会怎么做?您只需按下一个按钮即可切换到菜单,该菜单使您可以更改时区。在这里,系统无法预测您的外部中断对其计时过程的影响,也无法要求您等待,因为它正忙于增加手表的秒数。这时就该用到中断功能了。
中断不必总是外部的。它也可以是内部的。嵌入式中断中的大多数时间也可以促进CPU的两个外设之间的通信。考虑到预设的计时器被重置,并且当时间达到计时器寄存器中的值时触发中断。中断处理程序可用于启动其他外设,如DMA。
在本篇文章中,我们使用了MSP430上的外部中断来切换不同的LED。当使用按钮通过状态改变给出外部中断时,控制权被转移(抢占)到ISR。要了解诸如MSP430G2 Lauchpad开发板的CCS环境设置之类的基础知识,请查看使用CCS开发MSP430入门链接,因为我们不会在本文中对此进行详细介绍。
为什么我们需要中断? 需要中断以节省嵌入式系统中的轮询开销。当需要通过抢占当前正在运行的任务来执行优先级更高的任务时,将调用它们。它还可以用于将CPU从低功耗模式唤醒。当外部信号通过GPIO端口的边沿转换唤醒时,将执行ISR,CPU再次返回低功耗模式。
MSP430中的中断类型 MSP430中的中断分为以下几种类型: 1. 系统复位(System Reset) 2. 不可屏蔽中断(Non-Maskable) 3. 可屏蔽中断(Maskable) 4. 向量中断和非向量中断(Vectored和Non-Vectored)
系统复位: 它可能是由于电源电压(Vcc)和RST / NMI引脚上的低信号(选择了复位模式)引起的,也可能是由于看门狗定时器溢出和违反安全密钥的原因而发生的。
不可屏蔽中断: 这些中断不能被CPU指令屏蔽。一旦启用了通用中断,就不能将不可屏蔽中断从处理中转移。这是由振荡器故障和手动赋予RST / NMI的边沿(在NMI模式下)之类的源产生的。
可屏蔽中断: 如果发生中断,并且可以通过CPU指令屏蔽该中断,则该中断为可屏蔽中断。他们不必总是外部的。它们还取决于外围设备及其功能。此处使用的外部端口中断属于此类别。
向量中断和非向量中断: 向量中断:在这种情况下,中断设备通过传递中断向量地址为我们提供了中断源。在这里,ISR的地址是固定的,控制权转移到该地址,然后由ISR负责其余的工作。 非向量中断:这里所有的中断都有共同的ISR。当来自非向量源的中断发生时,控制权将转移到所有非向量中断共享到的公共地址。
MSP430中的中断程序控制 发生中断时,MCLK变为ON,并且CPU从OFF状态被调用回。中断发生后,由于程序的控制权被转移到ISR地址,因此程序计数器和状态寄存器中的值将移入堆栈。
连续清除状态寄存器,从而清除GIE并终止低功耗模式。通过将中断向量地址放在程序计数器中,可以选择并执行优先级最高的中断。在获得MSP430 GPIO中断示例代码之前,了解其中涉及的端口寄存器的工作非常重要。
MSP430上用于GPIO控制的端口寄存器(Port Register): 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,选择下降沿。
MSP430测试GPIO中断的电路 下面显示了用于测试我们的MSP430中断示例代码的电路。
LED和按钮的地都连接到开发板的地。当按钮被按下时会连接在一起。在LED之前连接一个电阻,以避免LED消耗大量电流。通常,使用100ohm – 220ohm范围内的低电阻。
我们使用3种不同的代码来更好地了解端口中断。前两个代码使用与电路图1相同的电路。让我们深入研究代码。建立硬件连接后,设置如下所示。
MSP430的GPIO中断编程 代码说明如下。在下面的代码中使看门狗定时器停止运行。看门狗定时器通常执行两个操作。一种是通过复位控制器来防止控制器陷入无限循环,另一种是它使用内置计时器触发周期性事件。当微控制器被复位(或加电)时,它处于定时器模式,并且将会在32毫秒后复位MCU。 - WDTCTL = WDTPW + WDTHOLD;
复制代码
将P1DIR寄存器的值设置为0x07可以将pin0、pin1和pin2的方向设置为输出。将P1OUT设置为0x30可以将其配置为在引脚4和引脚5上使能内部上拉电阻的输入。将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)
复制代码以下代码依次切换连接到引脚0、引脚1、引脚2的每个LED。 - if(count%3==0)
- {
- P1OUT ^= BIT1;
- P1IFG &= ~0x30;
- count++;
- }
- else if(count%3==1)
- {
- P1OUT ^= BIT1;
- P1IFG &= ~0x30;
- count++;
- }
- else
- {
- P1OUT ^= BIT2;
- P1IFG &= ~0x30;
- count++;
- }
复制代码
电路图2: 同样,让我们尝试使用其他引脚更好地理解该概念。因此,此处的按钮连接到引脚2.0而不是引脚1.5。修改后的电路如下。同样,该电路用于测试MSP430按钮中断程序。
此处端口2用于输入。因此必须使用不同的中断向量。 P1.4和P2.0读取输入型号。
由于端口2仅用于输入,因此P2DIR设置为0。要在启用内部上拉电阻的情况下将端口2的pin0设置为输入,必须将寄存器P2OUT和P2REN设置为1。在端口2的引脚0上中断并选择中断的边沿,将P2IE和P2IES的值设置为1。复位端口2中的标志,P2IFG被清除,以便可以在端口2上发生中断时再次设置该标志。 当中断源来自端口1时,连接到端口1的引脚1的LED发光。当中断源属于端口2时,连接到端口1的引脚2的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 ànd Debug进入调试模式。
进入调试模式后,按绿色运行按钮可自由运行MCU中已加载的代码。现在,当按下按钮时,边沿的变化会触发中断,从而提示LED状态的变化。
MSP430上的中断程序 成功上传代码后,我们只需使用按钮即可对其进行测试。每当使用按钮发出中断时,LED模式就会根据我们的程序而改变。
希望您喜欢本教程并学到了一些有用的东西。如果您有任何疑问,请在本文下面进行回复。 |