Лекции
Основы микропроцессорной техники
Глава 1.
Философия микропроцессорной техники
Глава 2.
Организация обмена информацией
Глава 3.
Функционирование процессора
Глава 4.
Организация микроконтроллеров
Глава 5.
Однокристальные микроконтроллеры серии PIC
Глава 6.
Проектирование устройств на микроконтроллерах
  11.   Особенности разработки цифровых ...
  12.   Разработка программного обеспечения для PIC-микроконтроллеров
Глава 7.
Организация персонального компьютера
Глава 8.
Интерфейсы персонального компьютера
      Экзамен

 
 
Основы микропроцессорной техники
Глава 6. Проектирование устройств на микроконтроллерах
Лекция #12: Разработка программного обеспечения для PIC-микроконтроллеров Страницы: « 1 2 3 4 5 вопросы »

6.3.3. Программирование учебных задач

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

;основная программа
LOOP
   CLRWDT
   CALL
   CALL
   GOTO

;
GET_RA

   MOVF
   MOVWF
   RETURN
;
SB1_VD2


   BTFSS

   GOTO
   BSF
P0
   BTFSC

   GOTO
   BCF
P1
   RETURN
;


   GET_RA
   SB1_VD2
   LOOP




   PORTA,W
   TEMPA





   TEMPA,4

   P0
   VD2

   TEMPA,4

   P1
   VD2

   ;сброс сторожевого таймера
   ;вызов подпрограммы GET_RA
   ;вызов подпрограммы SB1_VD2
   ;переход к метке LOOP для
   ;повторения процесса

   ;подпрограмма чтения состояния
   ;порта A
   ;чтение состояния порта A в W
   ;пересылка W в TEMPA
   ;возврат из подпрограммы

   ;подпрограмма вывода на светодиод
   ;VD2 состояния кнопки SB1 (разряда 4
   ;регистра TEMPA)
   ;пропустить команду, если
   ;TEMPA,4=1 (кнопка не нажата)
   ;перейти на P0
   ;зажечь светодиод VD2

   ;пропустить команду, если
   ;TEMPA,4=0 (кнопка нажата)
   ;перейти на P1
   ;погасить светодиод

Основная программа содержит замкнутый цикл LOOP – GOTO LOOP, необходимый для периодического повторения цикла контроля состояния кнопки и вывода его на индикатор. Команда CLRWDT исключает влияние возможного сброса по переполнению сторожевого таймера на работу программы. Две следующие команды осуществляют вызов подпрограмм GET_RA и SB1_VD2. Первая из них (GET_RA) вначале считывает текущее состояние порта A, которое помещается в рабочий регистр W. Поскольку рабочий регистр может потребоваться при исполнении других команд, его состояние записывается в регистр TEMPA, используемый здесь для временного хранения состояния порта A. Таким образом, после возврата из подпрограммы GET_RA в разряде 4 регистра TEMPA содержится информация о состоянии кнопки SB1: «1» – не нажата, «0» – нажата.

Подпрограмма SB1_VD2 анализирует состояние разряда 4 регистра TEMPA и, в зависимости от него, зажигает или гасит светодиод. В системе команд МК PIC16F84 нет команд условного перехода, поэтому для организации проверки того или иного условия используются команды, позволяющие пропустить выполнение следующей команды программы, в зависимости от состояния определенного бита в заданном регистре (BTFSS и BTFSC). В частности, команда BTFSS TEMP,4 пропускает исполнение команды GOTO P0, если TEMP,4 = 1 (кнопка не нажата). Тем самым реализуется команда BSF VD2, которая зажигает светодиод VD2. Затем анализируется условие TEMP,4 = 0 (кнопка нажата) и, если оно имеет место, светодиод гасится.

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

Рассмотрим более сложный вариант программы, предусматривающий зажигание светодиода VD2 только при следующем состоянии тумблеров и кнопок макета: SA1 = 1, SA2 = 1, SB1 = 1 и SB2 = 0.

;основная программа
   LOOP
   CLRWDT
   CALL
   CALL
   CALL
   GOTO

;
GET_RB

   MOVF
   MOVWF
   RETURN
;
ZAG_1110



   BTFSS
   GOTO
   BTFSS
   GOTO
   BTFSS
   GOTO
   BTFSC
   GOTO
   BSF
   GOTO
