MSP430 Launchpad教程-第2部分-中断和计时器
什么是“打断这是一个信号,通知我们的MCU某个事件已经发生,从而导致主程序正常流程的中断和“中断例程”的执行,该例程处理该事件并采取指定的措施。
快速链接
- 第1部分: MSP430启动板教程-第1部分-基础
- 第2部分: MSP430 Launchpad教程-第2部分-中断和计时器
- 第3部分: MSP430 LaunchPad教程-第3部分-ADC
- 第4部分: MSP430 LaunchPad教程-第4部分-UART传输
中断对于避免在轮询循环中浪费处理器的宝贵时间,等待外部事件至关重要(实际上,它们用于实时操作系统, 实时操作系统)。
在MSP430架构中,有几种类型的中断:定时器中断,端口中断,ADC中断等等。它们中的每一个都需要启用并配置为工作,并且每个中断都有一个单独的“服务例程”。
在本教程中,我们将看到如何使用计时器和端口中断来刷新某些LED,在下一个教程中,我们将保留ADC中断。因此,让我们编写一些代码!
#包括"msp430g2231.h" void main(void) { WDTCTL = WDTPW + WDTHOLD; // Stop WDT
您应该认识到这些行,我们在上一教程中使用了它们来为我们的MCU添加定义文件,声明主要功能并停止看门狗定时器。
CCTL0 = CCIE; //使能CCR0中断 TACTL = TASSEL_2 + MC_1 + ID_3; // SMCLK / 8,向上模式 CCR0 = 10000; // 12.5 Hz
这是一些有趣的东西。这些行配置计时器中断。我们首先通过将CCTL0寄存器中的CCIE位置1来使能它。
然后我们在TimerA控制寄存器中设置定时器模块的时钟。
如果查看msp430g2231.h文件,可以看到:
- TASSEL_2选择SMCLK(由内部DCO提供,该内部DCO的运行频率约为1 MHz)。
- MC_1选择“ UP模式”,定时器递增到存储在CCR0寄存器中的数字;
- ID_3为提供的时钟选择一个内部8x分频器(在我们的情况下,我们为SMCLK / 8)。
最后,我们设置CCR0寄存器。我们将TimerA模块配置为在溢出和触发中断之前最多计数该寄存器中存储的数量。
通过将其设置为10000,我们得到的溢出频率为12,5 Hz。实际上,我们有(SMCLK / 8)/ 10000 = 12,5。
您可以通过更改此数字来获得多个频率(请记住,MSP430具有16位定时器,因此存储在CCR0寄存器中的值不得大于65535),更改分频器或使用计数器添加if-else块在中断程序中。让我们继续。
P1OUT &= 0x00; //关闭所有内容 P1DIR &= 0x00; P1DIR |= BIT0 + BIT6; // P1.0 and P1.6 pins output the rest are input P1REN |= BIT3; // Enable internal pull-up/down resistors P1OUT |= BIT3; //Select pull-up mode for P1.3
这些行也应该很熟悉,但是有一些补充:首先,我们清除PORT1输出和方向寄存器。然后,我们将P1.0和P1.6引脚设置为输出,其余设置为输入。最后两行启用开关(BIT3)上的上拉电阻,以便正常状态(未按下按钮)将为“ 1”。
P1IE |= BIT3; // P1.3 interrupt enabled P1IES |= BIT3; // P1.3 Hi/lo edge P1IFG &= ~BIT3; // P1.3 IFG cleared
使用这些代码行,我们首先告诉MCU监听P1.3引脚的逻辑状态变化(有效地启用该特定引脚上的中断)。
然后我们在中断产生时选择边沿(从高到低或从低到高)。请记住,LaunchPad上的按钮在按下时将输入引脚连接到GND,而在未按下时将其连接到VCC。因此,我们选择高/低沿。
最后,我们清除该引脚的中断标志。中断标志程序P1IFG在中断发生时进行报告,应在中断服务程序结束时将其清除。
_BIS_SR(CPUOFF + GIE); // Enter LPM0 w/ interrupt while(1) //Loop forever, we do everything with interrupts! {} }
您可能还记得,通过这条线,我们在保持中断使能的同时关闭了CPU,以节省一些电源。然后我们进入一个循环,以确保MCU在执行中断工作时不执行其他操作。
//定时器A0中断服务程序 #pragma vector = TIMERA0_VECTOR __interrupt void Timer_A(void) { P1OUT ^= BIT0; // Toggle P1.0 }
这是TimerA中断服务程序。每当TimerA溢出时,都会执行此例程中插入的代码(请注意特殊声明)。如您所见,我们仅切换P1.0引脚(LaunchPad上的红色指示灯),然后返回正常执行。
//端口1中断服务程序 #pragma vector = PORT1_VECTOR __interrupt void Port_1(void) { P1OUT ^= BIT6; // Toggle P1.6 P1IFG &=~BIT3; // P1.3 IFG cleared }
这是Port1中断服务程序。每次我们按下P1.3按钮时,都会执行此例程中插入的代码(请注意特殊声明)。我们切换P1.6引脚(在LaunchPad上变为绿色),清除P1.3中断标志(非常重要),然后返回正常执行。
编译并编程LaunchPad时,按P1.3按钮时,应该看到红色的LED闪烁,绿色的LED切换。
这是完整的代码,请尽情享受!
#包括"msp430g2231.h" void main(void) { WDTCTL = WDTPW + WDTHOLD; //停止WDT CCTL0 = CCIE; //使能CCR0中断 TACTL = TASSEL_2 + MC_1 + ID_3; // SMCLK / 8,向上模式 CCR0 = 10000; // 12.5赫兹 P1OUT &= 0x00; //关闭所有内容 P1DIR &= 0x00; P1DIR | = BIT0 + BIT6; // P1.0和P1.6引脚输出,其余输入 P1REN | = BIT3; //启用内部上拉/下拉电阻 P1OUT | = BIT3; //为P1.3选择上拉模式 P1IE | = BIT3; //启用P1.3中断 P1IES | = BIT3; // P1.3高/低边缘 P1IFG &=〜BIT3; // P1.3 IFG已清除 _BIS_SR(CPUOFF + GIE); //输入带有中断的LPM0 while(1)//永远循环,我们处理中断! {} } //定时器A0中断服务程序 #pragma vector = TIMERA0_VECTOR __interrupt void Timer_A(void) { P1OUT ^ = BIT0; //切换P1.0 } //端口1中断服务程序 #pragma vector = PORT1_VECTOR __interrupt void Port_1(void) { P1OUT ^ = BIT6; //切换P1.6 P1IFG &=〜BIT3; // P1.3 IFG已清除 }
- 评论
- Write a Comment 选择添加评论

