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

691_Mikushin_A.V._Programmirovanie_mikroprotsessorov_

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

Рисунок 34. Схема подключения микроконтроллера к COM-порту компьютера

Через универсальный последовательный порт микроконтроллера осуществляются прием и передача информации, представленной в последовательном коде (младшими битами вперед). Наличие буферного регистра приемника позволяет совмещать операцию чтения ранее принятого байта с приемом очередного. Но если к моменту окончания приема байта предыдущий не был считан из регистра SBUF, то он будет потерян. Работой последовательного порта управляют три регистра:

Регистр управления/статуса приемопередатчика SCON

Бит SMOD регистра управления мощностью PCON

Буферный регистр приемопередатчика SBUF

Последовательный порт может работать в четырех различных режимах, но для связи микроконтроллера с компьютером подходит только режим 1. В этом режиме могут быть переданы через внешний вывод TXD или приняты через внешний вывод RXD 8 битов данных. При приеме, стоп-бит записывается во флаг RB8 регистра SCON. Скорость передачи последовательного порта в режиме 1 задаётся таймером Т1 или Т2.

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

Прием начинается с приходом старт-бита, если в бит REN регистра SCON записана логическая единица.

Управление режимом работы приемопередатчика осуществляется через регистр управления последовательного порта SCON. Этот регистр содержит не только управляющие биты, определяющие режим работы последовательного порта, но и девятый бит принимаемых или передаваемых данных (RB8 и ТВ8) и биты прерывания приемопередатчика (RI и TI). Формат и адреса бит регистра SCON приведён на рисунке 35.

101

Адрес Ст. зн.

 

 

 

 

 

 

Мл. зн.

 

 

Разр

 

 

 

 

 

 

Разр

 

98Н

SM0

SM1

SM2

REN

TB8

IT1

RB8

RI

SCON

 

SCON.7

SCON.6

SCON.5

SCON.4

SCON.3

SCON.2

SCON.1

SCON.0

 

 

 

9Fh

9Eh

9Dh

9Ch

9Bh

9Ah

99h

98h

 

Рисунок 35. Формат и адреса бит регистра управления последовательного порта SCON

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

SCON=0x40| //выбрать 8-ми битный режим работы последовательного порта 0x10| //разрешить работу приёмника

0x02; //разрешить запись первого байта в передатчик

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

SCON=0x52;//8 bit UART, разрешение работы приёмника и передатчика

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

Скорость работы последовательного порта обычно задаётся таймером 1. На высоких скоростях обмена информации этот таймер используется в режиме с автоперезагрузкой (старшая тетрада TMOD = 0010В). При синхронизации последовательного порта от таймера 1 скорость обмена определяется выражением:

f

2SMOD f

рез

 

 

32 12 (256 TH1)

В следующей таблице приведена настройка таймера 1 для наиболее часто применяющихся скоростей обмена по последовательному порту:

Частота приема/передачи

Частота резонатора

 

 

Таймер/счетчик 1

(BAUD RATE)

(МГц)

 

 

 

 

SMOD

С/Т

Режим (MODE)

Перезагружаемое число

 

 

 

 

 

 

 

 

 

19,2 Кгц

11,059

1

0

2

0FDH

 

 

 

 

 

 

9,6 Кгц

11,059

0

0

2

0FDH

 

 

 

 

 

 

4,8 Кгц

11,059

0

0

2

0FAH

 

 

 

 

 

 

2,4 Кгц

11,059

0

0

2

0F4H

 

 

 

 

 

 

1,2 Кгц

11,059

0

0

2

0F4H

 

 

 

 

 

 

102

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

1#include <ADuC812.h>

2#include <stdio.h>

4#ifndef GlobalDefine

5

#define ALE_Off

0x10

6

 

 

7

#define MAXBASE

0x8

8

 

 

9#define GlobalDefine

10#endif

11

12

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

14 #define Klaviat *(volatile unsigned char xdata *)0