P0
   BCF
P1
   RETURN
;   
   INCLUDE
;


   GET_RA
   GET_RB
   ZAG_1110
   LOOP




   PORTB,W
   TEMPB






   TEMPA,2
   P0
   TEMPA,3
   P0
   TEMPA,4
   P0
   TEMPB,0
   P0
   VD2
   P1

   VD2



   GET_RA.ASM

   ;сброс сторожевого таймера
   ;вызов подпрограммы GET_RA
   ;вызов подпрограммы GET_RB
   ;вызов подпрограммы ZAG_1110
   ;переход к метке LOOP для
   ;повторения процесса

   ;подпрограмма чтения состояния
   ;порта B
   ;чтение состояния порта B в W
   ;пересылка W в TEMPB


   ;зажигает светодиод VD2 только при
   ;следующем состоянии тумблеров и
   ;кнопок макета:
   ;SA1 = SA2 = SB1 = 1 и SB2 = 0
   ;пропустить команду, если
   ;TEMPA,2=1
   ;пропустить команду, если
   ;TEMPA,3=1
   ;пропустить команду, если
   ;TEMPA,4=1
   ;пропустить команду, если
   ;TEMPB,0=0
   ;зажечь светодиод VD2


   ;погасить светодиод VD2

Подпрограммы GET_RA и GET_RB помещают в регистры TEMPA и TEMPB текущие состояния портов A и B, соответственно. Подпрограмма ZAG_1110 анализирует состояния разрядов 2,3 и 4 регистра TEMPA и разряда 0 регистра TEMPB, и при условии TEMPA,2,3,4 = 1,1,1 и TEMPB,0 = 0, зажигает светодиод VD2. При невыполнении хотя бы одного из этих условий светодиод гасится.

Использование директивы INCLUDE GET_PORTA.ASM позволяет включать уже отлаженные модули подпрограмм в текущую программу. Для того чтобы этой возможностью можно было воспользоваться, необходимо сохранять отлаженные модули в виде отдельных ассемблерных файлов.

Попробуем теперь использовать семисегментный индикатор для контроля состояния тумблеров макета. Вначале напишем программу, которая выводит на индикатор HL семисегментное изображение любого двоичного числа от 0b до 1111b в шестнадцатиричном представлении.

;основная программа
   LOOP
   CLRWDT
   MOVLW
   CALL
   MOVWF
   GOTO

;
SEV_SEG

   ANDLW

   ADDWF

   RETLW
   RETLW
   RETLW
   RETLW
   RETLW
   RETLW
   RETLW
   RETLW
   RETLW
   RETLW
   RETLW
   RETLW
   RETLW
   RETLW
   RETLW
   RETLW
;


   0x0A
   SEV_SEG
   PORTB
   LOOP




   0x0F

   PCL,F

   0x80
   0xF2
   0x48
   0x60
   0x32
   0x25
   0x04
   0xF0
   0x00
   0x20
   0x10
   0x06
   0x8C
   0x42
   0x0C
   0x1C

   ;сброс сторожевого таймера
   ;пересылка константы 0A в W
   ;вызов подпрограммы SEVEN_SEG
   ;пересылка W в PORTB
   ;переход к метке LOOP для
   ;повторения процесса

   ;подпрограмма обслуживания
   ;семисегментного индикатора
   ;маскирование 4-х младших разрядов
   ;W и обнуление 4-х старших
   ;сложение W с PCL и пересылка
   ;результата в PCL
   ;возврат из подпрограммы с 80 в W
   ;возврат из подпрограммы с F2 в W
   ;возврат из подпрограммы с 48 в W
   ;возврат из подпрограммы с 60 в W
   ;возврат из подпрограммы с 32 в W
   ;возврат из подпрограммы с 25 в W
   ;возврат из подпрограммы с 04 в W
   ;возврат из подпрограммы с F0 в W
   ;возврат из подпрограммы с 00 в W
   ;возврат из подпрограммы с 20 в W
   ;возврат из подпрограммы с 10 в W
   ;возврат из подпрограммы с 06 в W
   ;возврат из подпрограммы с 8C в W
   ;возврат из подпрограммы с 42 в W
   ;возврат из подпрограммы с 0C в W
   ;возврат из подпрограммы с 1C в W

