Как проверить, установлен ли пин?
Как бы вы проверили, установлен ли входной контакт с использованием всего банка? Я думаю, что мне нужно использовать битовую манипуляцию с битовой маской, но я использовал это недостаточно, чтобы понять, как сделать то, что я хочу.
По сути у меня есть следующий код:
void setup() {
DDRA = 0x00;
PORTA = 0xff;
}
void loop(){
//Проверяем, не был ли нажат какой-либо вывод порта A
if (PINA & 0xff){
//делаем что-то
}
}
Но приведенный выше код не работает так, как я ожидал. Кто-нибудь пробовал использовать этот подход раньше? Я делаю это неправильно? Я подумал, что, поскольку я использовал все 8 контактов из одного банка, было бы лучше проверить, установлены ли какие-либо контакты в этом банке, вместо проверки каждого отдельного контакта. Я думал об этом, чтобы предотвратить пропуск любого пользовательского ввода в случае, если нажатие кнопки было инициировано во время выполнения программы другим кодом. Таким образом я только проверяю, установлено ли что-нибудь в банке, экономя время (я так думаю).
@Andy Braham, 👍0
Обсуждение3 ответа
Лучший ответ:
Проблема здесь:
//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
Самый простой способ — использовать DigitalRead в цикле. Это делает ваш код более переносимым и легким для чтения.
Весь смысл был в том, чтобы мне не приходилось читать каждый пин по отдельности, со временем у меня будет гораздо больше входных данных, и время, потраченное на проверку каждого входа, может не уловить все., @Andy Braham
У Uno максимум 20 входов; на частоте 16 МГц вы будете проверять их сотни тысяч раз в секунду (что дает вам 8 инструкций на вывод). Иногда вам это нужно; часто вы этого не делаете., @AMADANON Inc.
Я не совсем эксперт в «простом 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.
(источник: arduinoexperts.com)
Итак, что касается вашего конкретного вопроса, ваша битовая маска верна. Эта инструкция PORTA = 0xff;
бесполезна, поскольку, насколько мне известно, эти настройки игнорируются, поскольку вы устанавливаете направление вывода на выводах PORTA для ввода. Однако, судя по этому изображению, у atmega328 нет PORTA. Это ваша ошибка или вы используете другой микроконтроллер?
EDIT Емкость подтверждена, заставил ее переключаться между GND и VCC с помощью переключателя, и все работает нормально.
«Эта инструкция PORTA = 0xff;
бесполезна» Неверно. В современных, больших AVR это устанавливает состояние внутреннего подтягивающего резистора., @Ignacio Vazquez-Abrams
@IgnacioVazquez-Abrams Спасибо, что указали на это. И читая ваш ответ, все это имеет смысл. Всегда учусь :), @brtiberio
- Использование аналогового входа для чтения кнопки
- Преобразование строки в массив символов
- Поскольку double и float представляют один и тот же тип данных (обычно), что предпочтительнее?
- Можно ли использовать цифровые контакты в качестве выхода ШИМ?
- Bluetooth-модуль HC-05 не принимает AT-команды
- Программирование микроконтроллера Attiny85 без arduino
- Объединение кода для нескольких датчиков в одной программе
- Использование Arduino Nano для программирования (как ISP) автономного 328p
Если вы прикрепили кнопку к земле, то «нажатое» состояние будет равно 0, поэтому «любая нажатая кнопка» кодируется в инструкции
if (PINA == 0xff)
илиif (~PINA & 0xff)
., @frarugi87