This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] MSP430G2553:设置按钮中断和软件恢复时的行为不一致

Guru**** 2537220 points
Other Parts Discussed in Thread: MSP430G2553

请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/575795/msp430g2553-inconsistent-behavior-re-setting-up-push-button-interrupt-with-software-debounce

部件号:MSP430G2553

你(们)好 我有一个MSP430G2553,我正在使用它开发一个系统,从四个选项中选择一个,使用LED指示当前可选的选项,并使用一个按钮进行选择。 我配置代码的方式,它按预期工作,接近当时的80 %。 我的问题是,鉴于示波器上的轨迹显示观察到的按钮弹跳比软件反跳时间短,有人能看到我如何对其进行错误编码吗?

在代码中,我在连续模式下使用Timer1_A1在4个LED之间循环,并有延迟。 在 重新启用按钮引脚上的中断之前,我使用了一个软件去抖(来自bennthomsen.wordpress.com/engineering-toolbox/ti-msp430-launchpad/using-the-switches/),它使用看门狗计时器设置来创建一个32毫秒的延迟(WDT_MDLY_32)。 将中断设置为在低到高转换时触发,并向上拉引脚,以便按钮在释放时触发中断。 我在这个线路板电路上只观察到少于200 us的弹跳时间,所以要么我没有正确设置按钮,要么我没有正确实施看门狗软件延迟。

感谢您提供的任何帮助!

尼克

#include <MSP430.h>

#define LED1 BIT4
#define LED2 BIT5
#define LED3
BIT1
#define PB1 BIt2

volatile int timeroverflow =0;
volatile int ButtonPressed =0;