Программа начинает свою работу с пересылки константы 0x0A в рабочий регистр W. Затем производится вызов подпрограммы обслуживания семисегментного индикатора SEV_SEG. Работа подпрограммы SEV_SEG начинается с маскирования 4-х младших разрядов W и обнуления 4-х старших. Тем самым из анализа исключаются старшие разряды передаваемого из рабочего регистра W числа. Затем маскированное содержимое регистра W добавляется к текущему состоянию младшего байта счетчика команд PCL, и результат помещается в PCL. Таким образом, производится дополнительное смещение счетчика команд на величину, которая была передана в рабочем регистре. Например, если было W=0, то содержимое счетчика команд не изменится, и будет выполнена следующая команда RETLW 0x80, которая вызовет возврат из подпрограммы с записью 0x80 = B'1000000' в регистр W. Если, как было в приведенной программе, W=0A, то к содержимому PCL будет добавлено число 0x0A, и произойдет дополнительное смещение на 10 шагов. В результате будет выполнена команда RETLW 0x10, которая вызовет возврат из подпрограммы с записью 0x10 = B'0001000' в регистр W.

После возврата из подпрограммы производится пересылка W в PORTB и отображение его состояния на семисегментном индикаторе HL. В частности, если W = 0, то при выводе 1000000b на порт B семисегментный индикатор покажет , а при W = A покажет .Таким образом, может быть отображено любое 4-разрядное двоичное число.

Метод прямого управления счетчиком команд, использованный в подпрограмме SEV_SEG, может применяться для реализации табличной конвертации чисел. При этом необходимо иметь в виду, что данный метод не позволяет конвертировать более 256 значений в одной таблице. Кроме того, программа табличной конвертации должна целиком располагаться внутри 256-байтного блока во избежание переполнения младшего байта счетчика команд.

Используя подпрограмму SEV_SEG, напишем теперь программу, которая читает состояния тумблеров SA1 и SA2 и выводит на индикатор соответствующее число.

;основная программа
   LOOP
   CLRWDT
   CALL
   RRF

   RRF

   ANDLW
   CALL
   MOVWF
   GOTO

;
   INCLUDE
   INCLUDE
;


   GET_RA
   TEMPA,F

   TEMPA,W

   0x03
   SEV_SEG
   PORTB
   LOOP


   GET_RA.ASM
   SEV_SEG.ASM

   ;сброс сторожевого таймера
   ;вызов подпрограммы GET_RA
   ;сдвиг вправо на один разряд
   ;через перенос
   ;сдвиг вправо на один разряд
   ;через перенос
   ;маска на два младших разряда
   ;вызов подпрограммы SEVEN_SEG
   ;пересылка W в PORTB
   ;переход к метке LOOP для
   ;повторения процесса

Подпрограмма GET_RA помещает в регистр TEMPA текущее состояние порта A. Таким образом, в разрядах 2 и 3 регистра TEMPA хранится текущее состояние тумблеров SA1 и SA2. Для того чтобы биты состояния тумблеров заняли позиции 0 и 1 регистра TEMPA, производится два сдвига вправо через перенос, причем результат второго сдвига помещается в регистр W. Затем накладывается маска на два младших разряда рабочего регистра и производится вызов подпрограммы SEV_SEG. После выхода из подпрограммы результат подается на порт B и отображается на индикаторе.

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

;основная программа
   MOVLW
   CALL
;
   DELAY

   MOVWF
LOOPD
   DECFSZ
   GOTO
   RETURN
;
   0xL
   DELAY



   COUNT1

   COUNT1,F
   LOOPD
   ;пересылка константы H'L' в W
   ;вызов подпрограммы DELAY

   ;подпрограмма формирования
   ;задержки времени
   ;загрузка W в регистр COUNT1

   ;декремент COUNT1
   ;повторение цикла H'L' раз
   ;возврат из подпрограммы

