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

691_Mikushin_A.V._Programmirovanie_mikroprotsessorov_

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

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

ходить быстро и с постоянной задержкой по времени, то время взятия отсчетов (а также время вывода на индикаторы) будет строго постоянным.

Исходный текст подпрограммы опроса кнопок приведён в листинге 15.

Листинг 15. Исходный текст подпрограммы опроса кнопок.

sbit P1_7 = 0x97; sbit P2_7 = 0xa7; sbit P3_7 = 0xb7;

unsigned char SostKn=0;

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

Подпрограмма опроса кнопок

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

void OprosKnop(void) {if(P1_7)

SostKn|=1; else

SostKn&=~1; if(P2_7)

SostKn|=2; else

SostKn&=~2; if(P3_7)

SostKn|=4; else

SostKn&=~4;

}

В этой подпрограмме кнопки, разнесённые по трем различным портам, сводятся в одну переменную SostKn. Для опроса состояния кнопок установки времени используется условный оператор if. При помощи этого оператора опрашивается состояние логического уровня на входах седьмого вывода портов P1, P2 и P3. Объединение сигналов производится при помощи команд логического ‘И’ и ‘ИЛИ’.

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

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

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

121

это действие в отдельную подпрограмму. Пусть эта подпрограмма называется

CorrClock.

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

Листинг 16. Исходный текст первого варианта подпрограммы коррекции внутреннего состояния часов.

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

Подпрограмма блока коррекции часов

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

void CorrClock(void)

{if((SostKn&1)==0) //Если нажата кнопка "уст сек",

SEC=60;

//то обнулить счетчик секунд

}

Обработка нажатия на кнопки “уст мин” и “уст часов” производится несколько иначе. Дело в том, что по общепринятому алгоритму коррекции показаний часов при нажатии на эти кнопки необходимо непрерывно увеличивать показания счётчика часов или минут. Предварительный делитель начинает счет от числа 20, которое в двоичном представлении выглядит как 101002. То, что в младших разрядах записаны нулевые значения означает, что эти разряды будут меняться по двоичному закону, и единица в этих разрядах будет появляться через одинаковые промежутки времени.

Например, в младшем разряде единица будет появляться один раз за 100 мс, то есть десять раз в секунду. В следующем разряде единица будет появляться один раз за 200 мс, то есть пять раз в секунду. В третьем же разряде появление единицы будет неравномерным. Два раза единица в этом разряде появится через 400 мс, а один раз через 200 мс. Если использовать сигнал с этого бита для коррекции времени, то эта непериодичность коррекции показаний часов будет раздражать пользователя, поэтому такой вариант неприемлем.

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

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

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

Подпрограмма блока коррекции часов

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

void CorrClock(void)

{if((SostKn&1)==0) //Если нажата кнопка "уст сек",

122

SEC=60;

//то

обнулить счетчик секунд

if((Delit&3)==2)

//Если

в предделителе число не кратно 2,

return;

//то

выйти из подпрограммы коррекции времени

if((SostKn&2)==0) //Если

нажата кнопка "уст мин",

IncMin();

//то

увеличить содержимое счётчика минут

if((SostKn&4)==0) //Если нажата кнопка "уст час",

IncChas();

//то увеличить содержимое счётчика минут

}

 

 

В приведенном варианте программы проверяется два младших бита делителя. Для выделения двух младших бит используется логическое умножение содержимого переменной Delit с маской 00011b. Это число соответствует десятичному эквиваленту 310. Так как эти биты принимают значение 102 пять раз в секунду, то соответствующее количество раз в секунду будет вызываться подпрограмма увеличения значения содержимого счётчика минут (или часов).

Если скорость коррекции показаний часов пять раз в секунду покажется слишком высокой, то можно изменить соотношение коэффициентов деления таймера и делителя, например: 32 31250. Тогда можно будет выбрать скорость коррекции показания часов из набора вариантов два, четыре или восемь раз в секунду. Это обеспечивается двоичным характером коэффициента деления предварительного делителя, равного числу 32. В этом случае, так как изменился коэффициент деления таймера, один проход по основному циклу программы будет осуществляться за 31,25 мс. То есть время реакции часов увеличится. Правда, уменьшится и потребление тока от источника питания.

На этом можно завершить разработку часов. В заключение я хотел бы отметить, что ток потребления микроконтроллера на частоте 12 МГц в режиме пониженного энергопотребления составляет 6,5 мА. Это означает, что даже если отключить светодиодную индикацию, то батарейки с емкостью 300 мА/ч хватит на 46 часов работы. Отличные часы! Не правда ли?