15

16init()

17{TH1 = 0xFD; //Скорость 9600

181 TMOD = 0x20;//Таймер 1 в режиме autoreload

191 TCON=0x40; //Запуск таймера 1

201 SCON=0x52; //8 bit UART, разрешение приема

211 PCON&=0x7F; //Отключение дублирования скорости, установленной в TH1

22

1

}

23

 

 

24main()

25{init();

261 TI=0; SBUF='S'; while(!TI);

271

281 TI=0; SBUF='D'; while(!TI);

291

301 TI=0; SBUF='K'; while(!TI);

311

321 TI=0; SBUF='1'; while(!TI);

331

341 TI=0; SBUF='.'; while(!TI);

351

361 TI=0; SBUF='1'; while(!TI);

371

38

1

DPP=MAXBASE;

39

1

while(1)

40

1

{Klaviat=~1;

41

2

if(Klaviat==~0x11)

42

2

SvDiod=1;

43

2

else if(Klaviat==~0x21)

44

2

SvDiod=2;

45

2

else

46

2

SvDiod=0;

47

2

}

48

1

}

103

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

Перед началом вывода строки на компьютер из главной подпрограммы строкой 25 вызывается подпрограмма инициализации последовательного порта init(); В этой подпрограмме производится настройка таймера 1 на формирование синхросигнала с частотой, необходимой для работы последовательного порта на скорости обмена 9600 бит/с.

4. Пример реализации микроконтроллерного устройства

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

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

4.1. Разработка структурной схемы

Часы обязательно должны содержать устройство измерения времени, которое в свою очередь всегда состоит из генератора эталонных интервалов времени и счётчика этих интервалов. Схема устройства измерения времени приведена на рисунке 36.

Генератор импульсов

 

Счётчик

эталонной

 

временных

длительности

 

интервалов

 

 

 

Рисунок 36. Структурная схема устройства измерения времени

В простейшем случае генератор импульсов эталонной длительности должен вырабатывать минутные импульсы. В качестве генератора эталонных импульсов мог бы подойти кварцевый генератор, так как этот тип генераторов обладает высокой стабильностью колебаний. Но кварцевые генераторы вырабатывают колебания в диапазоне от 1 до 30 МГц. Это соответствует временным

104

интервалам от 0.03 до 1 мкС. Тем не менее, если воспользоваться делителем частоты, можно получить импульсы с периодом 1 минута.

Выберем частоту работы кварцевого генератора. Мы предполагаем использовать микроконтроллер семейства MCS-51, поэтому выберем частоту кварцевого генератора обычную для этих микроконтроллеров – 12 МГц. Тогда для формирования секундных импульсов (частота 1 Гц) потребуется делитель частоты на 12000000. Для формирования минутных импульсов потребуется ещё один делитель частоты. Так как в минуте содержится 60 секунд, то нам потребуется делитель на 60.

Уточнённая структурная схема разрабатываемого микропроцессорного устройства приведена на рисунке 37.

Кварцевый

12МГц

12000000

1сек

60

1мин

Счётчик временных

 

 

 

генератор

 

 

 

 

 

интервалов

Генератор эталонных интервалов времени

 

 

Рисунок 37. Уточнённая структурная схема устройства измерения времени

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

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

Структурная схема часов с учётом блока индикации и блока коррекции времени приведена на рисунке 38.

Кварце-

12МГц

1200000

1сек 60

1ми

Счётчик временных

вый гене-

 

0

 

 

интервалов

ратор

 

 

 

 

 

Генератор эталонных интервалов времени

 

 

 

 

 

 

 

Дешифратор

 

 

 

 

 

 

Блок коррекции

 

 

Светодиодный ин-

 

 

 

 

 

 

 

дикатор

 

 

 

 

 

 

 

 

 

 

Рисунок 38. Структурная схема часов

Блок индикации

 

 

 

 

105

4.2.Разработка принципиальной схемы

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