Основная программа производит вызов подпрограммы DELAY с некоторой константой L в рабочем регистре W, определяющей число внутренних циклов подпрограммы. Подпрограмма DELAY начинает свою работу с загрузки содержимого рабочего регистра в регистр пользователя COUNT1. Команда DECFSZ COUNT1,F уменьшает на единицу содержимое регистра COUNT1 и проверяет его на равенство нулю. Нулевое состояние регистра COUNT1 приводит к выходу из цикла и возврату из подпрограммы. Для исполнения каждого внутреннего цикла требуется три машинных цикла МК (1 цикл на исполнение команды DECFSZ при ненулевом результате и 2 цикла на каждую команду GOTO). Выход из подпрограммы DELAY потребует 4-х циклов (2 цикла на исполнение команды DECFSZ при нулевом результате и 2 цикла на RETURN). Если добавить к этому еще 4 цикла, необходимых для загрузки константы в рабочий регистр, вызова подпрограммы и загрузки регистра пользователя COUNT1, то общее время исполнения подпрограммы DELAY (задержка) составит

TD = 4 + 3*(L – 1) + 4 = 5 + 3*L циклов,

где L – константа, переданная через рабочий регистр в подпрограмму DELAY.

При тактовой частоте fosc = 2МГц время цикла равно tц = 2 мкс, поэтому при загрузке L = H'00' = .0 максимальный формируемый интервал времени составит 1,55 мс. Такой результат связан с тем, что команда DECFSZ сначала декрементирует содержимое регистра (H'00' – 1 = H'FF'), а затем уже анализирует результат.

Минимальный формируемый интервал времени составит при тех же условиях 5 циклов или 10 мкс. Для получения такого интервала необходимо перед вызовом подпрограммы DELAY загрузить в рабочий регистр число 0x01.

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

;
   DELAY_C

   MOVWF
LOOPD
   NOP
   DECFSZ
   GOTO
   RETURN
;



   MOVWF COUNT1


   COUNT1,F
   LOOPD

   ;подпрограмма формирования
   ;задержки времени (вариант C)
   ;загрузка W в регистр COUNT1

   ;пустая команда
   ;декремент COUNT1
   ;повторение цикла H'L' раз
   ;возврат из подпрограммы

Общее время исполнения подпрограммы DELAY_C, включая ее вызов, составит

TD = 4 + 4*(L – 1) + 4 = 4 + 4*L циклов.

При тактовой частоте fosc = 2МГц и загрузке константы L = H'F9' = .249 формируемый интервал времени составит ровно 2 мс. Уменьшение константы на единицу уменьшает формируемый временной интервал на 8 мкс. В частности, при L = .124 образуется задержка в 1 мс.

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

;основная программа
   MOVLW
   CALL
;
DELAY_D

   MOVWF
   CLRF
LOOPD
   DECFSZ
   GOTO
   CLRWDT
   DECFSZ
   GOTO
   RETURN
;
   0xL
   DELAY_D



   COUNT2
   COUNT1

   COUNT1,F
   LOOPD

   COUNT2,F
   LOOPD
   ;пересылка константы H'L' в W
   ;вызов подпрограммы DELAY_D

   ;подпрограмма формирования
   ;большой задержки времени (вариант D)
   ;загрузка W в регистр COUNT2
   ;сброс содержимого регистра COUNT1

   ;декремент COUNT1
   ;повторение цикла 256 раз
   ;сброс сторожевого таймера
   ;декремент COUNT2
   ;повторение цикла H'L' раз
   ;возврат из подпрограммы

Время исполнения внутреннего цикла подпрограммы DELAY_D составляет 3*256 + 4 машинных циклов МК, поэтому общая задержка составит

TD = 5 + (3*256 + 4)*L циклов.

При тактовой частоте fosc = 2МГц время цикла равно tц = 2 мкс, поэтому при загрузке L = H'00' = .0 максимальный формируемый интервал времени составит около 0,4 с.

Поскольку формируемый интервал времени достаточно велик, во внешний цикл включена команда сброса сторожевого таймера.

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

;
DELAY_E

   MOVWF
   CLRF
LOOPD
   NOP
   DECFSZ
   GOTO
   CLRWDT
   DECFSZ
   GOTO
   RETURN
;



   COUNT2
   COUNT1


   COUNT1,F
   LOOPD

   COUNT2,F
   LOOPD

   ;подпрограмма формирования
   ;большой задержки времени (вариант E)
   ;загрузка W в регистр COUNT2
   ;сброс содержимого регистра COUNT1

   ;пустая команда
   ;декремент COUNT1
   ;повторение цикла 256 раз
   ;сброс сторожевого таймера
   ;декремент COUNT2
   ;повторение цикла H'L' раз
   ;возврат из подпрограммы

