Как проверить, установлен ли пин?

Как бы вы проверили, установлен ли входной контакт с использованием всего банка? Я думаю, что мне нужно использовать битовую манипуляцию с битовой маской, но я использовал это недостаточно, чтобы понять, как сделать то, что я хочу.

По сути у меня есть следующий код:

void setup() {
   DDRA = 0x00;
   PORTA = 0xff;
}

void loop(){
   //Проверяем, не был ли нажат какой-либо вывод порта A
   if (PINA & 0xff){
      //делаем что-то
   }
}

Но приведенный выше код не работает так, как я ожидал. Кто-нибудь пробовал использовать этот подход раньше? Я делаю это неправильно? Я подумал, что, поскольку я использовал все 8 контактов из одного банка, было бы лучше проверить, установлены ли какие-либо контакты в этом банке, вместо проверки каждого отдельного контакта. Я думал об этом, чтобы предотвратить пропуск любого пользовательского ввода в случае, если нажатие кнопки было инициировано во время выполнения программы другим кодом. Таким образом я только проверяю, установлено ли что-нибудь в банке, экономя время (я так думаю).

, 👍0

Обсуждение

Если вы прикрепили кнопку к земле, то «нажатое» состояние будет равно 0, поэтому «любая нажатая кнопка» кодируется в инструкции if (PINA == 0xff) или if (~PINA & 0xff)., @frarugi87


3 ответа


Лучший ответ:

2

Проблема здесь:

//Check if any pin from Port A has been pressed
if (PINA & 0xff){

Поскольку подтягивания включены, по умолчанию контакты имеют высокий уровень. Чтобы обнаружить «пресс», их нужно притянуть к земле. Это изменит тест на:

//Проверяем, не был ли нажат какой-либо вывод порта A
if (~PINA) {

И для отдельных пинов:

//Проверяем, нажата ли PA3
if (!(PINA & _BV(PA3))) {
,

Когда я запускаю код if (~PINA), он всегда входит в цикл, несмотря ни на что. Это сработало для вас, вы это проверяли?, @Andy Braham

Я попробовал ваш код, и он всегда будет входить в цикл, но если вы измените код на if(~PINA & 0xff){ ... }, он будет работать., @Andy Braham

~PINA предполагает, что все 8 контактов используются для входа с активным низким уровнем. Если используется только часть порта, вам необходимо замаскировать используемые контакты., @Ignacio Vazquez-Abrams


0

Самый простой способ — использовать DigitalRead в цикле. Это делает ваш код более переносимым и легким для чтения.

,

Весь смысл был в том, чтобы мне не приходилось читать каждый пин по отдельности, со временем у меня будет гораздо больше входных данных, и время, потраченное на проверку каждого входа, может не уловить все., @Andy Braham

У Uno максимум 20 входов; на частоте 16 МГц вы будете проверять их сотни тысяч раз в секунду (что дает вам 8 инструкций на вывод). Иногда вам это нужно; часто вы этого не делаете., @AMADANON Inc.


0

Я не совсем эксперт в «простом avr-коде»; но я модифицировал Arduino Blink и получил (почти) идеальный пример. Установил перемычку между 5 В и 8-м контактом Arduino и загрузил следующий код:

void setup() {
  // инициализируем цифровой вывод 13 как выход.
  DDRB = 0b00100000;
  
  
}

// функция цикла выполняется снова и снова, вечно
void loop() {
  if (PINB & 0x1) {
    PORTB =  0b00100000;  // включаем светодиод (HIGH - уровень напряжения)
    delay(500);              // подождем секунду
    PORTB = 0;    // выключаем светодиод, понижая напряжение
    delay(500);              // подождем секунду
  }
}

Согласно следующему изображению контакт 8 на Arduino — это PB0, а контакт 13 — PB5. Поэтому, используя DDRB, я установил PB5 в качестве выхода, а все остальные — в качестве входа. Затем в цикле я проверяю, как и вы, регистр PINB и использую битовую маску для проверки первого контакта (PB0). И это работает... ну не совсем хорошо. По какой-то причине цикл проходит еще несколько раз, прежде чем он станет действительно низким. Я думаю, это потому, что я просто снимаю перемычку и фактически не заземляю контакт 8 (оставлен плавающим), и, возможно, дополнительные контуры разряжают некоторую емкость на этом контакте 8.

pinouts
(источник: arduinoexperts.com)

Итак, что касается вашего конкретного вопроса, ваша битовая маска верна. Эта инструкция PORTA = 0xff; бесполезна, поскольку, насколько мне известно, эти настройки игнорируются, поскольку вы устанавливаете направление вывода на выводах PORTA для ввода. Однако, судя по этому изображению, у atmega328 нет PORTA. Это ваша ошибка или вы используете другой микроконтроллер?

EDIT Емкость подтверждена, заставил ее переключаться между GND и VCC с помощью переключателя, и все работает нормально.

,

«Эта инструкция PORTA = 0xff; бесполезна» Неверно. В современных, больших AVR это устанавливает состояние внутреннего подтягивающего резистора., @Ignacio Vazquez-Abrams

@IgnacioVazquez-Abrams Спасибо, что указали на это. И читая ваш ответ, все это имеет смысл. Всегда учусь :), @brtiberio