Pull to refresh

Мультиплексирование вывода данных на дисплей с параллельным портом

Reading time6 min
Views5.5K
Мультиплексирование шины данных дисплея с параллельным выводом и последовательного порта Ардуино.

Статья описывает способ мультиплексного использования порта D микропроцессора ATMEL 328P (Ардуино НАНО) с целью обеспечения попеременного побайтного вывода в дисплей и обмена по последовательному каналу.

Собрал я как-то прибор для контроля уровня угарного газа (СО) из ненужных элементов – дисплей от Нокии N95, Ардуино НАНО с несправными портами (D3 и D11, пробиты в результате неудачного замыкания на +400 вольт при отладке генератора высокого напряжения), платы воспроизведения звуковых фрагментов и датчика на угарный газ MQ7. Все эти детали в той или иной степени были неисправны (кроме датчика) и никакого применения в других проектах найти не могли. Как ни странно, оказалось, что прибор очень полезен при использовании печки на даче. Лето 2019 года выдалось нежарким и печку я топил практически каждый день в течении пары недель в июле, соединяя приятное (медитирование на пламя) с полезным (утилизацией попиленных мусорных деревьев). Контролировать режимы горения оказалось очень легко, все манипуляции с заслонками сразу отражались на показаниях прибора, что позволяло управлять печкой разумно. Прибор в этой статье не описывается, в интернете таких устройств предостаточно на любой вкус. Отличительной особенностью моего прибора является функция постоянного контроля исправности датчика СО на основе сравнения запомненной эталонной кривой и получаемой в реальном масштабе времени, а также высокая скорость реакции на изменение уровня СО, достигнутая сравнением запомненных на предыдущем цикле данных с текущими.

Фокус этой статьи на увеличении скорости обмена процессора и дисплея с параллельным байтовым обменом данными.

Дисплей имеет параллельный байтовый обмен и, несмотря на использование всех известных мне способов увеличения скорости обмена, вывод на него оказался довольно медленным. Основная причина – необходимость побитного вывода байта данных на разные биты разных портов, так как Ардуино Нано не имеет ни одного полноценного порта шириной в один байт. Этот режим вывода требует грубо в 8 раз больше времени по сравнению с командой записи байта в регистр. У НАНО имеется единственный полноценный порт D, но его младшие биты используются для аппаратного последовательного порта, по которому происходит загрузка скетчей в процессор и обмен скетча с хост-машиной.

Я нашел относительно простой способ использования побайтного вывода на дисплей. Способ этот заключается в попеременном использовании порта D для вывода данных на дисплей и в обмене данными по последовательному каналу.

Предлагаемый способ позволяет значительно увеличить скорость интегрального обмена с дисплеем (около 3-х раз по моим измерениям). Под словом «интегральный» имеется в виду, что измерялись суммарные времена выполнения операций отрисовки экрана на макро-уровне. Вероятно, что измерение времен на уровне атомарных операций ввода-вывода дало бы существенно больший выигрыш (в районе одного порядка).

Измерения выполнялись на специально собранном макете (см. рисунок 1) следующим способом:

  1. В тестовой программе расставлялись метки времени с выводом на хост-машину.
  2. Дисплей присоединялся к выводам D2 — D9, загружалась тестовая программа, в которой вывод байта осуществлялся путем распределения байта по битам.
  3. Дисплей присоединялся к выводам D0 – D7, загружалась тестовая программа, в которой вывод байта осуществлялся командой PORTD=data.

image

image
Рисунок 1. Фотографии макета для отработки мультиплексирования вывода

Программы совершенно одинаковые, переключение способа вывода осуществлялось сменой имен подпрограмм SendDat и SendCom на SendDat1 и SendCom1 соответственно.
Вывод программы на встроенный сериал монитор записывался в OneNote и анализировался.

image
Рисунок 2. Измерение времени вывода на экран в режиме побайтного вывода

image
Рисунок 3. Измерение времени вывода на экран в режиме побитного вывода

Результаты измерений сведены в таблицу 1.

image
Таблица 1. Интегральный выигрыш в скорости обмена

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

Исследование мануала по процессору дало следующую информацию: включение режима последовательного порта перехватывает управление ножками D0 и D1 на аппаратном уровне. Это значит, что попытки управления ножками из скетча не дадут нужного результата.

Дальнейшее изучение вопроса показало, что, если не включать в скетче последовательный порт командой Serial.open(), то весь порт D остается в распоряжении пользователя. Можно перевести порт в режим вывода по всем ногам командой DDRD=0xFF и выводить весь байт одновременно командой PORTD=data, где переменная data содержит выводимые данные.

