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**** 2587365 points


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

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/622494/msp430g2553-problem-with-code-for-switch-debounce

器件型号:MSP430G2553

大家好、我正在尝试这个去抖 代码。 使用复位开关(S1)和 Launchpad 开关 P1.3 (S2)。 按下 S1时、绿色 LED 亮起。 按下 S2时、红色 LED 亮起。 如果按下两个开关中的一个超过1.5秒、两个 LED 将亮起、当释放开关时、两个 LED 将关闭。 这是完美的。 我添加了一个外部开关并将其连接到 P2.1 (S3)。 其功能与 launchpad 的 S2相同。 按下按钮 P2.1 (S3)时,检测到脉动,红色 LED 亮起。 然后我释放按钮、但红色 LED 不会熄灭、大约1.5秒后、绿色 LED 也会亮起。 执行此操作后、其他两个按钮(S1和 S2)继续正常工作、但 S3不再检测到任何脉动。 这种情况就好像未检测到按钮 P2.1已被释放、然后 P2.1中的中断似乎被禁用。


为了更容易找到错误、我添加的代码部分是'InitializeSwitch2'方法和最后两条看门狗 ISR 行:

#include "msp430g2553.h"

#define FLIP_HOLD (0x3300 | WDTHOLD) //保留其他位时保持翻转

#define S1 1 //开关1标志掩码
#define S2 2 //开关2标志掩码
#define Moth 3 //两个开关标志掩码
#define PRESSDURATION 47 //长按持续时间47*32ms = 1.5s

//事件*/
#define Switch1 #define Switch1 1 #1



volatile char PressCountS1 = 0;
volatile char PressCountS2 = 0;
volatile char SwitchState = 0;//在中断内部使用标志来存储当前开关状态
volatile char pressed = 0;//用于指示开关的标志 Press
volatile char PressRelease = 0; //用于指示开关按压和释放
易失性字符 longPress = 0的标志;//用于指示开关长按

空配置 WDT (空);
空初始化 Switch2 (空);//开关 P1.3
空初始化3 (空);//开关 P2.1

空主(空)
{
ConfigureWDT();
BCSCTL1 = CALBC1_1MHz;//将 DCO 设置为1MHz
DCOCTL = CALDCO_1MHz;//将 DCO 设置为1MHz

P1DIR |=(BIT0|BIT6);//将 P1.0和 P1.6上的 LED 设置为输出
P1OUT |=(BIT0|BIT6);//打开 P1.0和 P1.6 LED 以指示初始状态

InitializeSwitch2();//初始化连接到 P1.3的 Switch 2
InitializeSwitch3();//初始化连接到 P2.1的 Switch 2

while (1){

IF (预发布)
{

PressRelease 和=~(S1 + S2);//清除开关标志以指示开关按压已被处理
}

_bis_SR_register (LPM0_Bits + GIE);

}
}

void ConfigureWDT (void){
//看门狗计时器(WDT)将用于对 s1和 s2进行去抖
WDTCTL = WDTPW + WDTHOLD + WDTNMIES + WDTNMI;//WDT 密码+停止 WDT +检测 RST 按钮下降沿+将 RST/NMI 引脚设置为 NMI
IFG1 &=~(WDTIFG + NMIIFG);//清除 WDT 和 NMI 中断标志
IE1 |= WDTIE + NMIIE;//启用 WDT 和 NMI 中断
}

//此函数配置按钮,以便
在按下按钮时触发中断*。 这些中断将由 Port1_ISR()*/
void InitializeSwitch2 (void){处理
P1DIR &=~BIT3;//将按钮引脚设置为输入引脚
P1OUT |= BIT3;//为按钮设置上拉电阻
P1REN |= BIT3;//为按钮启用上拉电阻器、以使引脚保持高电平直到按下
P1IES |= BIT3;//启用中断以在下降沿(高电平(未按下)到低电平(按下)转换)触发
P1IFG &=~BIT3;//清除按钮的中断标志
P1IE |= BIT3;//为按钮
启用端口1上的中断}