我将示例转换为MSP-EXP430F5529LP,希望对您有所帮助!
#包括“ msp430F5529.h” //包含寄存器和内置函数的定义
#包括
void main(void)
{
WDTCTL = WDTPW + WDTHOLD; //停止WDT
TA0CCTL0 = CCIE; //使能CCR0中断
TA0CTL = TASSEL_2 | MC_1 | ID_3; // SMCLK / 8,向上模式
TA0CCR0 = 10000; //我必须计算出来,但是我很懒
P1OUT &= 0x00; //关闭P1上的引脚
P1DIR &= 0x00; //将P1引脚设置为输出
P1DIR | = BIT0; // P1.0引脚设置为输出,其余输入
P4OUT &= 0x00; //关闭P4上的引脚
P4DIR &= 0x00; //将P4引脚设置为输出
P4DIR | = BIT7; // P4.7引脚设置为输出,其余输入
P2REN | = BIT1; //为P2启用内部上拉/下拉电阻
P2OUT | = BIT1; //为P2.1选择上拉模式
P2IE | = BIT1; //启用P2.1中断
P2IES | = BIT1; // P2.1高/低边缘
P2IFG &=〜BIT1; // P2.1 IFG已清除
_BIS_SR(CPUOFF + GIE); //输入带有中断的LPM0
while(1)//永远循环,我们处理中断!
{}
}
//定时器A0中断服务程序
#pragma vector = TIMER0_A0_VECTOR
__interrupt void Timer_A0(void)
{
P1OUT ^ = BIT0; //切换P1.0
}
//端口2中断服务程序
#pragma vector = PORT2_VECTOR
__interrupt void Port_2(void)
{
静态uint8_t反跳= 0;
while(debounce <= 100)
{
if (~P2IN & BIT1) debounce++;
else debounce = 0;
}
P4OUT ^ = BIT7; //切换P4.7
debounce = 0;
P2IFG &=〜BIT1; // P2.1 IFG已清除
}

