В чём разница между PORT и LAT?


Если порт сконфигурирован как вход, чтение PORT и LAT может дать разные результаты: чтение PORT даёт то, что на ножках контроллера фактически присутствует, а чтение LAT — то, что в порт записывалось.

Следует запомнить, что PORT нужно использовать для чтения с пина, а LAT для записи.

У младших PIC вообще нет LAT, поэтому приходится учитывать Read-Modify-Write и предусматривать в своём коде отдельные байты для хранения состояния порта (по сути аналог LAT), так как иначе считанное значение может отличаться от ранее записанного в тот же порт, если между чтением\записью было преназначение режима вход\выход. Регистр LAT сохраняет то значение, которое было записано в режиме «выход».

Упрощённая схема портов МК PIC с буфером LAT и без
Упрощённая схема портов МК PIC с буфером LAT и без


У данной проблемы две причины. Первая причина в том, что команды сброса и установки отдельных битов в реги­стре порта работают по принципу Read-Modify-Write, то есть для установки одного пина контроллеру необходимо сначала считать весь байт целиком, модифицировать один бит и уже после этого установить результат обратно в порт.

Рассмотрим пример: мы хотим установить 3 бит регистра PORTB, для этого контроллер сна­чала считывает все восемь бит, затем выполняет установку бита 3 в 1, после чего модифицированный байт целиком записывается в выходную защелку порта. Если другой бит (например, бит 4) регистра PORTB в данный момент определен как вход, входной сигнал на этом выводе будет считан и записан обратно в выходную защелку этого же вывода, затирая ее предыдущее состояние. Если позднее линия 4 переключится в режим выхода, ее состояние может оказаться оши­бочным.

Вторая причина проблемы R-M-W на одном порту: запись в порт вывода происходит в конце цикла выполнения команды, а чтение в начале, то есть при чтении данные должны быть стабильны в начале цикла выполнения коман­ды. Поэтому если выходной вывод нагружен таким образом, что нагрузка влияет на его логическое состояние, то при операциях чтения, следующих сразу же за записью в тот же порт необходимо учитывать инерционность установления напряжения на выводах.

Например, если между выводом и землёй подключён конденсатор, ему потребуется время на заряд, когда вывод устанавливается в 1. Если конденсатор до этого был разряжен, некоторое время он работает почти как короткое замыкание, заставляя вывод перейти в состояние 0, и поэтому чтение регистра порта вернёт 0, хотя в него была записана 1.

Нужно держать в уме, что в фазе Read порт не переходит в состояние HiZ, а остаётся выходом. Открытые выходные транзисторы имеют своё сопротивление, пусть намного меньше сопротивления HiZ, но не нулевое. Вот на этом сопротивлении и падает напряжение в момент переключения на конденсаторе. Напряжение на конденсаторе падает не мгновенно и некоторое время (до порога переключения) предыдущее напряжение попадает в пределы напряжения предыдущего логического состояния, которое и считывается следующей R-M-W. Хотя выходная защёлка этого выхода уже в другом состоянии — следующая R-M-W читает предыдущее состояние.

Пример с кодом:
TRISB = 0b00000000; // Всё ножки на выход
PORTB = 0b00000000; // Установка нулей
...
TRISB = 0b00001111; // Переназначаем часть выводов порта на входы
RB7 = 1; // Устанавливаем старший бит регистра PORTB
TRISB = 0b00000000; // Опять меняем режим на выходы
Если сразу после этого читать PORTB мы получим значение 0b1000хххх, где х - неопределенное значение, зависящее от того, какие уровни присутствовали на указанных выводах порта в момент модификации старшего бита регистра PORTB.


Если же вместо PORTB = 0b10000000 использовать LATB = 0b10000000, то результат всегда будет 0b10000000, независимо от переходных процессов на ножках порта.

Чтобы избежать проблемы рекомендуется:

  1. Если необходимо узнать что было записано в порт, всегда использовать защёлки порта (LAT), а не биты состояния самого порта (PORT).
  2. При работе с битами порта вне прерывания и существовании вероятности изменения тех же битов в прерывании, отключать прерывание перед манипуляциями с битами порта.
  3. При последовательных операциях чтения\записи в один и тот же порт мо­жет потребоваться программная задержка (команда NOP), чтобы напряжение на выводе успело стабилизироваться до начала исполнения следующей команды чтения.





ˆ