Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

691_Mikushin_A.V._Programmirovanie_mikroprotsessorov_

.pdf
Скачиваний:
48
Добавлен:
12.11.2022
Размер:
1.96 Mб
Скачать

R1 U CC UVD1 U P0.1

IVD1

Рисунок 29. Схема различных вариантов подключения светодиодов к параллельным портам микроконтроллеров семейства MCS-51

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

Еще одна причина, по которой приходится прибегать к помощи транзисторного ключа – это пониженное напряжение питания микроконтроллера. На светодиоде падение напряжения в наихудшем случае может достигать 3 вольт, поэтому подключение светодиода непосредственно к порту микроконтроллера возможно только при 5-вольтовом напряжении питания.

По схеме с использованием транзисторного умощняющего ключа к микроконтроллеру подключен светодиод VD2. Расчет резистора R3 в этой схеме не отличается от расчета резистора R1, однако не стоит забывать, что напряжение питания в этой схеме может отличаться от напряжения питания светодиода VD1. В схеме, приведенной на рисунке 29, это так и есть. Расчет резистора R2 еще проще. Его можно рассчитать по следующей формуле:

91

R2 U CC 0.7 ,

I Б

где ток базы IБ должен быть, по крайней мере, в десять раз меньше тока светодиода VD2.

С точки зрения языка программирования, схемы подключения светодиодов влияют на то, каким логическим уровнем зажигается светодиод. Через светодиод VD1 ток будет протекать тогда, когда в порт будет записан уровень логического нуля. Поэтому для зажигания этого светодиода в порт следует записывать логический ноль. Если записать логический ноль в порт P2.7, то транзистор VT1 закроется, и ток через светодиод VD2 протекать не будет, а, значит, и сам светодиод светиться не будет. То есть для того, чтобы зажечь светодиод VD2 нужно записать в порт P2.7 логическую единицу.

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

P2 = 0x80; //двоичный эквивалент записываемого числа равен 1000 0000

В приведенном примере производится запись сразу во все восемь бит порта. При этом в старший бит порта записывается логическая единица, а в остальные биты порта записывается логический ноль. При этом в устройстве, схема которого приведена на рисунке 28, так как порт P2.7 будет выдавать высокий потенциал, то транзистор VT1 откроется, и в цепи его коллектора будет протекать ток. Этот ток будет протекать через светодиод VD2, и он загорится. Такой оператор применяется обычно при начальной инициализации устройства, когда необходимо определить первоначальные уровни напряжения на всех выводах микроконтроллера. Использование записи числа во весь порт позволяет при помощи всего четырех команд сформировать нужное напряжение на всех 32-х выводах параллельных портов микроконтроллера.

При работе со светодиодом VD1 оператор присваивания будет выглядеть несколько иначе:

P1 = 0xbf; //двоичный эквивалент записываемого числа равен 1011 1111

Здесь для зажигания диода VD1 на шестой вывод порта выдаётся нулевой потенциал, а на остальные выводы порта – единицы. Это связано с тем, что ток будет протекать через светодиод только при открытом нижнем транзисторе порта P0.6, а он будет открыт только при записи в этот бит порта логического нуля.

Высчитывать шестнадцатеричный код, который следует записать в параллельный порт контроллера, может оказаться затруднительным. Поэтому часто для его формирования пользуются операцией побитового инвертирования ‘~’.

92

При использовании операции побитового инвертирования приведённый выше оператор будет выглядеть следующим образом:

P1 = ~0x40; //двоичный эквивалент записываемого числа равен 1011 1111

(инверсия от 0100 0000)

Более распространённый случай – это когда необходимо записать единицу только в один или несколько битов (выводов) порта, не изменяя при этом содержимого остальных битов порта. К этим выводам могут быть подключены другие устройства. Такая ситуация встречается при дальнейшем выполнении программы. Время от времени в зависимости от внешних условий будет требоваться зажигать или гасить светодиоды, не изменяя уровни напряжения на остальных выводах порта. В этом случае используется операция логического суммирования. Например:

P2 = P2|0x80; //Зажечь светодиод VD2 не изменяя напряжения на остальных выводах порта

Язык программирования C позволяет записать этот же оператор в более короткой форме:

P2|=0x80; //Зажечь светодиод VD2 не изменяя напряжения на остальных выводах порта

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

0x01 – единица записана только в нулевом бите

0x02 – единица записана только в первом бите

0x04 – единица записана только во втором бите

0x08 – единица записана только в третьем бите 0x82 – единицы записаны в битах номер 7,1 и 0 0x07 – единицы записаны в битах номер 2,1 и 0

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

P2 |= (1<<0)| //Записать логическую единицу в нулевой бит, (1<<2)| //а также во второй бит, (1<<7); //и еще в седьмой бит.

