Nano Hash - криптовалюты, майнинг, программирование

В режиме 4-битных данных можно ли использовать остальные 4 бита для других вещей?

Итак, я пишу программу на C для интерфейса ЖК-дисплея в режиме 4-битных данных. Однако мне было интересно, могу ли я использовать остальные 4 бита для чего-то еще, например, для внешнего прерывания. Чтобы быть более конкретным, я использую PORTD для линий данных на Arduino, однако мне также нужен контакт PD2 для использования прерывания INT0 (кнопка). Я заметил, что в своей программе я продолжал устанавливать младшие 4 бита в 0 при отправке команд:

PORTD = cmd & 0xf0;
flashLCD();
PORTD = (cmd & 0x0f) << 4;

Это работает отлично, но устанавливает другие биты в 0. Это вызывается по таймеру, что означает, что я повторно отправляю команды. Поэтому я попытался сохранить предыдущее значение регистра и дополнить его некоторыми побитовыми операциями:

uint8_t initial_state = PORTD;
PORTD = (cmd & 0xf0) | (initial_state & 0x0f);
flashLCD();
PORTD = ((cmd & 0x0f) << 4) | (initial_state & 0x0f)

Он отправляет cmd на ЖК-дисплей, однако по-прежнему не отвечает на прерывание. Я хотел знать, есть ли что-то, что я не принимаю во внимание, или моя логика неверна. Спасибо.

Редактировать: Nvm Я понял это. Моя ЖК-библиотека всегда сбрасывала регистр порта на 0, даже в 4-битном режиме, поэтому другие неиспользуемые порты также сбрасывались. Я только что изменил библиотеку, чтобы использовать другие порты в 4-битном режиме.

26.02.2019

  • При использовании 4-битного режима ЖК-дисплея остальные 4 контакта даже не нужно подключать к GPIO Arduino. Таким образом, вы можете использовать их для чего угодно 26.02.2019
  • В общем, если я использую один и тот же порт по-разному, я буду работать с копией в ОЗУ, модифицировать ее и записывать это значение в порт. Причины таковы: а) порт может быть доступен только для записи и б) чтение порта может повлиять на его поведение, например биты состояния, связанные с другими видами использования порта. 26.02.2019

Ответы:


1

Вы правильно заметили, что другие биты могут быть сохранены с помощью побитовых операций

PORTD = (PORTD & 0x0F) | (high_bits << 4);

Но! эта строка будет скомпилирована в несколько машинных инструкций:

  1. загрузить значение PORTD в регистр
  2. выполнить побитовое И над регистром
  3. загрузить high_bits в другой регистр
  4. выполнять другие вычисления (сдвиг влево по старшим битам и т. д.)
  5. выполнить побитовое ИЛИ
  6. сохранить результат обратно в PORTD

Давайте представим, что где-то между 1 и 6 срабатывает прерывание, оно останавливает выполнение кода и изменяет младшие биты PORTD. После завершения процедуры прерывания программа продолжает выполняться и перезаписывает все 8-е биты PORTD на то, что было сохранено в регистрах до прерывания, таким образом перезаписывая младшие биты PORTD, отбрасывая все изменения, сделанные в процедуре прерывания.

Таким образом, есть два подхода к тому, чтобы сделать операцию записи в PORTx атомарной.

Во-первых: просто отключите прерывание на время обновления регистра PORTx:

uint8_t old_sreg = SREG; // save SREG register (including I flag)
cli(); // clear I flag, thus prohibiting interrupts
PORTD = (PORTD & 0x0F) | (high_bits << 4); // perform the operation
SREG = old_sreg; // restoring SREG and I flag, if it was set before

Второй подход работает только на новых ядрах AVR (например, ATmega328, 1284, 2560 и т. д.), но не работает на более старых (ATmega8, 32 и т. д.). См. техническое описание, раздел Порты ввода-вывода -> Порты как общий цифровой ввод-вывод -> Переключение контактов. Запись единиц в биты PINx инвертирует соответствующие биты PORTx. Используя его, можно обновить только необходимые биты регистра PORTx, оставив другие нетронутыми, тем самым устраняя необходимость блокировки прерываний. Это может быть полезно в критичных по времени средах, где прерывание должно срабатывать как можно быстрее.

PIND = (PORTD ^ (high_bits << 4)) & 0xF0;

Конечно, это сработает, если гарантируется, что прерывание может изменить только другие (в данном примере - младшие) биты PORTD. Если прерывание также может записывать те же биты, то это может привести к неожиданным результатам, так что будьте осторожны.

01.03.2019
  • О, хорошо, я не подумал об этом, спасибо. Однако не проще ли сначала окружить назначение PORT с помощью cli(), а затем sei()? Пример: кли(); ПОРТ = ...; сэй(); 03.03.2019
  • @Okbuddydude, если вы уверены, что прерывания были включены раньше, то да. Но если ваш код вызывается из обработчика прерываний или из другой подпрограммы, когда прерывания были отключены, небрежное обращение к sei() может привести к нежелательным последствиям. Поэтому лучше сохранить флаг I из SREG и восстановить его в прежнее состояние. 03.03.2019

  • 2

    Я не знаю, какие контроллеры (ATmega/AVR или какие-то еще) используются на Arduino, и вы даже не указываете, какой из них вы используете.

    Но обычно порты и выводы портов могут быть настроены на режим ввода или вывода. Поскольку вы выдаете 4 бита через PORTD, я предполагаю, что весь 8-битный порт (все выводы порта) настроен как выход.

    Вы должны рассмотреть свое руководство, могут ли определенные контакты всего порта быть выходными контактами, а другие могут быть входными контактами одновременно и как.

    Будьте осторожны при переключении ввода/вывода всего порта между ними, это может иметь побочные эффекты, например. нежелательные переходы H-L/L-H. Однажды у меня было такое с микросхемой вывода 8255, что вызвало сброс моего графического ЖК-дисплея из-за подключенной линии сброса ЖК-дисплея.

    26.02.2019
    Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

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

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..