Из блока индикации только дешифратор можно реализовать программно. Светодиодные индикаторы естественно должны быть подключены к выводам микроконтроллера.

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

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

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

Получившаяся принципиальная схема часов приведена на рисунке 39.

Рисунок 39. Принципиальная схема часов

106

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

Максимальный коэффициент деления на таймере можно получить 65536. Попробуем необходимый коэффициент деления генератора эталонных интервалов времени равный 12000000 разделить на несколько сомножителей. Прежде всего, выделим сомножитель, равный 12. Это внутренний делитель таймера, который всегда присутствует в составе микросхемы и не может быть нами отключен. То есть нам остаётся реализовать делитель на 1000000.

Выберем коэффициент деления таймера равным 50000. Это число меньше максимально возможного числа, допустимого для шестнадцатиразрядного таймера (216=65536). В результате деления числа 1000000 на число 50000 остаётся число 20. Этот коэффициент деления можно реализовать программно на одной ячейке внутренней памяти данных микроконтроллера.

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

4.3. Разработка программы устройства

Как уже обсуждалось ранее, алгоритм и программу можно писать одновременно. Начнём написание программы с организации простейшей програм- мы-монитора. Напомню, что в программе, написанной на языке программирования C-51, первой выполняется подпрограмма с именем main. Именно в этой подпрограмме и организуем этот монитор. Первоначальный вариант программы приведен в листинге 1.

Листинг 1. Исходный текст первоначального варианта программы.

void main(void)

{while(1); //Бесконечный цикл

}

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

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

нажав на кнопку .

107

Листинг 2. Дизассемблированный текст первоначального варианта программы.

C:0x0000

020003

LJMP

C:0003

C:0x0003

787F

MOV

R0,#0x7F

C:0x0005

E4

CLR

A

C:0x0006

F6

MOV

@R0,A

C:0x0007

D8FD

DJNZ

R0,C:0006

C:0x0009

758107

MOV

SP(0x81),#0x07

C:0x000C

02000F

LJMP

main(C:000F)