void InitializeSwitch3 (void){
P2DIR &=~BIT1;//将按钮引脚设置为输入引脚
P2OUT |= BIT1;//为按钮设置上拉电阻
P2REN |= BIT1;//为按钮启用上拉电阻、以使引脚保持高电平直到按下
P2IES |= BIT1;//启用中断以在下降沿(高电平(未按下)到低电平(按下)转换)触发
P2IFG &=~BIT1;//清除按钮的中断标志
P2IE |= BIT1;//为按钮启用端口1上的中断
}


// ISR 在 nRST/NMI 引脚上检测 s1的产生/中断
//注意 NMI 中断的发生会自动禁用 NMI 中断使能。
#pragma vector = NMI_Vector
_中断 void NMI_ISR (void)
{
if (IFG1 & NMIIFG)//检查 NMI 中断是否由 nRST/NMI 引脚引起
{
IFG1 &=~NMIIFG;//清除 NMI 中断标志
IF (WDTCTL & WDTNMIES)//检测到下降沿
{
P1OUT |= BIT6;//打开 P1.0红色 LED 以指示开关1已按下
SwitchState |= S1;//将 Switch 1 State 设置为 pressed
已按下|= S1;//设置 S1已按下标志
PressCountS1 = 0;//重置开关2长按计数
WDTCTL = WDT_MDLY_32 | WDTNMI;// WDT 32ms 延迟+将 RST/NMI 引脚设置为 NMI
//注意:WDT_MDLY_32 = WDTPW | WDTTMSEL | WDTCNTCL // WDT 密码+间隔模式+清除计数
//注意:这也会将 NMI 中断设置为在上升沿触发

}
else //检测到上升沿
{
P1OUT &=~(BIT6+BIT0);//关闭 P1.6和 P1.0 LED
SwitchState &=~S1;//重置开关1已按下标志
PressRelease |= S1;//设置 Press and released 标志
WDTCTL = WDT_MDLY_32 | WDTNMIES | WDTNMI;// WDT 32ms 延迟+下降沿+将 RST/NMI 引脚设置为 NMI
}
__BIC_SR_REGISTER_ON_EXIT (LPM0_BITS);//Wake CPU
} //请注意、NMIIE 现在被清除;WDT_ISR 将在32ms 后设置 NMIIE
否则{//*在此处添加代码以处理其他类型的 NMI (如果有)

}

#pragma vector=Port1_vector
__interrupt void Port1_ISR (void)
{
IF (P1IFG & BIT3)// Checkamos que se ha *** el pulpador conectado al P1.3
{
P1IE &=~BIT3;//禁用按钮中断以避免退回
P1IFG &=~BIT3;//清除按钮的中断标志
IF (P1IES 和 BIT3)
{//检测到下降沿
P1OUT |= BIT0;//打开 P1.0红色 LED 以指示开关2已按下
SwitchState |= S2;//将 S2状态设置为按下
按下|= S2;//设置开关2按下标志
PressCountS2 = 0;//重置开关2长按计数
}
其他
{//检测到上升沿
P1OUT &=~(BIT0+BIT6);//关闭 P1.0和 P1.6 LED
SwitchState &=~S2;//重置开关2状态
PressRelease |= S2;//设置按压和释放标志
}
P1IES ^= BIT3;//切换边沿检测
IFG1 &=~WDTIFG;//清除 WDT 的中断标志
WDTCTL = WDT_MDLY_32 |(WDTCTL & 0x007F);//使用与 NMI 中断设置的相同 NMI 状态重新启动 WDT
__BIC_SR_REGISTER_ON_EXIT (LPM0_BITS);//Wake CPU
}

}

#pragma vector=port2_vector
__interrupt void port2_ISR (void)
{
IF (P2IES & BIT1)// Checkamos que se ha *** el pulpador conectado al P2.1
{
P2IE &=~BIT1;//禁用按钮中断以避免退回
P2IFG &=~BIT1;//清除按钮的中断标志
IF (P2IES 和 BIT1)
{//检测到下降沿
P1OUT |= BIT0;//打开 P1.0红色 LED 以指示开关2已按下
SwitchState |= S2;//将 S2状态设置为按下
按下|= S2;//设置开关2按下标志
PressCountS2 = 0;//重置开关2长按计数
}
其他
{//检测到上升沿
P1OUT &=~(BIT0+BIT6);//关闭 P1.0和 P1.6 LED
SwitchState &=~S2;//重置开关2状态
PressRelease |= S2;//设置按压和释放标志
}
P2IES ^= BIT1;//切换边沿检测
IFG1 &=~WDTIFG;//清除 WDT 的中断标志
WDTCTL = WDT_MDLY_32 |(WDTCTL & 0x007F);//使用与 NMI 中断设置的相同 NMI 状态重新启动 WDT
__BIC_SR_REGISTER_ON_EXIT (LPM0_BITS);//Wake CPU
}
}

// WDT 用于通过延迟重新启用 NMIIE 和 P1IE 中断来对 s1和 s2进行去抖
//并计时印刷
#pragma vector 的长度= WDT_vector
__interrupt void WDT_ISR (void)
{
如果(开关状态和 S1)//检查开关1是否按下
{
如果(++PressCountS1 =PRESSDURATION )//长按持续时间47*32ms =1.5s
{
P1OUT |= BIT0;//打开 P1.1 LED 以指示长按
长按|= S1;//设置长按标志中的 S1位
__BIC_SR_REGISTER_ON_EXIT (LPM0_BITS);//Wake CPU
}
}

如果(开关状态和 S2)//检查开关2是否按下
{
如果(++PressCountS2=PRESSDURATION )//长按持续时间47*32ms =1.5s
{
P1OUT |= BIT6;//打开 P1.2 LED 以指示长按
长按|= S2;//设置长按标志中的 S2位
__BIC_SR_REGISTER_ON_EXIT (LPM0_BITS);//Wake CPU
}
}

IFG1 &=~NMIIFG;//清除 NMI 中断标志(如果已通过弹跳进行设置)
P1IFG &=~BIT3;//清除按钮中断标志(如果已通过弹跳进行设置)
IE1 |= NMIIE;//重新启用 NMI 中断以检测下一个边沿
P1IE |= BIT3;//重新启用 P1.3上按钮的中断

P2IFG &=~BIT1;//清除按钮中断标志(如果它已通过弹跳进行设置)
P2IE |= BIT1;//重新启用 P2.1上按钮的中断
} 

提前感谢。

此致、

弗兰·马丁

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

    错误发生在 ISR port2_ISR 中,在第一个 if 语句的条件下,我检查的是 P2IES 而不是 P2IFG :(
    谢谢!

    此致、


    Fran Martín。

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

    看起来很棒!

    很好的进步!

    ?  您是否有从开关接地的电容器?  

    有些人使用~ 0.01 ~ 0.1uF 、这可以消除伪退回。

    但我在您的代码中看到您使用的是计数环路。

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

    [引用用户="Otto Cepella"]

    看起来很棒!

    很好的进步!

    [/报价]

    大家好、Otto 、非常感谢! )

    [引用用户="Otto Cepella"]

    ?  您是否有从开关接地的电容器?  

    有些人使用~ 0.01 ~ 0.1uF 、这可以消除伪退回。

    但我在您的代码中看到您使用的是计数环路。

    [/报价]

    首先、我测试了该 RC 开关去抖电路(最后一个电路: coder-tronics.com/.../) 、它运行良好。 为了节省硬件组件的成本、我决定将开关直接接地并使用 SW 控制反射、看起来效果非常好。  

    此致 Otto、

    弗兰·马丁。