Время исполнения внутреннего цикла подпрограммы DELAY_E составляет 4*256 + 4 машинных циклов МК, поэтому общая задержка составит

TD = 5 + (4*256 + 4)*L циклов.

При тактовой частоте fosc = 2МГц и при загрузке L = H'F3' = .243 формируемый интервал времени составит около 0,5 с при погрешности не более 0,2%. Если необходима более высокая точность, можно вставить необходимое количество пустых операций во внешний цикл формирования задержки.

Рассмотрим далее несколько программ с использованием подпрограмм формирования задержки времени. Начнем с написания программы, которая подает звуковой сигнал на динамик BA1 при нажатии на кнопку SB1. Динамик будет звучать только в том случае, если на выход RA0 будет подан периодически изменяющийся сигнал. Для того чтобы звук был хорошо слышен, его частота должна находиться вблизи максимума слышимости человеческого уха. Выберем частоту звучания равной 1 КГц, что соответствует периоду следования импульсов сигнала 1 мс.

;основная программа
LOOP
   CLRWDT
   CALL
   CALL
   GOTO

;
SB1_BA1


   BTFSC

   GOTO
   BSF
   MOVLW

   CALL
   BCF
   MOVLW

   CALL
B0
   RETURN
;
   INCLUDE
   INCLUDE
;


   GET_RA
   SB1_BA1
   LOOP





   TEMPA,4

   B0
   BA1
   0x3E

   DELAY_C
   BA1
   0x3E

   DELAY_C



   GET_RA.ASM
   DELAY_C.ASM

   ;сброс сторожевого таймера
   ;вызов подпрограммы GET_PORTA
   ;вызов подпрограммы SB1_BA1
   ;переход к метке LOOP для
   ;повторения процесса

   ;подпрограмма подачи звука на
   ;динамик BA1 при нажатии на кнопку
   ;SB1
   ;пропустить команду, если
   ;TEMPA,4=0 (кнопка нажата)
   ;перейти на B0
   ;подача высокого уровня на RA0
   ;пересылка константы
   ;H'3E' = .62 в W
   ;вызов подпрограммы DELAY_C
   ;подача низкого уровня на RA0
   ;пересылка константы
   ;H'3E' = .62 в W
   ;вызов подпрограммы DELAY_C

Как и раньше, подпрограмма GET_RA считывает текущее состояние порта A, которое затем передается в регистр TEMPA. Подпрограмма SB1_BA1 анализирует состояние разряда 4 регистра TEMPA и, в зависимости от результата, озвучивает динамик BA1 или нет. Необходимая выдержка линии RA0 в единичном и нулевом состояниях обеспечивается подпрограммой DELAY_C с параметром L = H'3E' = .62. Это соответствует времени задержки около 0,5 мс, что и дает в результате необходимую частоту следования сигнала 1 Кгц.

Рассмотрим далее программу, которая заставляет мигать светодиод VD2 при нажатии на кнопку SB1. Для того чтобы мигания были хорошо видны, выберем их частоту равной 1 Гц.

;основная программа
LOOP
   CLRWDT
   CALL
   CALL

   GOTO

;
SB1_VD2M

   BTFSC

   GOTO
   BSF
   MOVLW

   CALL
   BCF
   MOVLW

   CALL
V0
   BTFSS

   GOTO
   BCF
V1
   RETURN
;
   INCLUDE
   INCLUDE
;


   GET_RA
   SB1_VD2M

   LOOP




   TEMPA,4

   V0
   VD2
   0xF3

   DELAY_E
   VD2
   0xF3

   DELAY_E

   TEMPA,4

   V1
   VD2



   GET_RA.ASM
   DELAY_E.ASM

   ;сброс сторожевого таймера
   ;вызов подпрограммы GET_RA
   ;вызов подпрограммы
   ;SB1_VD2M
   ;переход к метке LOOP для
   ;повторения процесса

   ;подпрограмма мигания светодиода
   ;VD2 при нажатии на кнопку SB1
   ;пропустить команду, если
   ;TEMPA,4=0 (кнопка нажата)
   ;перейти на V0
   ;зажечь светодиод VD2
   ;пересылка константы
   ;H'F3' = .243 в W
   ;вызов подпрограммы DELAY_E
   ;погасить светодиод
   ;пересылка константы
   ;H'F3' = .243 в W
   ;вызов подпрограммы DELAY_E

   ;пропустить команду, если
   ;TEMPA,4=1 (кнопка не нажата)
   ;перейти на V1
   ;погасить светодиод

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