void OffturnLeds(void);
/*
main.c
*/
int main(void){
Int selectingLED = 1;
Int ledPostit = 0;
Int myLeds[4]={LED1,LED2,LED3,LED4};

WDTCTL = WDTPW | WDTHOLD;	//停止看门狗计时器
//将端口设置为i/o
P1SEL = 0;
P1SEL2 = 0;
P1DIR ||(LED1 + LED2);
	P1OUT =~(LED1 + LED2);//关闭P2SEL

	= 0;
P2SEL2 = 0;
P2DIR ||(LED3 + LED4);
	P2OUT =~(LED3 + LED4);//关闭这些功能

//首先打开此LED
P1OUT = LED1;

//设置按钮
P2DIR &=~PB1;//设置为输入引脚
P2REN |= PB1;//启用上/下拉电阻器
P2OUT |= PB1;//选择上拉
P2IES &=~PB1;//启用中断以在上升边缘触发
P2IFG &=~PB1;//清除中断标志
P2IE |= PB1;//在此引脚上启用中断
	/*
	MC_2连续向上,ID_3输入除以8,tassel_2 SMCLK,启用中断
	*/
	TA1CTL = MC_2 + tassel_2 + ID_3 + TAIE;
__enable_interrupt ();
	for (;)
	{
	int lpbPressed = pushButtonPressed;
	IF (lpbPressed == 1)
	{
	IF (选择LED == 1)
	{
	//禁用计时器中断
	TA1CTL &=~TAIE;
	选择LED =0;
	其他{
	//启用计时器中断并返回显示LED
	TA1CTL |= TAIE;
	选择LED = 1;
	//turnOffLeds();
	}
	pushButtonPressed = 0;
	//启用按钮中断
	P2IE |= PB1;
	}
	IF (时间溢出== 1)
	{
	时间溢出=0;
	//关闭所有LED
	TurnOffLeds();
	如果(ledPostit < 2)//检查端口1
	{
	P1OUT |= myLeds[ledPost];
	}else {//必须为port2
	P2OUT |= myLeds[ledPosit];
	}
	IF (ledPostit > 2)
	{
	ledPostit = 0;
	其他{
	ledPostit = ledPostit + 1;
	}
	}
	}返回
	0;
}
作废TurnOffLeds(void){

P1OUT &=~(LED1 + LED2);
P2OUT &=~(LED3 + LED4);
}
#pragma vector = port2_vector
__interrupt void port2_isr (void)
{
P2IFG &=~PB1;//清除标志
P2IE &=~PB1;//禁用中断
/*
WDTCTL = WDT_MDLY_32;//启动并设置分退退弹的WD计时器
IFG1 &=~WDTIFG;//清除标志
IE1 |= W技工 经;//启用WDT中断
*/
pushButtonPressed =1;
}
#pragma vector = WDT_vector
__interrupt void WDT_ISR(void)
{
IE1 &=~WTIE;//禁用WDT
IFG1 &=~WDTIFG;//清除标志
WDTCTL = WDTPW | WDTHOLD;//停止WD
//启用按钮中断
P2IE |= PB1;
}
#pragma vector = Timer1_A1_vector
__interrupt void Timer1_A1_ISR (void)
{
静态内部计时器计数器=0;
开关(TA1IV){
情况10://OVERFLOW TA1IFG
{
IF (时间计数器== 3)
{
时间溢出= 1;
计时器计数器=0;
其他{
timerCounter = timerCounter + 1;
}
中断;
}
默认:
//抱歉
中断;
}
} 

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    哇,这个代码示例在我的上述问题中有一个问题。 在我的工作副本中,port2_isr没有注释出监视程序计时器的激活。 它应显示为...

    #pragma vector = port2_vector
    __interrupt void port2_isr (void){
    
    P2IFG &=~PB1;//清除标志
    P2IE &=~PB1;//禁用中断
    
    WDTCTL = WDT_MDLY_32;//启动并设置分退退弹的WD计时器
    IFG1 &=~WDTIFG;//清除标志
    IE1 |= W技工 经;//启用WDT中断
    
    pushButtonPressed = 1;
    }
    

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    问题到底是什么? 中断不会被调用吗?
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    问得好。 每次松开按钮时都会调用port2_isr。 为变量pushButtonPressed分配了值1,并在条件IF (lpbPressed ==1)结束时清除该变量的代码。 当行为与设计不一致时 ,似乎已再次设置P2IFG (或从不在WDT_ISR中清除),条件IF中的代码(lpbPressed ==1) 将立即再次运行,从而将系统重置为释放按钮之前的现有状态。

    我将代码(在当前配置中)包含在本回复中,以避免混淆。 感谢您的参与!

    #include <MSP430.h>
    
    #define LED1 BIT4
    #define LED2 BIT5
    #define LED3
    BIT1
    #define PB1 BIt2
    
    volatile int timeroverflow =0;
    volatile int ButtonPressed =0;
    
    void OffturnLeds(void);
    /*
    main.c
    */
    int main(void){
    Int selectingLED = 1;
    Int ledPostit = 0;
    Int myLeds[4]={LED1,LED2,LED3,LED4};
    
    WDTCTL = WDTPW | WDTHOLD;	//停止看门狗计时器
    //将端口设置为i/o
    P1SEL = 0;
    P1SEL2 = 0;
    P1DIR ||(LED1 + LED2);
    	P1OUT =~(LED1 + LED2);//关闭P2SEL
    
    	= 0;
    P2SEL2 = 0;
    P2DIR ||(LED3 + LED4);
    	P2OUT =~(LED3 + LED4);//关闭这些功能
    
    //首先打开此LED
    P1OUT = LED1;
    
    //设置按钮
    P2DIR &=~PB1;//设置为输入引脚
    P2REN |= PB1;//启用上/下拉电阻器
    P2OUT |= PB1;//选择上拉
    P2IES &=~PB1;//启用中断以在上升边缘触发
    P2IFG &=~PB1;//清除中断标志
    P2IE |= PB1;//在此引脚上启用中断
    	/*
    	MC_2连续向上,ID_3输入除以8,tassel_2 SMCLK,启用中断
    	*/
    	TA1CTL = MC_2 + tassel_2 + ID_3 + TAIE;
    __enable_interrupt ();
    	for (;)
    	{
    	int lpbPressed = pushButtonPressed;
    	IF (lpbPressed == 1)
    	{
    	IF (选择LED == 1)
    	{
    	//禁用计时器中断
    	TA1CTL &=~TAIE;
    	选择LED =0;
    	其他{
    	//启用计时器中断并返回显示LED
    	TA1CTL |= TAIE;
    	选择LED = 1;
    	}
    	pushButtonPressed = 0;
    	}
    	IF (时间溢出== 1)
    	{
    	时间溢出=0;
    	TurnOffLeds();
    	如果(ledPostit < 2)//检查端口1
    	{
    	P1OUT |= myLeds[ledPost];
    	}else {//必须为port2
    	P2OUT |= myLeds[ledPosit];
    	}
    	IF (ledPostit > 2)
    	{
    	ledPostit = 0;
    	其他{
    	ledPostit = ledPostit + 1;
    	}
    	}
    	}返回
    	0;
    }
    作废TurnOffLeds(void){
    
    P1OUT &=~(LED1 + LED2);
    P2OUT &=~(LED3 + LED4);
    }
    #pragma vector = port2_vector
    __interrupt void port2_isr (void)
    {
    P2IFG &=~PB1;//清除标志
    P2IE &=~PB1;//禁用中断
    
    WDTCTL = WDT_MDLY_32;//启动并设置分退退弹的WD计时器
    IFG1 &=~WDTIFG;//清除标志
    IE1 |= W技工 经;//启用WDT中断
    
    pushButtonPressed =1;
    }
    #pragma vector = WDT_vector
    __interrupt void WDT_ISR(void)
    {
    IE1 &=~WTIE;//禁用WDT
    IFG1 &=~WDTIFG;//清除标志
    WDTCTL = WDTPW | WDTHOLD;//停止WD
    //启用按钮中断
    P2IE |= PB1;
    }
    #pragma vector = Timer1_A1_vector
    __interrupt void Timer1_A1_ISR (void)
    {
    静态内部计时器计数器=0;
    开关(TA1IV){
    情况10://OVERFLOW TA1IFG
    {
    IF (时间计数器== 3)
    {
    时间溢出= 1;
    计时器计数器=0;
    其他{
    timerCounter = timerCounter + 1;
    }
    中断;
    }
    默认:
    //抱歉
    中断;
    }
    } 

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    我应该补充一点,正如最近的代码示例所示,我正在清除port2_ISR中的P2IFG (而不是我在回复文本中指明的WDT_ISR)。 即使我在port2_ISR和WDT_ISR中清除了P2IFG,该行为仍然表明pushButtoPressed变量在IF (lpbPressed ==0)条件的末尾没有被指定为0,或者P2IFG在没有第二次按下/释放按钮的情况下以某种方式重置。 因此,在单个按钮按下/释放时,pushButtonPressed变量在port2_isr中设置,在IF(lpbPressed ==0)条件下清除,并在某个位置再次设置,以便状态返回到释放按钮之前的状态。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    好的,我通过在port2_isr中禁用timerA1而不是在IF (selectingLED ==1)条件下,解决了这一问题。 我将此线程保持打开一段时间,看看是否有人可以指出设计中的错误。 谢谢你。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    似乎已再次设置P2IFG

    弹跳会在随机时间产生大量边线。 正确的弹跳算法必须能够随时处理P2IFG变化。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    WDT在P2IE中重新启用PB1中断之前通常会产生32毫秒的等待时间,正如我所指出的,示波器轨迹仅显示小于200 us的弹跳。 我是否可能设置了错误的WDT。 在重新启用PB1中断之前,我是否应该通过切换我可以监控的引脚来验证时间延迟?