问题描述
我正在尝试构建一个程序,该程序的扫描灯至少带有5个led,一个按钮连接到外部中断引脚。按下一个按钮(然后松开)以启动扫描仪灯。按下(然后松开)再次停止扫描灯(依此类推...)。
- 我在PD2上有一个接地侧开关
- 我在PD3,PD4,PD5,PD6和PD7上有我的LED。
- 我正在使用ATMega328P
我知道当我按下按钮时,高耸的灯就会起作用,但是当我再次按下时,感觉它并没有将值恢复为1。
我的代码:
#ifndef F_cpu
#define F_cpu 1000000UL
#endif
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#define BIT_IS_CLEAR(byte,bit) (!(byte & (1 << bit)))
volatile int value = 1;
int main(void)
{
DDRD = 0b111110000;
DDRD &= ~(1 << PD2); // clear DDRD bit 2,sets PD2 (pin 4) for input
PORTD |= (1 << PD2); // set PD2/INT0 (pin 4) internal pull-up resistor
PCICR = 0b00000100;
PCMSK2 = 0b00000100;
sei();
while (value==1) //when value is 1 it should start having a towerlight
{
PORTD= 0x80;
_delay_ms(15000);
PORTD= 0x40;
_delay_ms(15000);
PORTD= 0x20;
_delay_ms(15000);
PORTD= 0x10;
_delay_ms(15000);
PORTD= 0x08;
_delay_ms(15000);
}
}
ISR(PCINT2_vect)
{
if(BIT_IS_CLEAR(PIND,PD2) & value==1) { // if switch is pressed (logic low)
value=0;
} else if(value == 0) {
value=1;
} else {
// ideally should never get here,but may occasionally due to timing
}
}```
解决方法
您正在使用按位与,此处应为逻辑与。更改
if(BIT_IS_CLEAR(PIND,PD2) & value==1)
对此
if(BIT_IS_CLEAR(PIND,PD2) && (0 != value))
比较非零(等于1)可防止value
损坏;因为您想要零或非零条件。添加括号使意图非常明确。 Yoda比较(将常数放在左侧)可以防止意外分配。
要考虑的另一件事是您要对开关进行去抖动的操作-以模拟方式使用R-C + Schmitt或单稳态,或者以数字方式使用计时器程序,该程序经常对输入进行采样并计算“在最后一个样本(例如16个样本)中有1个或0个”?
我发现边沿触发的中断对于手动开关输入不是特别有效。
,关于:
while (value==1)
{
....
}
当value
为0时,退出循环,然后执行退出程序。这是程序中的严重逻辑缺陷