Ток потребления можно снизить, применив вместо стандартного кварцевого резонатора часовой резонатор с частотой 32,768 кГц. При этом ток потребления микроконтроллера снизится в 366 раз и составит 18 мкА. При таком токе потребления той же самой батарейки хватит на 16666 часов или на 694 суток (почти два года работы). Есть разница? Однако при этом программа предварительного делителя будет немного сложнее.

Придется строить делитель с дробным коэффициентом деления. Такие делители обычно строят, переключая два коэффициента деления с определенным периодом, но я думаю, в данном случае это имеет смысл. Основная цель приведенного примера была не в разработке рабочего устройства, а в обучении создания и развития программного проекта на языке программирования C-51, а также иллюстрация его возможностей.

123

Заключение

Ну, вот мы и закончили краткий обзор возможностей языка программирования C-51. Конечно, в рамках одной книги невозможно рассмотреть все особенности применения языка программирования. Тем не менее, я сделал попытку рассмотреть основные особенности работы с микроконтроллерами на языке программирования высокого уровня.

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

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

Успехов вам!

124

Приложения

П.1. Система команд микроконтроллеров семейства MCS-51

Таблица П.1. Машинные команды, влияющие на значения флагов регистра PSW

 

 

Флаги

 

 

Флаги

Мнемоника

 

 

 

 

 

Мнемоника

 

 

 

C

 

OV

 

AC

C

OV

AC

 

 

 

 

 

 

 

 

 

 

 

 

 

 

ADD

+

 

+

 

+

CLR C

0

 

 

 

 

 

 

 

 

 

 

 

 

ADDC

+

 

+

 

+

CPL C

+

 

 

 

 

 

 

 

 

 

 

 

 

SUBB

+

 

+

 

+

ANL C, bit

+

 

 

 

 

 

 

 

 

 

 

 

 

MUL

0

 

+

 

 

ANL C, /bit

 

 

 

 

 

 

 

 

 

 

 

 

 

DIV

0

 

+

 

 

ORL C, bit

+

 

 

 

 

 

 

 

 

 

 

 

 

DA

+

 

 

 

 

ORL C, /bit

+

 

 

 

 

 

 

 

 

 

 

 

 

RRC

+

 

 

 

 

MOV C, bit

+

 

 

 

 

 

 

 

 

 

 

 

 

RLC

+

 

 

 

 

CJNE

+

 

 

 

 

 

 

 

 

 

 

 

 

SETB C

1

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

125

Таблица П.2. Обозначения и символы, используемые при описании команд

Обозначение

Назначение

 

 

А

Аккумулятор

 

 

Rn

Регистры текущего выбранного банка регистров

 

 

R

Номер загружаемого регистра, указанного в команде

 

 

direct

Прямоадресуемая 8-битовая ячейка памяти данных

 

 

@Ri

Косвенноадресуемая 8-битовая ячейка внутреннего

ОЗУ данных

 

 

 

data 8

8-битная константа, входящая в код операции (КОП)

 

 

data 16

16-битная константа, входящая в код операции (КОП)

 

 

data H

Старшие биты (15-8) 16-битной константы

 

 

data L

Младшие биты (7-0) 16-битной константы

 

 

adr 11

Младшие 11-бит адреса

 

 

adr 16

Полный 16-битный адрес

 

 

adr L

Младшие биты адреса

 

 

rel

Байт смещения с учетом знака

 

 

bit

Адрес бита

 

 

126

Таблица П.3. Перечень команд микроконтроллеров семейства MCS-51

Hex

Чис-

Число

Мнем.

 

 

 

ло

цик-

Операнды

Описание команды

код

код

байт

лов

 

 

 

 

 

 

 

 

 

 

 

 

 

 

00

1

1

NOP

 

Нет операции

 

 

 

 

 

 

01

2

2

AJMP

code addr (0

Безусловный переход

 

 

 

 

стр)

в пределах 2 кБ

 

 

 

 

 

 

02

3

2

LJMP

code addr

Безусловный переход

 

 

 

 

 

в пределах 64 кБ

 

 

 

 

 

 

03

1

1

RR

A

Циклический сдвиг вправо

 

 

 

 

 

 

04

1

1

INC

A

ACC ACC + 1

 

 

 

 

 

 

05

2

1

INC

data addr

data data + 1

 

 

 

 

 

 

 

06

1

1

INC

@R0

(R0)

(R0) + 1

 

 

 

 

 

 

 

07

1

1

INC

@R1

(R1)

(R1) + 1

 

 

 

 

 

 

 

08

1

1

INC

R0

R0

R0 + 1

 

 

 

 

 

 

 

09

1

1

INC

R1

R1

R1 + 1

 

 

 

 

 

 

 

0A

1

1

INC

R2

R2

R2 + 1

 

 

 

 

 

 

 

0B

1

1

INC

R3

R3

R3 + 1

 

 

 

 

 

 

 

0C

1

1

INC

R4

R4

R4 + 1

 

 

 

 

 

 

 