93

В этом примере для объединения бит в одно число использована операция логического суммирования, а для указания номера бита – сдвиг единицы влево на необходимое число разрядов.

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

Запись нуля производится аналогичным образом при помощи побитовой операции логической ‘И’, как это показано в следующем примере:

P2 &= ~((1<<0)|

//Записать логический ноль в нулевой,

(1<<5)|

//пятый

(1<<3));

//и третий биты порта

Операция побитового инвертирования ‘~’ в данном примере применяется, так как запись в бит логического нуля производится операцией логического умножения его прежнего содержимого с нулём.

А теперь посмотрим, как должны объявляться переменные, соответствующие параллельным портам процессора. Для объявления переменных с адресами регистров специальных функций, применяется расширения языка программирования C. Для объявления переменных в этом адресном пространстве используется зарезервированное слово sfr или sfr16. Например:

sfr P0 = 0x80; //порт P0 расположен по адресу 080h sfr P2 = 0xA0; //порт P2 расположен по адресу 0a0h

Точно так же можно объявлять битовые переменные, соответствующие отдельным битам этих портов или других регистров специальных функций с битовой адресацией при помощи зарезервированного слова sbit:

Sbit TF1 = 0x8F; //Флаг переполнения таймера T1 sbit TR1 = 0x8E; //Флаг включения таймера T1

Это полезно для описания процессоров, неизвестных языку программирования keil-C. Для описания же большинства процессоров семейства MCS-51 достаточно подключить готовый файл описания микроконтроллера при помощи директивы include. Например, для описания внутренних регистров микроконтроллера ADuC812 используется строка:

#include "ADuC812.h"

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

При подключении светодиодов к параллельному порту, расположенному во внешней памяти следует использовать другую команду. Например, пусть па-

94

раллельный порт расположен по адресу 0x0007. Для доступа к этой ячейке памяти можно воспользоваться объявлением, которое используется в обычном языке C для доступа к конкретным ячейкам памяти микропроцессора:

#define SvDiod *(volatile unsigned char xdata *)7

Здесь объявляется однобайтовая ячейка памяти (unsigned char), доступ к которой возможен через указатель данных DPTR (для этого после объявления типа переменной использован символ ‘*’). То, что эта ячейка памяти находится во внешней памяти данных, показывает уточняющее слово xdata, отсутствующее в стандартном языке программирования C. Для того чтобы объявленная переменная не могла быть уничтожена оптимизатором языка программирования C, к объявлению типа переменной добавляется зарезервированное слово volatile, запрещающее уничтожение операторов, использующих эту переменную.

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

Чтобы этого не произошло, в конце программы необходимо разместить оператор бесконечного цикла. Для этого можно воспользоваться строкой:

for(;;);

или:

while(1){ }

3.2 Ввод информации через параллельный порт

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

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

Для решения указанных проблем и реализации гальванической развязки датчиков и микропроцессорного устройства, все датчики с точки зрения принципиальной схемы представляют собой контакты, работающие на замыкание. Поэтому схема подключения датчика и кнопки не различаются. Со стороны микропроцессорного устройства необходимо преобразовать замыкание/размыкание контактов в логические уровни, необходимые для правильной работы микропроцессорного устройства. Такая схема приведена на рисунке 30.

95

Рисунок 30. Подключение кнопки к параллельному порту ввода

В приведённой на рисунке 30 схеме резистор R подаёт единичный потенциал на вход параллельного порта. Применение резистора позволяет закорачивать вход параллельного порта на корпус устройства не вызывая чрезмерного тока через контакт. При замыкании контактов кнопки или датчика, на вход параллельного порта подаётся потенциал логического нуля. Эти логические уровни могут быть введены в микроконтроллер при помощи программы, загруженной в его внутреннюю память программ.

Иногда требуется вводить информацию с большого количества кнопок. В этом случае для уменьшения требующегося от микроконтроллера количества линий ввода-вывода используется клавиатура. Для подключения к микроконтроллеру клавиатуры используется два порта: порт ввода и порт вывода. Схема подключения клавиатуры приведена на рисунке 31.

Рисунок 31. Подключение клавиатуры к микропроцессорному устройству

96

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

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

Рисунок 32. Временные диаграммы напряжения на выводах порта вывода

В микроконтроллерах используются квазидвунаправленные порты вводавывода. При подключении клавиатуры к такому порту половину его можно использовать как порт вывода, а половину как порт ввода. Схема подключения к такому порту приведена на рисунке 33.

97

Рисунок 33. Подключение клавиатуры к микроконтроллеру