#包括
/ *
* main.c
*/
int main(void){
WDTCTL = WDTPW | WDTHOLD; //停止看门狗定时器
TA0CCTL0 = CCIE; / * TA0CCTL0寄存器:如果您打算使用定时器,则需要设置的第一个寄存器是CCTL0。它是一个16位寄存器,该寄存器的设置会影响我们如何使用该寄存器。为了我们的目的,我们只是告诉它使用* /启用中断。
TA0CTL = TASSEL_2 + MC_1 + ID_3; / * TASSEL_2:使用SMCLK MC_1:递增ID_3:除以8 * /
TA0CCR0 = 10000; //最多10000
P1OUT = 0;
P1DIR = BIT0; // P0作为输出
P1REN | = BIT1; //为P1启用上拉/下拉
P1OUT | = BIT1; //拉出P1的分辨率
P4OUT = 0;
P4DIR = 0;
P4DIR= BIT7;
P1IE |= BIT1; //P1.0 interrupt enable
P1IES | = BIT1; //高/低边
P1IFG &=〜BIT1; //清除标志
_BIS_SR(CPUOFF + GIE); //睡觉直到中断
while(1) {}
return 0;
}
//定时器A中断
#pragma vector = TIMER0_A0_VECTOR
__interrupt void TIMER0_A0_ISR(void)
{
P4OUT ^= BIT7;
}
#pragma vector = PORT1_VECTOR
__interrupt void Port_1(void)
{
P1OUT ^= BIT0;
P1IFG &= ~BIT1;
}

非常感谢!



不错的教程。我可以知道你从哪里得到材料吗?我的意思是指令集。谢谢!

我有关于清除中断标志的问题。
为什么我们不需要在Timer的中断服务程序中清除中断标志,而需要在Port1中断服务程序中清除中断标志?

430x2xxx没有IV,并且一次可以设置多个IFG标志,并且如果仅通过读取就清除了所有标志,那么如果对IFG寄存器进行位测试,就不能有多个标志,因此您需要手动清除该位。

#pragma vector = PORT1_VECTOR
__interrupt void Port_1(void)
{
P1OUT ^ = BIT6; //切换P1.6
P1IFG &=〜BIT3; // P1.3 IFG已清除
}
如果按下按钮1.3,则进入ISR,因为为此配置了P1IE和P1IES,然后在例程P1OUT XOR BIT6,P1IFG中将程序返回到“ main()”?我的意思是,ISR本身会结束并自动返回吗?如果很严格,我想如果再按一次该按钮,程序将再次进入ISR。我是说。
但是,当TimerA告诉MCU“去ISR_TimerA例程?_TimerA开始计数,并且在计数结束时,程序将转到ISR_TimerA?如果是的话,哪一行开始对TimerA进行计数。我们如何停止”例如,ISR_TimerA ...在5次相同的中断之后。
我认为我的问题不是那么荒谬。


我不知道为什么它不显示。