0D

1

1

INC

R5

R5

R5 + 1

 

 

 

 

 

 

 

0E

1

1

INC

R6

R6

R6 + 1

 

 

 

 

 

 

 

0F

1

1

INC

R7

R7

R7 + 1

 

 

 

 

 

 

10

3

2

JBC

bitaddr,

Усл. переход если бит = 1 и

 

 

 

 

codeaddr

сброс бита

 

 

 

 

 

 

11

2

2

ACALL

codeaddr

Вызов подпрограммы

 

 

 

 

(0 стр)

в пределах 2 кБ

 

 

 

 

 

 

12

3

2

LCALL

Dataaddr

Вызов подпрограммы

 

 

 

 

 

в пределах 64 кБ

 

 

 

 

 

 

13

1

1

RRC

A

Циклический сдвиг вправо

 

 

 

 

 

через флаг C

 

 

 

 

 

 

14

1

1

DEC

A

ACC ACC - 1

 

 

 

 

 

 

15

2

1

DEC

dataaddr

data data - 1

 

 

 

 

 

 

16

1

1

DEC

@R0

(R0) (R0) - 1

 

 

 

 

 

 

 

127

17

1

1

DEC

@R1

(R1) (R1) - 1

 

 

 

 

 

 

18

1

1

DEC

R0

R0 R0-1

 

 

 

 

 

 

19

1

1

DEC

R1

R1 R1-1

 

 

 

 

 

 

1A

1

1

DEC

R2

R2 R2-1

 

 

 

 

 

 

1B

1

1

DEC

R3

R3 R3-1

 

 

 

 

 

 

1C

1

1

DEC

R4

R4 R4-1

 

 

 

 

 

 

1D

1

1

DEC

R5

R5 R5-1

 

 

 

 

 

 

1E

1

1

DEC

R6

R6 R6-1

 

 

 

 

 

 

1F

1

1

DEC

R7

R7 R7-1

 

 

 

 

 

 

20

3

2

JB

bit addr, data

Условный переход если бит =

 

 

 

 

addr

1

 

 

 

 

 

 

21

2

2

AJMP

code addr

Безусловный переход в преде-

 

 

 

 

(1 стр)

лах 2 кБ

 

 

 

 

 

 

22

1

2

RET

 

Возвращение из подпрограм-

 

 

 

 

 

мы

 

 

 

 

 

 

23

1

1

RL

A

Циклический сдвиг влево

 

 

 

 

 

 

24

2

1

ADD

A, #data

ACC ACC + число

 

 

 

 

 

 

25

2

1

ADD

A, data addr

ACC ACC + data

 

 

 

 

 

 

26

1

1

ADD

A, @R0

ACC ACC + (R0)

 

 

 

 

 

 

27

1

1

ADD

A, @R1

ACC ACC + (R1)

 

 

 

 

 

 

28

1

1

ADD

A, R0

ACC ACC + R0

 

 

 

 

 

 

29

1

1

ADD

A, R1

ACC ACC + R1

 

 

 

 

 

 

2A

1

1

ADD

A, R2

ACC ACC + R2

 

 

 

 

 

 

2B

1

1

ADD

A, R3

ACC ACC + R3

 

 

 

 

 

 

2C

1

1

ADD

A, R4

ACC ACC + R4

 

 

 

 

 

 

2D

1

1

ADD

A, R5

ACC ACC + R5

 

 

 

 

 

 

2E

1

1

ADD

A, R6

ACC ACC + R6

 

 

 

 

 

 

2F

1

1

ADD

A, R7

ACC ACC + R7

 

 

 

 

 

 

30

3

2

JNB

bitaddr,

Условный переход

 

 

 

 

codeaddr

если бит = 0

 

 

 

 

 

 

31

2

2

ACAL

codeaddr

Вызов подпрограммы

 

 

 

L

(1 стр)

в пределах 2 кБ

 

 

 

 

 

 

128

32

1

2

RETI

 

Возвр. из подпр. обслужив.

 

 

 

 

 

прерывания

 

 

 

 

 

 

33

1

1

RLC

A

Циклический сдвиг влево

 

 

 

 

 

через флаг C

 

 

 

 

 

 

34

2

1

ADDC

A, #data

ACC ACC + число + C

 

 

 

 

 

 

35

2

1

ADDC

A, dataaddr

ACC ACC + data + C

 

 

 

 

 

 

36

1

1

ADDC

A, @R0

ACC ACC + (R0) + C

 

 

 

 

 

 

37

1

1

ADDC

A, @R1

ACC ACC + (R1) + C

 

 

 

 

 

 

38

1

1

ADDC

A, R0

ACC ACC + R0+ C

 

 

 

 

 

 

39

1

1

ADDC

A, R1

