Обучение : Программирование на Си для PIC


Регистры портов. Определение направлений работы линий.

Что такое регистр? Регистр – это ячейка памяти в МК (в области ОЗУ). Если это ячейка памяти, то в неё можно записать один байт информации. А байт это некое число, которое лежит в десятичном диапазоне 0…255. Некоторые регистры/ячейки имеются определенные имена и отвечают за тот или иной режим работы МК, что очень подробно расписывается в даташите.

 

Рассмотрим строчку TRISB = 0b00010000;

 

Мы видим, что регистр TRISB приравнивается чему-то. Вы наверняка слышали о некоторых системах счисления: двоичная, десятичная, шестнадцатеричная. И чтобы компилятор понимал, какое число в данном случае употребляем, существуют определенные форматы записи.

 

127 – обычное десятичное число 127;

0x7F – число 127 в 16-ричной системе счисления;

0b01111111 – число 127 в двоичной системе счисления.

 

Если нет приставки – то это десятичное число, если префикс 0х – то это 16-ричное число, если префикс 0b – то это двоичное число. Что такое двоичные и 16-ричные числа – напрягаем Интернет. Программу для перевода двоичных, 16-ричных и десятичных чисел скачиваем здесь, либо воспользуйтесь стандартным калькулятором Windows (вид – инженерный).

 

Почему мы TRISB приравниваем некому двоичному числу? Для ответа на этот вопрос сначала заучим правило: биты в байте нумеруются справа налево от нуля до семи. Каждый бит в регистре/ячейке TRISB отвечает за направление работы соответствующей ножки на порту В. Например, нулевой бит отвечает за направление работы ножки RB0. Фраза TRISB = 0b00010000; говорит нам, что четвертый бит в этом регистре будет равен 1. Использование двоичной записи гораздо нагляднее показывает направление работы каждой ножки.

 

А как запомнить – какой бит (0 или 1) нужен для работы на вход или для работы на выход? Мы говорили, что ножки работают на вход или на выход (вход/выход – на англ. Input/Output или IO – наверняка вы это слышали в аббревиатуре BIOS – базовая система ввода/вывода). Внешне буквы I/O похожи на цифры 1/0. Цифра 1 – это вход (Input), а цифра 0 – это выход (Output).

 

Итак, гладя на фразу TRISB = 0b00010000; мы видим что 4й бит равен единице. А это значит что RB4 будет input, т.е. цифровой линией, работающей на вход. Если бы мы записали TRISB = 0b00100010; то этим мы скажем, что RB0-RB2-RB3-RB4-RB6-RB7 работают на выход, RB1 и RB5 на вход.

 

TRISA = 0b00000000; // направление работы ножек порта А

TRISB = 0b00010000; // направление работы ножек порта В

 

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

 

Следующая строчка CMCON = 0x07; // отключение компараторов. Для тех кто не в теме объясняю – в МК типа PIC16F62X встроен модуль компараторов. Выводы этого модуля имеют названия AN0…AN3 (см. картинку на стр. 3 даташита). По-умолчанию (после сброса питания МК) ножки RA0…RA4 не являются цифровыми линиями ввода/вывода; они подключены к модулю компараторов. Нам нужно сделать переключение с AN0…AN3 на RA0…RA4. Именно за это отвечает строчка CMCON = 0x07;. Более подробнее смотрите даташит стр. 54 (рекомендую не смотреть).

 

Далее у нас две строчки

 

PORTA = 0; // очищаем порт А

PORTB = 0; // очищаем порт Б

 

Для чего нужна очистка? Представим ситуацию – мы подаем питание на МК. Начинается выполнение программы. Выполнились строчки определения направления. И что после этого? На ножках, которые работают на выход может быть любое состояние сигнала. Признаком хорошего тона является именно в этом месте программы, в самом начале установить на ножках НЛУ (если обратного не требует логика работы устройства). Это как минимум экономит энергию, а как максимум даёт вам уверенность в определенности состояния сигналов на ножках.

 

Что такое очистка? Это прописывание нуля в регистр или установка конкретного бита в ноль. Эти две строчки можно было бы написать и в двоичном формате

 

PORTA = 0b00000000; // очищаем порт А

PORTB = 0b00000000; // очищаем порт Б

 

Те же яйца, вид с боку. Это означает, на всех цифровых линиях, которые работают на выход, будет установлен НЛУ. Если бы мы записали PORTB = 0b10010001 то на RB0, RB4 и RB7 будет установлен ВЛУ (при условии, если эти ножки будут настроены на выход).

 