我正在尝试获取外部中断并使LED闪烁。但是我收到类似“ pragma vector =接受数字参数或“ unused_interrupts”而不是PORT_VECTOR的错误”
int main(){
//停止看门狗定时器
WDTCTL = WDTPW + WDTHOLD;
P1DIR&=〜BIT4; //配置为输入
P1输出|= BIT4;
P3DIR | = BIT4;
P3OUT|= BIT4;
P1IES = 0x01;
P1IE = 0x01; // 1b =启用相应的端口中断
P1IFG= 0x01; // PxIFG标志设置为高到低过渡
P1REN = 0x01; //启用上拉或下拉
}
#pragma vector = PORT_VECTOR
__interrupt void Port_1(void){
如果((P1IN& BIT4)==0 ){
//将输入读取为GND
P3OUT|= BIT4;
}
否则if((P1IN& BIT4)==1 ){
P3OUT&= ~BIT4;
}
}




上面的例子效果很好。现在,如果我想使用timer_A以不同的频率闪烁2个LED,我该怎么办?
我已将TACCRO = 10000和TACCR1 = 60000
因此,通过TACCTLO = CCIE和TACCTL1 = CCIE允许中断
还提出了两个ISR:
#pragma vector = TIMERA0_VECTOR
__interrupt void ISR1(无效)
{ }
和#pragma vector = TIMERA1_VECTOR
__interrupt void ISR2(无效)
{ }
但它不能正常工作。一个LED指示灯完美闪烁,而另一个则不闪烁。任何人都可以建议。提前致谢。

什么是#
vector = PORT1_VECTOR是什么意思?另外,如果我将2个交换机连接到端口1的2个不同的引脚,并希望为它们执行不同的例程,该如何实现?

大家好,
我为使FR5994的代码工作有点挣扎,所以我认为这可以帮助其他人使用基于fr5994的启动板
// **************************************************** *******************************************
// MSP430闪烁LED演示-软件切换P1.0
//
// MSP430x5994
//-----------------
// / / \\ |辛|-
// | | | |
//--| RST XOUT |-
// | | |
// | | P1.0 |->LED1
// P1.1 |->LED2
// P5.5 |<--P5.5
//
//德州仪器(TI)
// 2013年7月
// **************************************************** *******************************************
#包括<msp430.h>
void main(void)
{
//CLK SETUP
WDTCTL = WDTPW + WDTHOLD; //停止WDT
PM5CTL0 &=〜LOCKLPM5; //禁用GPIO上电默认的高阻抗模式
TA0CCTL0 = CCIE; //使能CCR0中断
TA0CTL = TASSEL_1 + MC_1 + ID_3; // ACLK = 32.768kHz / 8,升频
TA0CCR0 = 4096; // 1Hz赫兹
P1OUT &= 0x00; //关闭所有内容
P1DIR &= 0x00;
P1DIR | = BIT0 + BIT1; // P1.0和P1.1引脚输出,其余为输入。输出用于两个LED
P5REN | = BIT5; //启用内部上拉/下拉电阻
P5OUT | = BIT5; //需要设置上拉高电阻
P5IE | = BIT5; //启用P5.5中断
P5IES | = BIT5; // P5.5高/低边缘
P5IFG &=〜BIT5; //已清除P5.5 IFG
_BIS_SR(CPUOFF + GIE); //输入带有中断的LPM0
while(1)//永远循环,我们处理中断!
{}
}
//定时器A0中断服务程序
#pragma vector = TIMER0_A0_VECTOR
__interrupt void Timer_A0(void)
{
P1OUT ^ = 0x01; //切换P1.0
//TA0CTL &= ~TAIFG;
}
//端口5中断服务程序
#pragma vector = PORT5_VECTOR
__interrupt void Port_1(void)
{
P1OUT ^ = 0x02; //切换P1.1
P5IFG &=〜BIT5; //已清除P5.5 IFG
}

谢谢,将时钟设置为1 Hz非常重要。我想在开发之前,我们应该先看一下时钟源。

你好,恩里科。非常好的系列文章。似乎很多人都在错误:
#2580-D
pragma vector =接受数字参数或“ unused_interrupts”,但
PORT2_Vector”,因为他们尝试使用中断。我在许多论坛上都看过,而且没有一种建议的解决方案似乎真正解决了这个问题。我只是在尝试将端口2的一个引脚拉低时产生一个中断。我已经多次重写代码以尝试不同的端口和不同的引脚,但始终会收到相同的警告。
关于解决方案有什么建议吗?我正在使用CCS 9和MPS430 FR2355评估板。
真诚的,鲍勃

