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


Пример 1. Мигающие светодиоды

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

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

Рассмотрим следующую программу.

 

            LIST        P=PIC16F84A
            __CONFIG    H3FF1

STATUS      EQU         H0003
PORTB       EQU         H0006
TRISB       EQU         H0006
Reg_1       EQU         H000C
Reg_2       EQU         H000D
Reg_3       EQU         H000E

            org         0           ; начало программы            
; подготовительные моменты
            bsf         STATUS,5    ; переход в Банк 1
            clrf        TRISB
            bcf         STATUS,5    ; переход назад в Банк 0
; установка сигналов на порту В
m1          movlw       b11111111 ; запись в аккумулятор
            movwf       PORTB       ; перенос из аккумулятора в порт
            call        Pause       ; переход на метку (с возвратом)
            clrf        PORTB       ; "очистка" порта
            call        Pause       ; переход на метку (с возвратом)
            goto        m1          ; переход на метку (зацикливание)


;delay = 500000 machine cycles
Pause       movlw       .85
            movwf       Reg_1
            movlw       .138
            movwf       Reg_2
            movlw       .3
            movwf       Reg_3
wr          decfsz      Reg_1, F
            goto        wr
            decfsz      Reg_2, F
            goto        wr
            decfsz      Reg_3, F
            goto        wr
           
            return

            end                     ; конец программы

 

И собственно результат компиляции – текст прошивки:

 

:020000040000FA
:10000000831686018312FF308600092086010920AD
:10001000032855308C008A308D0003308E008C0B05
:0C0020000F288D0B0F288E0B0F280800F6
:02400E00F13F80
:00000001FF

 

Разберем эту программу. В шапке программы появилось обозначение трех регистров общего назначения как, например, Reg_1 EQU H000C . Закономерен вопрос – почему именно такие имена и такие адреса? Адреса регистров общего назначения согласно документации лежат в диапазоне от h0C до h4F , т.е. всего 68 регистров; первые три регистра из этого диапазона мы именовали для наших дальнейших целей. Имена регистров выбраны по причине рациональности использования как в плане перечисления, так и в плане восприятия. Действительно, проще регистрам дать "бытовые" номера, чем придумывать какие-то имена и путаться в них.

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

Далее следует сегмент установки сигналов на порту. Этот сегмент является основным в работе программы. Суть проста. Сначала устанавливается на всех ножках сигнал высокого уровня (2 команды). Затем выдерживается пауза 0,5 сек (светодиоды включены). Затем порт очищается, что приводит к установке сигналов низкого уровня. Снова пауза (светодиоды выключены). И, наконец, переход к началу, что зацикливает нашу программу.

Переход к сегменту паузы производится командой call Pause . Эта команда, как мы упоминали ранее в главе 2, используется в паре  с одной из двух команд (RETLW и RETURN). Собственно команду RETURN мы видим в конце сегмента паузы.

Сегмент паузы осуществляет задержку в программе длительностью 0,5 сек. Понятие о времени и расчет задержек рассмотрен в главе 3. Мы использовали программу Pause ver1.2 для создания сегмента паузы. После этого несложно догадаться, почему регистрам общего назначения даны такие. С другой стороны, нет никаких препятствий переименовать регистры в созданном сегменте паузы. Нами был выбран путь меньшего сопротивления.

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

 

; установка сигналов на порту В
m1          movlw       b11111111 ; запись в аккумулятор
            movwf       PORTB       ; перенос из аккумулятора в порт
            call        Pause1      ; переход на метку (с возвратом)
            clrf        PORTB       ; "очистка" порта
            call        Pause2      ; переход на метку (с возвратом)
            goto        m1          ; переход на метку (зацикливание)

;delay = 500000 machine cycles
Pause1      movlw       .85
            movwf       Reg_1
            movlw       .138
            movwf       Reg_2
            movlw       .3
            movwf       Reg_3
wr1         decfsz      Reg_1, F
            goto        wr1
            decfsz      Reg_2, F
            goto        wr1
            decfsz      Reg_3, F
            goto        wr1
            return

;delay = 1000000 machine cycles
Pause2      movlw       .173
            movwf       Reg_1
            movlw       .19
            movwf       Reg_2
            movlw       .6
            movwf       Reg_3
wr2         decfsz      Reg_1, F
            goto        wr2
            decfsz      Reg_2, F
            goto        wr2
            decfsz      Reg_3, F
            goto        wr2           
            return

 

Здесь два сегмента паузы помеченные метками Pause1 и Pause2. Для правильности работы сегментов метки wr в соответствующих сегментах паузы переименованы в wr1 и wr2. Обратите внимание, в разных сегментах паузы используются одинаковые регистры общего назначения, т.к. в начале каждой паузы эти регистры заполняются своими значениями.

И даже в этом случае, программу можно попытаться упростить.

 

; установка сигналов на порту В

m1          movlw       b11111111 ; запись в аккумулятор

            movwf       PORTB       ; перенос из аккумулятора в порт

            call        Pause1      ; переход на метку (с возвратом)

            clrf        PORTB       ; "очистка" порта

            call        Pause1      ; переход на метку (с возвратом)

            call        Pause1      ; переход на метку (с возвратом)

            goto        m1          ; переход на метку (зацикливание)

 

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

В заключении этого примера предлагаю вам самостоятельно модифицировать программу и исключить команду очистки порта (clrf PORTB). Вместо этого предлагаю "затирать" число в порту B другим числом, отличающимся от нуля. Даю подсказку – вам потребуется пара команд (movlw и movwf). Поэкспериментируйте, вам понравится.


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

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

 








 
 
 

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