int main(void)
{
DDRD = 0x00 ;
DDRB = DDRB | 0b00100000 ;
while (1)
{
while(!(PIND & (1<<6))){
PORTB |= 1<<PORTB5 ;
}
while((PIND & (1<<6))) {
PORTB &= ~(1<<PORTB5) ;
}
}
return 0;
}
Я пытаюсь создать базовую систему безопасности с помощью переключателя, который при поломке подхватывается PIND7, а затем устанавливает PB5. И наоборот, когда переключатель установлен, низкий сигнал улавливается PIND7, а затем очищает бит на PB5. У микроконтроллера нет проблем, когда переключатель установлен, он немедленно сбрасывает бит в PB5, но когда переключатель ломается, для установки бита в PB5 требуется около 30 секунд. Спасибо за любую помощь, которую вы можете оказать, я извиняюсь, если мой код неаккуратный, я всего лишь новичок.
Обычно очень помогает простая таблица истинности.
Вот моя попытка расшифровать это из вашего текста:
PIND6 | PORTB5
0 | 1
1 | 0
Эта таблица истинности просто говорит, что если PIND6 равен 0, то PORTB5 должен быть равен 1, и «наоборот». Собственно говоря, PORTB5 является логическим НЕ для PIND6.
Это математическое уравнение для того, что нам нужно:
PORTB5 = !PIND6, что совпадает с
.
Я не думаю, что вы хотите иметь два цикла while в своем основном цикле. Это не лучший способ проверки состояния, так как вы можете застрять в них. Как я полагаю, вы получаете.
Вместо этого вам следует либо использовать оператор if, либо просто назначить PORTD, либо использовать любой из них вместе с отклоненным вводом. Я покажу все три из них с некоторым интервалом между ними. Вы не должны держать все три, вы должны выбрать один из них.
Вот непроверенный код:
int main(void)
{
DDRD = 0x00 ;
DDRB = DDRB | 0b00100000 ;
unsigned int debounce = 0; //remove this line if you don't care about debouncing
char old_PIND = PIND;//remove this line if you don't care about debouncing
while (1)
{
////////////////////////////////////////////////
//You can do either this:
////////////////////////////////////////////////
PORTB = (PORTB&(~(1<<PORTB5)))|(~((PIND&(1<<6))>>1));
//(PORTB&(~(1<<PORTB5))) => PORTB but with a 0 on bit 5
//(~((PIND&(1<<6))>>1)) => PIND, but only 6th bit, inverted and shifted 1 step ->
//And then just OR them together
//You could probably remove some parenthesis, but I prefer having more than fewer
////////////////////////////////////////////////
//Or you can do this, it will give you the same result
////////////////////////////////////////////////
if(PIND&(1<<6)){//If it's a 1
PORTB &= ~(1<<PORTB5);//then set PORTB5 to 0
}else{
PORTB |= (1<<PORTB5); //if PIND6 is a 0, set PORTB5 to 1
}
////////////////////////////////////////////////
//Or you can do this if you want debouncing
////////////////////////////////////////////////
if(debounce==0){
if(old_PIND!=PIND){
//if we're in here, it means that the input has changed
//and that the input may bounce a lot for the next couple of microseconds.
//we want to wait some time and then use the value we get later
//because that value will (hopefully) be stable, without any burst noise.
debounce = 10000;//This sets the debounce-timer
//if you want to do this "properly", then you should use one of
//the built in timers that Atmega328P supports,
//instead of using a variable like I do. But this will work.
}else{
//if we're in here, it means that the input has stayed the same
//for one debounce-timer, so now it's stable.
//same code as before:
if(PIND&(1<<6)){//If it's a 1
PORTB &= ~(1<<PORTB5);//then set PORTB5 to 0
}else{
PORTB |= (1<<PORTB5); //if PIND6 is a 0, set PORTB5 to 1
}
}
old_PIND = PIND;//update old_PIND so we can detect changes
}else{
debounce-=1;
}
}
return 0;
}
Итак, технически, просто замените операторы while на операторы if и выучите слово «логическая инверсия», и вы будете на хорошей стороне.
Если вы хотите быть педантичным или «правильным», вам следует использовать прерывания вместе с внутренними таймерами, потому что они делают код более эффективным. Но этот код решит проблему, как вы ее представили.
Питер Беннет