2: {while(1);

//Бесконечный цикл

C:0x000F

80FE

SJMP

main(C:000F)

Для того чтобы было легче ориентироваться в тексте программы, перед операторами ассемблерного кода в этом листинге приводится строка исходного текста программы. Например, в листинге 2 это предпоследняя строка.

Бесконечный цикл программы в этом листинге реализуется командой SJMP, расположенной по адресу 000F. Эта команда выполняется за два цикла микроконтроллера. Каждый же цикл микроконтроллера выполняется за двенадцать тактов, отсюда и была получена цифра 2мкс. 12МГц/24=500кГц. Период этой частоты и будет равен двум микросекундам.

Кроме определения времени прохода программы по циклу, в листинге 2 можно убедиться, что программа обнуляет всё содержимое памяти данных (команды, расположенные в ячейках памяти программ с адреса 0003 по 0008) и устанавливает первоначальное значение указателя стека (команда, расположенная по адресу 0009). То есть многие действия, которые приходится делать в программе, написанной на языке программирования ассемблер, в программе, написанной на языке программирования C-51, выполняются автоматически.

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

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

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

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

Программа в основном режиме может ожидать переполнения таймера, опрашивая его флаг TF0, но при использовании прерываний от таймера можно

108

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

Для реализации прохождения микроконтроллером по основному циклу один раз в 50мс, поместим команду PCON=1 в конце тела бесконечного цикла, образованного оператором while(1). В качестве источника прерываний будет служить таймер T0. Переход на начало бесконечного цикла будет осуществляться сразу после возврата из подпрограммы обслуживания прерывания.

Так как прерывания нам потребуются каждые 50 мс, то разрешение прерываний от таймера разместим в подпрограмме инициализации таймера. Разрешение прерываний от таймера производится записью единиц в биты регистра специального назначения IE. Разрешение прерываний от таймера производится битом ET0, а общее разрешение всех прерываний битом EA. Можно записать в эти биты единицу двумя командами присваивания EA=1 и ET0=1, но вспомним, что эти биты находятся в одном регистре. Это означает, что мы можем обойтись одной командой.

Установим биты EA и ET0 в единичное состояние командой логического сложения IE = IE | 0x82, ведь шестнадцатеричное число 0x82 соответствует двоичному числу 10000010. Старший бит этого числа соответствует биту EA, а второй бит этого числа соответствует биту ET0. Использование команды логического сложения вместо команды присваивания позволяет не изменять оставшиеся биты выбранного регистра вне зависимости от состояния этих бит. Язык программирования C позволяет записать эту команду короче: IE |= 0x82.

Теперь специально для начинающих. Я думаю, что перевод чисел из одной системы счисления в другую достаточно затруднителен для человека, впервые столкнувшегося с программированием. Эту работу можно возложить на компилятор. Программа при этом получится длиннее, но зато можно описать комментариями каждый бит многоразрядного числа. Дело в том, что все операции над константами компилятор выполняет в процессе трансляции исходного текста программы, а в загрузочный модуль размещает результирующее число. Поэтому команда IE |= 0x82 может выглядеть в следующем виде: IE |= (1<<7)|(1<<1). Здесь мы просто указываем нужные нам номера битов. Выражение в первых скобках просто означает выделение седьмого бита (единица, сдвинутая на семь позиций влево), а выражение во вторых скобках означает выделение первого бита (единица, сдвинутая на одну позицию влево). Именно такую форму команды мы и выберем.

Теперь микроконтроллер каждые 50 мс будет не только просыпаться, но и передавать управление на вектор прерывания таймера T0. Этот вектор находится по адресу 0Bh. Подпрограмму повторной записи числа 50 мс в таймер нужно поместить точно на этот адрес. Размещение подпрограммы на векторе прерывания мы осуществим зарезервированным словом interrupt. Вектор прерывания конкретно таймера T0 выбирается числом 1.

109

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

Листинг 3. Исходный текст программы, обеспечивающей проход по циклу один раз за 50 мс.

#include<reg51.h>

void Timer0(void) interrupt 1 //ВЕКТОР ПРЕРЫВАНИЯ ТАЙМЕРА T0 {TH0=-50000/256; //Загрузить старший байт таймера TL0=-50000; //Загрузить младший байт таймера

}

/********************************************************************

Подпрограмма настройки таймера T0 на 50 мс режим работы

********************************************************************/

void Timer0_Init(void)

{TMOD=(0<<7)|

//Запретить управление таймером T1 от ножки INT1

(0<<6)|

//Синхронизировать таймер T1 от внутреннего генератора

(0<<4)|

//Перевести таймер T1 в тринадцатиразрядный режим работы

(0<<3)|

//Запретить управление таймером T0 от ножки INT0

(0<<2)|

//Синхронизировать таймер T0 от внутреннего генератора

1;

//перевести таймер T0 в первый режим работы

//Настройка таймера на генерацию 50-ти миллисекундного интервала времени TH0=-50000/256; //Загрузить старший байт таймера

TL0=-50000; //Загрузить младший байт таймера

IE |=(1<<7)|

//Разрешить прерывания в микроконтроллере

(1<<1);

//Разрешить прерывания конкретно от таймера T0

TR0=1;

//включить таймер T0

}

//и вернуться в основную программу

void main(void)

 

{//-------------

ИНИЦИАЛИЗАЦИЯ МИКРОКОНТРОЛЛЕРА-------------------------

Timer0_Init();//Настроить таймер

T0 на прерывания с периодом 50мс

//-------------

ОСНОВНАЯ ПРОГРАММА МИКРОКОНТРОЛЛЕРА--------------------

while(1)

//Бесконечный цикл

 

{PCON=1;

//Перевести микроконтроллер в пониженный режим

}

//потребления тока и подождать переполнения таймера

}

 

 

110