Обратите внимание, что в подобной схеме нельзя использовать порт P0, так как в этом случае придется использовать дополнительные резисторы, как это показано на рисунке 31. Для того чтобы не было неоднозначности при определении номера нажатой кнопки, выдадим на выходной порт процессора код опроса клавиатуры. Этот код опроса должен содержать на выходе только один логический ноль. Для записи кода в выходной порт, как и в предыдущей главе можно воспользоваться оператором присваивания. Например:

P2 = ~1; //Подать на все ввыводы параллельного порта высокий потенциал, а на нулевой - низкий

В этом примере в порт записывается константа 111111102, которая формируется оператором инвертирования ‘~’ из константы 000000012. После записи этой константы на всех выводах порта кроме нулевого вывода появляется единичный потенциал. На нулевом выводе этого порта появляется низкий потенциал, который может поступать на входные линии параллельного порта при замыкании контактов кнопок клавиатуры. По считанному с входного порта клавиатуры коду можно будет определить состояние кнопок, подключенных к нулевому выводу порта вывода клавиатуры.

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

Port2 = ~2; //подать нулевой потенциал на первый вывод выходного порта клавиатуры

98

Коды, которые выдаются в выходной порт клавиатуры, называется кодами опроса клавиатуры.

После подачи сигнала опроса клавиатуры можно осуществлять считывание логических уровней на выводах порта ввода. Это можно осуществить операцией сравнения. Например:

if(Port2 ==~0x11)

//Если нажата кнопка на пересечении нулевой колонки и

 

нулевой строки

SvDiod=1;

//то зажечь нулевой светодиод

Для понимания этой команды необходимо, чтобы перед глазами кроме исходного текста программы находилась принципиальная схема устройства. Схема приведена на рисунке 33. Из этой схемы видно, что если ни одна из кнопок не будет нажата, то код 111111102, записанный в порт клавиатуры не изменится, и при считывании содержимого этого порта мы получим неизмененный код.

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

101111102.

Коды, которые считываются из входного порта клавиатуры, называются кодами сканирования клавиатуры или скан-кодами клавиатуры.

Для анализа состояния кнопок клавиатуры можно воспользоваться кодом, считываемым с входного порта клавиатуры. Однако намного лучше сначала скопировать содержимое порта ввода во внутреннюю переменную, а только потом анализировать её содержимое. Это позволяет обеспечить одновременность считывания всех выводов порта (или портов) и тем самым избежать неоднозначности работы микроконтроллера при, казалось бы, одинаковых внешних условиях.

Ниже приведен листинг примера программы, позволяющей определять состояние кнопок клавиатуры:

#include "ADuC812.h"

//Подключить определения всех внутренних регистров

ADuC812

 

#define SvDiod P0

//Светодиоды подключены к порту P0

#define Klaviat P2

//Клавиатура подключена к порту P2

main()

 

{while(1)

 

{Klaviat=~1;

 

if(Klaviat==~0x11)

//Если нажата кнопка на пересечении нулевой колонки

 

и нулевой строки

SvDiod=1;

//то зажечь нулевой светодиод

else if(Klaviat==~0x21)//Если нажата кнопка на пересечении нулевой колонки и первой строки

99

SvDiod=2;

//то зажечь первый светодиод

else

//иначе (если не нажата ни одна из кнопок)

SvDiod=0;

//погасить все светодиоды

}

}

В этой программе, построенной по одномодульному принципу, используется одна единственная функция с именем main, в которой выполняются все необходимые действия. Имя подпрограммы определяется языком программирования C, который после предварительной инициализации переменных всегда передаёт управление подпрограмме с именем main.

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

‘{…}’.

Код опроса нулевой колонки клавиатуры формируется оператором присваивания Klaviat=~1;. После выполнения этого оператора на всех выводах порта, кроме нулевого вывода, выдаётся единичный потенциал.

Для индикации состояния кнопок используются светодиоды. При обнаружении скан-кода нажатой кнопки зажигается соответствующий светодиод. Проверка скан-кодов ведётся условными операторами if. Зажигание светодиодов осуществляется операторами присваивания SvDiod=1; и SvDiod=2;.

3.3 Обмен информацией через последовательный порт

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

Однако при работе с последовательным портом микроконтроллера возникает ряд трудностей. Основная трудность заключается в том, что последовательный порт микроконтроллера использует логические TTL уровни. Уровнем логического нуля считается напряжение ниже 0,4В. Уровнем логической единицы считается напряжение больше 2,4В. Последовательный порт компьютера при передаче логического нуля формирует напряжение +10В, а при передаче логической единицы формирует напряжение –10В.

Для согласования логических уровней COM порта компьютера и последовательного порта микроконтроллера в настоящее время используются специализированные микросхемы. Схема подключения микроконтроллера с использованием микросхемы ADM202 к COM-порту компьютера приведена на рисун-

ке 34.

100