ACC ACC + R1+ C

 

 

 

 

 

 

3A

1

1

ADDC

A, R2

ACC ACC + R2+ C

 

 

 

 

 

 

3B

1

1

ADDC

A, R3

ACC ACC + R3+ C

 

 

 

 

 

 

3C

1

1

ADDC

A, R4

ACC ACC + R4+ C

 

 

 

 

 

 

3D

1

1

ADDC

A, R5

ACC ACC + R5+ C

 

 

 

 

 

 

3E

1

1

ADDC

A, R6

ACC ACC + R6+ C

 

 

 

 

 

 

3F

1

1

ADDC

A, R7

ACC ACC + R7+ C

 

 

 

 

 

 

40

2

2

JC

codeaddr

Условный переход если флаг

 

 

 

 

 

C = 1

 

 

 

 

 

 

41

2

2

AJMP

codeaddr (2

Безусловный переход в пре-

 

 

 

 

стр)

делах 2 кБ

 

 

 

 

 

 

42

2

1

ORL

dataaddr, A

data data | ACC

 

 

 

 

 

 

43

3

2

ORL

dataaddr, #data

data data | число

 

 

 

 

 

 

44

2

1

ORL

A, #data

ACC ACC | число

 

 

 

 

 

 

45

2

1

ORL

A, data addr

ACC ACC | data

 

 

 

 

 

 

46

1

1

ORL

A, @R0

ACC ACC | (R0)

 

 

 

 

 

 

47

1

1

ORL

A, @R1

ACC ACC | (R1)

 

 

 

 

 

 

48

1

1

ORL

A, R0

ACC ACC | R0

 

 

 

 

 

 

49

1

1

ORL

A, R1

ACC ACC | R1

 

 

 

 

 

 

4A

1

1

ORL

A, R2

ACC ACC | R2

 

 

 

 

 

 

4B

1

1

ORL

A, R3

ACC ACC | R3

 

 

 

 

 

 

4C

1

1

ORL

A, R4

ACC ACC | R4

 

 

 

 

 

 

129

Hex

Число

Число

Мнем.

 

 

цик-

Операнды

Описание команды

код

байт

лов

код

 

 

 

 

 

 

 

 

 

 

 

 

 

4D

1

1

ORL

A, R5

ACC ACC | R5

 

 

 

 

 

 

4E

1

1

ORL

A, R6

ACC ACC | R6

 

 

 

 

 

 

4F

1

1

ORL

A, R7

ACC ACC | R7

 

 

 

 

 

 

50

2

2

JNC

code addr

Условный переход

 

 

 

 

 

если флаг C = 0

 

 

 

 

 

 

51

2

2

ACAL

code addr

Вызов подпрограммы

 

 

 

L

(2 стр)

в пределах 2 кБ

 

 

 

 

 

 

52

2

1

ANL

data addr, A

data data & ACC

 

 

 

 

 

 

53

3

2

ANL

data addr,

data data & число

 

 

 

 

#data

 

 

 

 

 

 

 

54

2

1

ANL

A, #data

ACC ACC & число

 

 

 

 

 

 

55

2

1

ANL

A, data addr

ACC ACC & data

 

 

 

 

 

 

56

1

1

ANL

A, @R0

ACC ACC & (R0)

 

 

 

 

 

 

57

1

1

ANL

A, @R1

ACC ACC & (R1)

 

 

 

 

 

 

58

1

1

ANL

A, R0

ACC ACC & R0

 

 

 

 

 

 

59

1

1

ANL

A, R1

ACC ACC & R1

 

 

 

 

 

 

5A

1

1

ANL

A, R2

ACC ACC & R2

 

 

 

 

 

 

5B

1

1

ANL

A, R3

ACC ACC & R3

 

 

 

 

 

 

5C

1

1

ANL

A, R4

ACC ACC & R4

 

 

 

 

 

 

5D

1

1

ANL

A, R5

ACC ACC R5

 

 

 

 

 

 

5E

1

1

ANL

A, R6

ACC ACC R6

 

 

 

 

 

 

5F

1

1

ANL

A, R7

ACC ACC R7

 

 

 

 

 

 

60

2

2

JZ

codeaddr

если ACC=0 то PC= codeaddr

 

 

 

 

 

иначе PC+2

 

 

 

 

 

 

61

2

2

AJMP

codeaddr

Безусловный переход

 

 

 

 

(3 стр)

в пределах 2 кБ

 

 

 

 

 

 

62

2

1

XRL

dataaddr, A

data data ACC

 

 

 

 

 

 

63

3

2

XRL

dataaddr, #data

data data число

 

 

 

 

 

 

64

2

1

XRL

A, #data

ACC ACC число

 

 

 

 

 

 

65

2

1

XRL

A, data addr

ACC ACC data

 

 

 

 

 

 

130