Внимание. Те кто не понял, читайте заново и перечитывайте, пока не уловите логику. Это основы основ – определить направление работы ножек и установить соответствующий уровень сигнала на соответствующей ножке.

 

Теперь рассмотрим работу с конкретными битами регистров TRISx и PORTx (это позволит работать индивидуально с ножками, а не со всеми сразу). По пути C:\Program Files\HI-TECH Software\PICC\9.50\include\ в известном вам файле pic16f62xa.h приводятся наименования регистров и битов в регистрах. В файле мы можем найти фразы TRISA, TRISB, PORTA, PORTB – это названия регистров (TRISх отвечают за направление работы, PORTx используются для установки исходящих сигналов на линиях и оценки входящих сигналов). Именно в эти регистры в тексте программы мы прописываем некоторые числа. Однако мы видим индивидуальные биты, например TRISA0, TRISB1, RA2, RB3 и прочие.

 

Фразу TRISB = 0b00010000; можно было бы заменить набором фраз

 

TRISB0=0; TRISB2=0; TRISB5=0; TRISB7=0;  

TRISB1=0; TRISB3=0; TRISB4=1; TRISB6=0;

// аналогично определяются направления через TRISAx, где х – соотв. бит

 

и последовательность фраз не имеет значения. В общем мы имеем 8 фраз, в которых мы «поклонились» каждому биту, т.е. определили направление работы каждой ножки. Ну а теперь давайте посмотрим как можно индивидуально установить сигнал на ножке. Заменим фразу PORTB = 0b01011011; набором фраз

 

RB0=1; RB2=0; RB5=0; RB7=0; RB1=1; RB3=1; RB4=1; RB6=1;

// аналогично определяется уровень сигнала через RAx, где х – соотв.бит

 

Таким образом, установили определенный уровень сигнала на конкретной ножке. И вы должны четко понимать, что  PORTB = 0b01011011 и PORTB = 91 это одно и то же, но менее наглядно. И теперь вы должны понять, почему двоичная запись для таких случаев более удобна; мне проще написать двоичное число, посчитав количество битов и комбинацию нулей и единиц, чем переводить двоичное число в десятичное или 16-ричное.

 

Всё, хватит про порты. Неохваченным остался вопрос работы с ножками, которые настроены на вход. Об этом чуть позже.

 

Риторическое отступление. Те, кто переходит с Ассемблера на Си, последние две страницы прочитал с легкостью и радостными чувствами. Действительно, удобность управления портами и ножками поражает своей простотой и наглядностью. На ассемблере это выглядит менее понятно и менее удобно. И вы уже должны интуитивно предположить, как работать с ножками, настроенными на вход. Конец отступления.

 

Последняя строчка в функции podgot звучит как

 

RBPU = 0;  // подтягивающие R (0-вкл, 1-выкл)

 

R – это символ резистора (сопротивления). Что такое подтягивающие резисторы? Мы знаем, что МК работает с сигналами ВЛУ и НЛУ, то есть с нулями и единицами. А теперь представим, что ножка настроена на вход и «висит в воздухе» (ни к чему не подключена). Какой уровень сигнала на ней в таком случае будет? Мне трудно сказать определенно. И я не далек от истины. Действительно, на ножке будет неопределенное состояние, вызываемое наводками, что приводит к хаотичному появлению ВЛУ и НЛУ на ножке. И это означает, что на ножке так называемое серое состояние и его иначе называют третьим состоянием. Чтобы избежать подобной неопределенности, ножки «подтягивают» через сопротивления к плюсу или к минусу питания (традиционно к плюсу).

 

Что такое подтягивание? Это подключение сопротивления (резистора) одной стороной к цифровой линии МК, другой стороной к линии питания МК. Номинал этого сопротивления принципиального значения не имеет и может находиться в пределах 1 ком – 10 ком (я ставлю 4,7-5,1 ком).

 

Все известные мне PIC имеют на порту В программно включаемые подтягивающие резисторы к плюсу. В данном случае резисторы включаются и отключаются «скопом»: либо подтягивающие резисторы (8 шт.) подключены ко всем линиям порта В, либо ни одна линия не подтянута. За подключение/отключение отвечает специальный бит, который называется RBPU. Это, пожалуй, единственный инвертированный бит. Если мы его приравняем нулю, то значит подключим подтягивающие резисторы. И наоборот, прописав в этот бит единицу, мы отключим подтягивающие резисторы.

 