Перевести порт D в режим вывода достаточно один раз (в Setup). Последующие включения-выключения режима последовательного обмена не влияют на режим порта D – он так и остается в режиме параллельного вывода 8 бит. При включении режима последовательного обмена выводы D0 и D1 перейдут в режим приема и передачи соответственно. На выводе D1 появится «1» независимо от предыдущего состояния бита D1, и эта «1» будет на этом выводе все время пока включен режим последовательной передачи, кроме моментов передачи символов. При выключении режима последовательной передачи выводы D0 и D1 перейдут в состояние вывода и на них появятся сигналы из регистра вывода. Если в регистре вывода на месте D1 имеется «0», то на выводе будет сформирован отрицательный перепад, который приведет к передаче паразитного символа в последовательный канал.

Рассмотрим теперь вопрос – а не помешает ли такое использование порта D загрузке программ? При загрузке программы процессор сбрасывается импульсом, который генерируется контроллером USB порта FT232RL (либо его аналогом CH340) при выставлении сигнала DTR. Сигнал DTR переходит из 1 в 0 и отрицательный перепад через конденсатор сбрасывает процессор. После сброса процессор включает последовательный порт, запускает загрузчик и принимает код программы. Итак – нормальной загрузке скетча изменение режима работы порта D не мешает.
Если в скетче требуется вывод в сериал порт, то достаточно команды Serial.open() перед командами вывода.

Однако есть тонкость. Заключается она в том, что вход RxD микросхемы FT232RL остается присоединенным к выводу TxD и данные, идущие на дисплей, принимаются и пересылаются далее в хост-машину. Данные эти выглядят как шум, хотя на самом деле им не являются (рисунок 4).

image
Рисунок 4. Вид экрана в режиме побайтного вывода без блокирования

Бороться с этим ненужным сигналом можно двумя путями.

Первый путь – программный. Заключается он в том, что в скетче перед выводом используется команда Serial.println() для создания новой строки перед выводом полезной информации. Это облегчит программе в хост машине анализ входящих строк и выделение полезной информации от скетча.

Второй путь – аппаратный. Вход RxD FT232RL подсоединен к выходу TxD через резистор 1 кОм. Чтобы заблокировать передачу информации достаточно присоединить вход RxD FT232RL к «1». Сделать это проще всего одним из свободных выводов Ардуино. Я использовал вывод D8. Для выполнения этого действия я припаял к выводу 7 резистора RP1B номиналом 1 кОм проводок с разъемом на конце, проведя его через отверстия в плате с целью механической фиксации. На рисунке 5 это соединение показано красной линией, на рисунке 6 приведена фотография места пайки.

image
Рисунок 5. Часть схемы Ардуино нано

image
Рисунок 6. Место пайки дополнительного провода в Ардуино НАНО

Механизм этот работает так: после сброса ножка D8 находится в режиме высокоимпедансного входа и штатной работе механизма загрузки программ в плату Ардуино не мешает.

Когда в скетче надо начать управлять дисплеем, то вывод D8 переводится в режим активного вывода, на нем выставляется «1» (это блокирует передачу данных от вывода TxD Atmel328P на вывод RxD FT232RL) и после этого выполняется команда Serial.end();. Порядок действий важен, так как после выключения режима последовательной передачи на выводе TxD появится бит D1, который сохранился в выходном регистре порта D от предыдущей записи байта в этот порт. Если бит D1 был «0», то при выключении режима последовательной передачи ножка процессора переключится из «1» в «0» и это породит передачу паразитного символа по последовательному каналу.

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

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

Для выполнения этих задач в скетч добавлены две подпрограммы:

void s_begin()
{
  Serial.begin(115200); // Включаем управление выводом TxD от модуля USART. Нога TxD переходит в "1", нога RxD становится входом
  pinMode(8, INPUT); // Отключаем подтяжку входа RxD FT232RL к "1", разрешая прохождение сериал данных на вход RxD FT232RL
 }

void s_end()
{
  Serial.flush(); //Ждем конца передачи 
  pinMode(8, OUTPUT); //Подтягиваем вход FT232RL к "1" отключая передачу данных пока идет управление дисплеем. Без этого 
  D8_High;            //будут передаваться паразитные данные 
  Serial.end(); // закрываем сериал канал. В этот момент на ноги TxD и RxD начинают выводится биты D0(RxD) и D1(TxD) порта D 
}

Полностью тестовую программу можно взять тут.
Tags:
Hubs:
+6
Comments39

Articles

Change theme settings