大家好、谢谢观看。 我正在尝试实现一个连接到第二个 PWM 引脚的按钮按压释放、该引脚使用 WDT 来对按钮进行去抖。 结果应为:BTN Down、PWM On;BTN Up PWM Off。 该系统还必须捕获按钮状态更改的时序、以准确确定按钮的加/减时间( 本演示代码中未显示 TA1CCR2到变量的捕获)。 在尝试实现这一目标时、我有几个问题、但当前设置的最大问题是按钮状态与 PWM 行为之间的关系在多次按下按钮后会逆转。 首先、系统按照所述工作、但在几个按钮按下/释放周期后、I PWM 在按钮被释放时打开、然后在更多的时间后再切换回
我在这个论坛上读过关于提出和清除 CCIE 标志的时机的良好讨论、但我的应用似乎不需要像这些示例中那样进行高度准确的计数。 如果我能够在10 - 40ms 的范围内获得准确的时序、那就好了。 我在一个很好地处于 WDT "超时"范围内的示波器上看到按钮反弹以进行去抖、因此看起来效果很好。
那么、我的问题是如何实现这种相对简单的方案。 我使用 MSP430G2553 Timer1_A3在连接到按钮的引脚 P2_5上进行捕获、并使用引脚 P2_6上的 Timer0_A3进行 PWM 输出。 相关问题包括...
我是否可以使用 PxREN 设置内部上拉电阻(数据表显示、当配置为 I/O 时、这适用于引脚)? 我现在有一个外部上拉电阻器。
我是否需要停止计时器才能切换触发中断的边沿(TA1CTL)?
我是否必须在 TA1CCTL2中复位 COV?
是否允许使用 PxIN 和 BTN_KEY 测试引脚的状态? 正如目前使用的那样、这似乎不能按预期工作。
最后、在调试时、我注意到调试器报告、当我在 CM_1和 CM_2之间切换时、TA1CCTL2的 CMx 位为 CM_3、尽管我可以看到我正在正确切换 CCIE 位。 为什么会这样呢?
感谢您的任何想法、下面是我的代码...
#include <msp430.h>
#define BTN_KEY BIT5 //attach key to P2_5 TA1.2
#define BUZZER BIT6 // Buzzer -> P2_6
void PortsInit(void);
void InitBuzzer(void);
volatile char edge = 0; //used to toggle CCR2 edge detect
int main(void)
{
WDTCTL = WDTPW | WDTHOLD; // stop watchdog timer
PortsInit();
P2DIR &= ~BTN_KEY; //Set Btn as input
P2SEL = BTN_KEY; //Set Btn for Timer1_A CCI1A capture
InitBuzzer();
//Set up Timer1A
TA1CTL = MC_2 | ID_3 | TASSEL_2 | TACLR;// | TAIE;
// capture on falling edge, CCI1A input, synchronous cap, capture mode, ints enabled
TA1CCTL2 = CM_2 | CCIS_1 | SCS | CAP | CCIE;
__enable_interrupt();
for ( ; ; ){
// do nothing
}
return 0;
}
#pragma vector = WDT_VECTOR
__interrupt void WDT_ISR(void){ // use to debounce falling and rising
IE1 &= ~WDTIE; // disable WDT interrupt
IFG1 &= ~WDTIFG; // clear flag
WDTCTL = WDTPW + WDTHOLD; // put WDT back in hold state
TA1CCTL2 &= ~CCIFG; // clear the CCRO flag
TA1CCTL2 &= ~COV; // reset COV bit if it was set
TA1CCTL2 |= CCIE; //enable interrupts
}
#pragma vector = TIMER1_A1_VECTOR
__interrupt void TIMER1_A1_ISR (void){
switch (__even_in_range(TA1IV, 10)){
case 0:
break;
case TA1IV_TACCR2:
//grab value of TA1CCR2 here
TA1CCTL2 &= ~CCIE; // disable further CCIE interrupts
TA1CTL |= MC_0; // stop timer
if((P2IN & BTN_KEY) == 0){ // should be here at beginning of down pulse
edge = 1;
TA0CTL |= MC_1; // start tone
P2SEL |= BUZZER;
TA1CCTL2 |= CM_1; // trigger on rising edge
}else{ // Should be here after down pulse finished
edge = 0;
TA0CTL |= MC_0; // end tone
P2SEL &= ~BUZZER;
TA1CCTL2 |= CM_2; // trigger on falling edge, enable interrupts
}
TA1CTL |= MC_2; // restart timer
IE1 |= WDTIE; // enable watchdog interrupt
WDTCTL = WDT_MDLY_32; // start and set WDT (watch dog timer) 32ms interval
break;
case TA1IV_TAIFG:
break;
default:
for (;;){
//Should not be possible
}
}
}
void PortsInit(void){
P1OUT = 0;
P1DIR = 0xFF;
P2OUT = 0;
P2DIR = 0xFF;
P3OUT = 0;
P3DIR = 0xFF;
}
void InitBuzzer(void){
P2DIR |= BUZZER;
TA0CCR0 = 0x8ec; // period
TA0CCR1 = 0x476; // period/2
TA0CTL = TACLR + TASSEL_2 + MC_1; // Timer -> SMCLK, Up Mode, Clear
TA0CCTL1 |= OUTMOD_7; // Output mode for TA0.1 Reset/Set
}