Наконец мы с вами рассмотрели 6 строчек функции podgot. Это ни что иное, как продолжение нашей рыбы. Ни одна программа не обходится без подготовки ножек портов. Можно конечно сделать хитрый проект и использовать состояние регистров TRISx и PORTx по-умолчанию в МК, т.е. использовать состояние битов после сброса (это также отражено в даташите). Но береженого бог бережет. Ни на что не надейтесь. Излишняя уверенность – повод для ошибок. Запомните – если что-то не работает – проблема либо в программе, либо в электрических соединениях (99,999%). Ну произошел провал напряжения, ну сбросился МК, а какие-то ячейки не сбросились в умолчания, вот вам и траблы (баги, глюки).

 

Строго говоря, направление работы ножек можно в любой момент переопределить в программе, в зависимости от поставленных целей и внешней схемотехники. А изменение уровня сигнала на линиях – это обычное дело; т.е. мы дергаем ножками. В наших первых учебных проектах мы будем строго определять направления работы ножек и уровень сигналов на линиях в самой первой вызываемой функции podgot (функцию можете назвать иначе, хоть zopa).

 

Ну что друзья, переходим к практике. Не бздите, всё довольно просто.

 

Мы помним что есть такие записи

 

#define knopka RB4 // кнопка

#define diod   RA0 // светодиод

 

В функции main есть строчка

 

diod = knopka;

 

что означает «RA0 присвоить состояние из RB4». Смотрим схему.

 

 

Схема нарисована в Протеусе (Proteus). В этой схеме предполагается, что питание подано на соответствующие линии питания (их нет на картинке).

 

А теперь разбираем работу схемы.

1) Внутри МК мы включили подтягивающие резисторы (у нас это делается только на порту Б и только к плюсу питания), таким образом у нас на RB4 ВЛУ или иначе говоря единица до тех пор, пока не нажата кнопка. Если мы нажимаем кнопку, то мы закорачиваем RB4 на минус питания, что переводит ножку в НЛУ (в ноль).

2) Программа у нас зациклена в main. RA0 присваивается состояние которое на RB4. Когда кнопка не нажата, на RA0 у нас единица, т.е. ВЛУ и светодиод светится. Нажимаем кнопку, и светодиод гаснет, т.к. на RA0 устанавливается ноль.

 

Т.к. цикл крутится с большой частотой (при частоте 4 мГц МК выполняет 1 млн операций в секунду) кнопка у нас опрашивается ну очень часто. Это приводит к моментальному реагированию светодиода на нажатие кнопки.

 

Именно так оценивается состояние сигнала на ножке, которая работает на вход – оцениваются входящие сигналы.

 

Вам не нравится такой алгоритм управления? Сделайте иное включение

 

 

Было бы хорошо, если бы вы заметили дефекты в программе. Их два.

1) Т.к. программа крутится в цикле, то у нас постоянно вызывается функция podgot и выполняются действия, которые нам нужно сделать только единожды. Переопределение направления работы ножек (пусть даже и без изменения направления) приводит к тому, что ножка в момент определения направления может находиться а неопределенном состоянии, а это фактор нестабильности.

2) В цикле мы постоянно чистим порты. С одной стороны мы устанавливаем RA0=RB4 и ожидаем, что оставшаяся часть цикла программы не будет затрагивать ножку RA0 на порте А. У нас же происходит обратное. Мы установили сигнал, и практически сразу же у нас он снимается чисткой. Это приводит к мерцанию диода с высокой (незаметной глазу) частотой. Мы можем закомментировать //PORTA = 0; но это не выход из ситуации.

 

И что делать? Напишите функцию main иначе (см. ниже). Нововведения мы рассмотрим в следующем разделе.

 

void main (void)

{ // начало функции

podgot(); // вызов функции подготовки МК

while(1)

{ // начало бесконечного цикла

diod = knopka;

} // конец бесконечного цикла

} // конец функции

 

А под конец этого раздела мы посмотрим работу со светодиодом с точки зрения физиологии. Смотрим картинки ниже.

 

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

1) Ножка RBx работает на выход (подтягивающий резистор автоматически отключен). Прописывая RBx=1 мы устанавливаем сигнал высокого логического уровня (ВЛУ), т.е. напряжение равное напряжению питания.

2) Ножка RBx работает на выход (подтягивающий резистор автоматически отключен). Прописывая RBx=0 мы устанавливаем сигнал низкого логического уровня (НЛУ), т.е. напряжение равное 0 вольт.

3) Нетрадиционный способ управления. Ножка RBx работает на вход. Прописывая RBPU = 0 или RBPU = 1 мы включаем или отключаем подтягивающий резистор на RBx, т.е. устанавливаем ВЛУ. И этот вариант имеет право на жизнь.


<<< назад далее >>>

Просмотров: 74850

 








 
 
 

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