Подпрограммы формирования задержки времени могут быть также полезны при работе с такими внешними источниками сигналов, как тумблеры, кнопки, переключатели и т.п. Дело в том, что все механические коммутаторы имеют одно негативное свойство, известное как «дребезг» контактов, которое обусловлено механическими колебаниями контактов при их замыкании и размыкании. Длительность колебаний составляет обычно несколько миллисекунд, в течение которых на вход МК может поступать пачка импульсов вместо идеального перепада.

Аппаратные способы борьбы с «дребезгом» контактов основаны на использовании RS-триггеров, одновибраторов или триггеров Шмитта. В устройствах на основе МК подавление «дребезга» контактов обычно осуществляется программными способами, которые основаны на повторном считывании состояния линии порта через определенное время.

В качестве примера рассмотрим «бездребезговый» вариант подпрограммы чтения состояния порта A.

;
GET_RAD


DD
   MOVF
   ANDLW

   MOVWF
   CLRWDT
   MOVLW

   CALL
   MOVF
   ANDLW
   SUBWF
   BTFSS

   GOTO
   RETURN
;
   INCLUDE
;





   PORTA,W
   0x1C

   TEMPA

   0x0A

   DELAY_E
   PORTA,W
   0x1C
   TEMPA,W
   Z

   DD


   DELAY_E.ASM

   ;подпрограмма чтения состояния
   ;порта A в регистр TEMPA
   ;с подавлением "дребезжания"

   ;чтение состояния порта A в W
   ;наложение маски b'00011100'
   ;на неиспользуемые биты W
   ;пересылка W в TEMPA
   ;сброс сторожевого таймера WDT
   ;пересылка константы
   ;H'0A' = .10 в W
   ;вызов подпрограммы DELAY_E
   ;чтение состояния порта A в W
   ;наложение на W маски b'00011100'
   ;вычитание W из ТЕМРA
   ;пропустить команду, если результат
   ;нулевой
   ;перейти на метку DD

Суть работы подпрограммы заключается в повторном чтении состояния порта A спустя некоторое время после предыдущего и сравнении его с прежним значением. Константа H'0A' = .10, пересылаемая в регистр W перед вызовом подпрограммы DELAY_E, обеспечивает значение задержки времени около 20 мс - этого, как правило, достаточно для завершения переходных процессов при переключении механических коммутаторов. Маскирование неиспользуемых разрядов порта повышает надежность работы подпрограммы. Сброс сторожевого таймера перед вызовом подпрограммы задержки нужен для исключения сброса МК между двумя процедурами опроса порта A.

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

;основная программа
   CLRF
LOOP
   CLRWDT
   CALL
   BTFSC
   GOTO

   INCF
   MOVF

   CALL
   MOVWF
TEST
   CALL
   BTFSS
   GOTO

   GOTO
;
   INCLUDE
   INCLUDE
;
   COUNT3


   GET_RAD
   TEMPA,4
   LOOP

   COUNT3,F
   COUNT3,W

   SEV_SEG
   PORTB

   GET_RAD
   TEMPA,4
   TEST

   LOOP

   GET_RAD.ASM
   SEV_SEG.ASM
   ;сброс счетчика нажатий

   ;сброс сторожевого таймера
   ;вызов подпрограммы GET_RAD
   ;проверка нажатия SB1
   ;если не нажата – возврат
   ;на метку LOOP
   ;инкремент счетчика
   ;пересылка содержимого
   ;счетчика в рабочий регистр
   ;вызов подпрограммы SEVEN_SEG
   ;пересылка W в PORTB

   ;вызов подпрограммы GET_RAD
   ;проверка нажатия SB1
   ;если еще нажата – возврат
   ;на метку TEST
   ;возврат на метку LOOP

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

Страницы: « 1 2 3 4 5 вопросы »