鲍勃,你应该尝试 我们的论坛.

谢谢。我会试一试。


“每个PxREN寄存器中的每个位均启用或禁用相应I / O引脚的上拉/下拉电阻。
PxOUT寄存器中的相应位选择是将引脚上拉(1)还是下拉(0)。”
我在代码中添加了注释,以使其更加清晰,感谢您的举报!


您只需使用P1IE和P1IES寄存器启用引脚中断即可。然后,在PORT1中断例程中,可以使用P1IFG寄存器上的if语句为每个引脚执行不同的代码,这将使您知道已按下了哪个引脚。


我正在使用MPS430g2553控制器,我想从具有5个按键的小键盘上设置时间,它的作用是什么?


#pragma vector = TIMER0_A0_VECTOR
代替
#pragma vector = TIMERA0_VECTOR
定时器中断服务程序,它应该工作。我在10分钟前测试过!

你好,
我想了解这行 #pragma vector = TIMER0_A0_VECTOR does when compiling?





感谢您的教程。我们对代码的解释非常好,而且很容易将代码分解为更简单的理解方式,非常感谢。
我将行“ P1IES | = BIT3;”更改为“ P1IES&=〜BIT3; ,即从上升沿到下降沿。
它按预期工作,..
同时我也尝试过
我将“ P1OUT | = BIT3;”行更改为“ P1OUT&= ~BIT3; ".
如果我是正确的,这是清除位,即。将该位设置为下拉电阻器模式。
输出没有变化。
它应该不起作用,对.. ???!

现在,当按下按钮时,它变低,在轮询中,它用(〜BIT2&P1IN)。使用中断编码如何完成?


我正在g2553上使用此端口和计时器中断程序。
它显示错误为:“ Port”未识别为内部或外部命令。
我还按照g2553.h更改了中断名称,但仍然是相同的错误……
为了 参考...这里 is the code :::
#包括“ msp430g2553.h”
void main(void)
{
WDTCTL = WDTPW + WDTHOLD; //停止WDT
CCTL0 = CCIE; //使能CCR0中断
TACTL = TASSEL_2 + MC_1 + ID_3; // SMCLK / 8,向上模式
CCR0 = 10000; // 12.5赫兹
P1OUT &= 0x00; //关闭所有内容
P1DIR &= 0x00;
P1DIR | = BIT0 + BIT6; // P1.0和P1.6引脚输出,其余输入
P1REN | = BIT3; //启用内部上拉/下拉电阻
P1OUT | = BIT3; //为P1.3选择上拉模式
P1IE | = BIT3; //启用P1.3中断
P1IES | = BIT3; // P1.3高/低边缘
P1IFG &=〜BIT3; // P1.3 IFG已清除
_BIS_SR(CPUOFF + GIE); //输入带有中断的LPM0
while(1)//永远循环,我们处理中断!
{}
}
//定时器A0中断服务程序
#pragma vector = TIMER0_A0_VECTOR
__interrupt void Timer_A(void)
{
P1OUT ^ = BIT0; //切换P1.0
}
//端口1中断服务程序
#pragma vector = PORT1_VECTOR
__interrupt void PORT1_ISR(无效)
{
P1OUT ^ = BIT6; //切换P1.6
P1IFG &=〜BIT3; // P1.3 IFG已清除
}

TA0CTL = TASSEL_2 + MC_1 + ID_3;
TA0CCR0 = 10000;
TA0CCTL0 = CCIE
#pragma vector = TIMER0_A0_VECTOR

要发布对评论的回复,请单击每个评论所附的“回复”按钮。要发布新评论(而不是回复评论),请查看评论顶部的“写评论”标签。
注册后,您可以参加所有相关网站上的论坛,并获得所有pdf下载的访问权限。