Файл: Самоучитель по программированию PIC контроллеров для начинающих (Е.А. Корабельников,2008).pdf
ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 16.06.2025
Просмотров: 3640
Скачиваний: 3
;ГРУППА ПОДПРОГРАММ ПРЕОБРАЗОВАНИЯ 4-БАЙТНЫХ ДВОИЧНЫХ ЧИСЕЛ В 8-РАЗРЯДНЫЕ
;ДЕСЯТИЧНЫЕ ЧИСЛА.
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;Подготовка к преобразованию.
;================================================================================
Bin2_10 |
bcf |
Status,C |
; |
Сброс флага переноса-заёма. |
|
movlw |
.32 |
; |
Запись в регистр Count числа проходов |
||
movwf |
Count |
; |
преобразования, равного суммарному |
||
; |
количеству битов многоразрядного регистра |
||||
; |
TimerL/TimerM/TimerH/TimerHH (8*4=32). |
||||
clrf |
LED0 |
; |
Сброс в 0 содержимого регистра LED0. |
||
clrf |
LED1 |
; |
-------"------ |
LED1. |
|
clrf |
LED2 |
; |
-------"------ |
LED2. |
|
clrf |
LED3 |
; |
-------"------ |
LED3. |
|
clrf |
LED4 |
; |
-------"------ |
LED4. |
|
clrf |
LED5 |
; |
-------"------ |
LED5. |
|
clrf |
LED6 |
; |
-------"------ |
LED6. |
|
clrf |
LED7 |
; |
-------"------ |
LED7. |
|
;------------------------------------------------------------------------------- |
|||||
; Примечание: процесс преобразования |
заканчивается при уменьшении числа проходов |
||||
; преобразования, которые заложены в регистр Count (.32), до нуля.
;================================================================================
; Циклический сдвиг влево.
;================================================================================
Loop16 |
rlf |
TimerL,F |
; Циклический сдвиг влево 4-байтного двоичного |
rlf |
TimerM,F |
; числа, записанного в группе регистров |
|
rlf |
TimerH,F |
; TimerL/TimerM/TimerH/TimerHH, на одну |
|
rlf |
TimerHH,F |
; позицию через бит С регистра STATUS. |
|
rlf |
LED0,F |
; Циклический сдвиг влево 4-байтного двоичного |
|
rlf |
LED1,F |
; числа, записанного в группе регистров |
|
rlf |
LED2,F |
; LED0/LED1/LED2/LED3, на одну позицию через |
|
rlf |
LED3,F |
; бит С регистра STATUS. |
|
decfsz |
Count,F |
; Декремент (-1) содержимого регистра Count с |
|
; сохранением результата в нем же. |
|||
goto |
adjDEC |
; Если результат не=0, то переход в ПП adjDEC |
|
; Если результат =0, то программа |
|||
; исполняется далее. |
;================================================================================
; |
Поразрядное |
распределение содержимого регистров LED0... |
3 (обоих |
|
; |
полубайтов) |
по младшим полубайтам регистров LED0... |
7. |
|
;================================================================================
swapf |
LED3,W |
; Запись старшего полубайта LED3 |
andlw |
0Fh |
; в младший полубайт LED7. |
movwf |
LED7 |
; -------------------------------- |
movfw |
LED3 |
; Запись младшего полубайта LED3 |
andlw |
0Fh |
; в младший полубайт LED6. |
movwf |
LED6 |
; -------------------------------- |
swapf |
LED2,W |
; Запись старшего полубайта LED2 |
andlw |
0Fh |
; в младший полубайт LED5. |
movwf |
LED5 |
; -------------------------------- |
movfw |
LED2 |
; Запись младшего полубайта LED2 |
andlw |
0Fh |
; в младший полубайт LED4. |
movwf |
LED4 |
; -------------------------------- |
swapf |
LED1,W |
; Запись старшего полубайта LED1 |
andlw |
0Fh |
; в младший полубайт LED3. |
movwf |
LED3 |
; -------------------------------- |
movfw |
LED1 |
; Запись младшего полубайта LED1 |
andlw |
0Fh |
; в младший полубайт LED2. |
movwf |
LED2 |
; -------------------------------- |
245
swapf |
LED0,W |
; Запись |
старшего полубайта LED0 |
|
andlw |
0Fh |
; в младший полубайт LED1. |
||
movwf |
LED1 |
; -------------------------------- |
||
movfw |
LED0 |
; Запись |
младшего полубайта LED0 |
|
andlw |
0Fh |
; в младший полубайт LED0. |
||
movwf |
LED0 |
; -------------------------------- |
||
;-------------------------------------------------------------------- |
||||
; Конец распределения. В младших полубайтах |
регистров LED0... |
7 |
||
;установлены двоично-десятичные числа в порядке возрастания разрядности.
;Старшие полубайты = 0.
;-------------------------------------------------------------------- |
||
return |
; |
Переход по стеку в группу подпрограмм |
; |
8-разрядной динамической индикации. |
;================================================================================
; Запись в регистр FSR адресов регистров LED0...3 для дальнейшей косвенной
;адресации к ним в ПП adjBCD.
;Переход к обработке следующего LED - после возврата по стеку.
;================================================================================
adjDEC |
movlw |
LED0 |
; |
Запись в регистр FSR, через регистр W, |
|
movwf |
FSR |
; |
адреса регистра LED0 с дальнейшим переходом |
||
call |
adjBCD |
; |
в ПП adjBCD (адрес следующей команды |
||
; |
закладывается в стек). |
||||
;--- |
> Возврат по стеку из ПП adjBCD. |
||||
movlw |
LED1 |
; |
----------------------------- |
||
movwf |
FSR |
; |
То же самое для регистра LED1. |
||
call |
adjBCD |
; |
----------------------------- |
||
;--- |
> Возврат по стеку из ПП adjBCD. |
||||
movlw |
LED2 |
; |
----------------------------- |
||
movwf |
FSR |
; |
То же самое для регистра LED2. |
||
call |
adjBCD |
; |
----------------------------- |
||
;--- |
> Возврат по стеку из ПП adjBCD. |
||||
movlw |
LED3 |
; |
----------------------------- |
||
movwf |
FSR |
; |
То же самое для регистра LED3. |
||
call |
adjBCD |
; |
----------------------------- |
||
;--- |
> Возврат по стеку из ПП adjBCD. |
||||
goto |
Loop16 |
; |
Проход всех LED (с LED0 по LED3). Переход в |
||
; |
ПП Loop16, то есть на следующее кольцо |
||||
; |
числовых преобразований. |
||||
;================================================================================
; Основные операции преобразования двоичных чисел в двоично-десятичные:
; операции сложения LED0...3 и констант 03h,30h с условиями по 3-му и 7-му битам.
;================================================================================
adjBCD |
movlw |
3 |
; Сложить содержимое |
текущего LED (LED0...3) с |
addwf |
0,W |
; числом 03h, c записью результата операции, |
||
movwf |
Mem |
; через регистр W, в |
регистр Mem. |
|
btfsc |
Mem,3 |
; Анализ состояния 3-го бита регистра Mem. |
||
movwf |
0 |
; Если бит № 3 =1, то содержимое регистра Mem |
||
; копируется в текущий LED. |
||||
movlw |
30 |
; Если бит №3 =0, то |
содержимое текущего LED |
|
addwf |
0,W |
; складывается с константой 30h, с последующей |
||
movwf |
Mem |
; записью результата |
операции, через регистр |
|
; W, в регистр Mem. |
||||
btfsc |
Mem,7 |
; Анализ состояния 7-го бита регистра Mem. |
||
movwf |
0 |
; Если бит №7 =1, то |
содержимое регистра Mem |
|
; копируется в текущий LED. |
||||
retlw |
0 |
; Если бит №7 =0, то |
регистр W очищается и |
|
; происходит возврат |
по стеку в ПП adjDEC. |
|||
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;ГРУППА КОМАНД ПРЕОБРАЗОВАНИЯ ДВОИЧНО-ДЕСЯТИЧНОГО КОДА В КОД 7-СЕГМЕНТНОГО
;ИНДИКАТОРА (относится к группе подпрограмм динамической индикации).
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ TABLE .....................................
;.....................................
246
; .....................................
;******************************************************************************** end ; Конец программы.
Сначала разберемся с общей "конструкцией" программы.
Вначале ее исполнения, рабочая точка программы начинает свое движение по "линейному" участку ПП START, начиная с 1-й ее команды и до команды call Bin2_10.
После исполнения команды call Bin2_10, рабочая точка программы "прыгает" на 1-ю команду ПП преобразований чисел Bin2_10, после чего она начнет исполняться.
Врезультате исполнения команды call Bin2_10, адрес команды, следующей за командой call Bin2_10, "закладывается" в стек и находится там до окончания отработки ПП Bin2_10. После окончания отработки ПП Bin2_10 (после исполнения команды return), из вершины стека "выгружается" указанный выше адрес, и после отработки всех оставшихся команд ПП START, начинается исполнение ПП динамической индикации (то, о чем говорилось в предыдущем разделе).
После отработки ПП динамической индикации, рабочая точка программы переходит в ПП формирования 4-байтного, двоичного числа.
Обращаю Ваше внимание на то, что этот переход происходит без использования команды перехода, так как работа происходит на "линейном" участке программы (просто исполняется следующая команда).
"Конструкций" подпрограмм формирования 4-байтного, двоичного числа может быть множество. Это зависит от функциональности устройства, которое обслуживает программа. Главное, чтобы в результате работы этой ПП, тем или иным способом, было сформировано 4-байтное, двоичное число.
После того как это произошло, для обеспечения перехода в ПП преобразований чисел ("закольцовки"), осуществляется безусловный переход на метку NEW, входящую в состав ПП
START.
Таким образом, мы "прошлись" по кольцу полного цикла программы.
По ходу исполнения программы, таких колец может быть "намотано" множество.
Это зависит от времени, в течение которого устройство находится во включенном состоянии. Разбираемся с возможными "непонятками".
Вопрос: "Зачем осуществлять безусловный переход на метку NEW? Если этого не делать (команда goto NEW и метка NEW отсутствуют), то из ПП формирования 4-байтного, двоичного числа, в ПП преобразований чисел, рабочая точка программы перейдет самоходом (стык находится на линейном участке программы)".
Ответ: да, таким образом рабочая точка программы войдет в ПП преобразований чисел, но выйти из нее она не сможет, так как стек будет пустой (куда переходить? "Глюк").
А пустой он будет потому, что перед исполнением ПП преобразований чисел, в него не "заложился" адрес возврата (не исполнена команда call).
Для того чтобы обеспечить эту "закладку", а заодно и вернуться "туда, куда положено", необходимо выполнить команду goto NEW (перейти на исполнение команды call Bin2_10). Разбираемся с ПП START.
С точки зрения обеспечения надежности работы устройства, полный цикл программы лучше начинать с исполнения ПП START, а не с команды, которая не входит в ее состав.
Впротивном случае, ПП START будет исполнена всего один раз (после включения питания устройства, на 1-м "витке" полного цикла программы), и в ходе дальнейшей работы программы (от 2-го "витка" и далее), ПП START будет обходиться.
Вэтом случае, при неконтролируемом изменении содержимого задействованных в программе регистров (например, в результате какого-то сбоя), существует вероятность "зависания" программы.
Если предприняты меры по "борьбе с зависаниями" (например, работает сторожевой таймер), то в принципе, это не страшно, но если этих мер не предпринято или существуют сомнения, или речь идет об обеспечении максимальной надежности работы устройства, то перестраховаться не помешает.
При наличии такой перестраховки, последствия некоторых сбоев будут ликвидированы за счет приведения "поврежденного" содержимого регистров к норме.
Насколько я понимаю, в ответах на этот "скользкий вопрос", единого мнения нет. Можно, начиная со 2-го "витка" полного цикла программы, обойти ПП START. Можно не обходить.
247
Можно включить в полный цикл программы (от 2-го "витка" и далее) наиболее "ответственные", подготовительные операции ПП START (это что-то типа компромиссного варианта).
Реализацию именно такого подхода Вы и видите в тексте программы Bin2_10.asm. "Ответственные" (эта оценка субъективна) команды подготовительных операций ПП START располагаются ниже команды call Bin2_10, а команды подготовительных операций, "рангом пониже", располагаются выше ее.
Это означает то, что команды подготовительных операций, располагающиеся выше команды call Bin2_10, будут исполнены на 1-м "витке" полного цикла программы, и в дальнейшем (от 2-го "витка" и далее), они исполняться не будут.
Команды подготовительных операций, располагающиеся ниже команды call Bin2_10, будут исполняться на каждом "витке" полного цикла программы.
В "перестраховочном" случае, нужно заменить команду goto NEW на команду goto START. Если есть такое желание, то ничто не мешает осуществить такую замену.
А теперь давайте разберемся в сути преобразований двоичных чисел в двоично-десятичные. Предположим, что группа ПП формирования 4-байтного, двоичного числа "выдала на гора" 4-байтное, двоичное число.
По определению, такое число должно быть "заложено" в 4 регистра общего назначения. Пусть они будут называться Timer...
Так как регистров 4 штуки, то нужно определиться с порядком их старшинства:
TimerHH, TimerH, TimerM, TimerL.
Ранее об этом говорилось.
Если нужно что-то подсчитать, то речь идет о многоразрядном, двоичном счетчике, которому можно поставить в соответствие, например, двоичный счетчик на 8-ми микросхемах 555ИЕ5 (каждая 555ИЕ5 работает с полубайтом, а не с байтом, и поэтому таких м/схем нужно 8 штук). Эта аналогия относится к форме представления результатов счета.
По этому показателю, аналогия полная.
То есть, в обоих случаях, 32-битное, двоичное число будет отображаться в стандартном весовом коде.
Что же касается принципов счета, то существуют весьма существенные различия, связанные с тем, что в 555ИЕ5, счет реализуется только аппаратными средствами.
Пошли дальше.
Линейка 7-сегментных индикаторов, состоящая из 8-ми знакомест, может отобразить десятичное число не более 99 999 999.
Двоичный эквивалент этого числа в стандартном весовом коде:
00000101 11110101 11100000 11111111
См. конвертор систем исчисления, который у Вас имеется (можете проверить). Вопрос: "Что такое двоично-десятичное число"?.
Ответ: двоично-десятичное число это одно из чисел числового диапазона 0 … 9 ,
представленное в двоичной форме.
Двоично-десятичное число, по определению, не может быть больше 9-ти.
Из этого следует то, что оно отображается только в младшем полубайте байта, а старший полубайт байта всегда будет равен нулю (0000хххх).
Например, десятичное число 99 999 999, в двоичном виде, может быть отражено в 4-байтном регистре, но в двоично-десятичном виде, такое число не может быть отражено в четырех регистрах.
В последнем случае, для отображения этого числа потребуется 8 регистров. Число 99 999 999, в двоично-десятичном виде, выглядит так:
00001001 00001001 00001001 00001001 00001001 00001001 00001001 00001001
Вы видите, что во всех младших полубайтах всех 8-ми регистров, "лежат" девятки, а во всех старших полубайтах, нули.
Вот зачем и нужны 8 регистров LED0...7, "прописку" которых Вы видите в "шапке" программы. Первые четыре из них (LED0...3), в ПП преобразований чисел, задействуются для хранения промежуточных и конечных результатов преобразований.
Регистры LED4...7 для этого не задействуются.
На конечной стадии работы ПП преобразований чисел, из младших и старших полубайтов
248
регистров LED0...3, в младшие полубайты регистров LED0...7 (это не ошибка, никакой ошибки нет), переписываются конечные результаты преобразований чисел.
Это и есть то, что в дальнейшем, подлежит кодировке.
При этом, в старших полубайтах LED0...7 "выставляются" нули. Это как раз то, что Вы видите в примере (для случая 99999999).
Вконечном итоге, в младших полубайтах регистров LED0...7, на все время полного цикла ПП динамической индикации, фиксируются двоично-десятичные числа, с которыми эта ПП и будет работать.
Вобщем виде, работу ПП преобразований чисел можно описать так:
После "влёта" рабочей точки программы в ПП преобразований, в предварительно назначенный счетчик "проходов" Count, записывается константа, значение которой равно суммарному количеству битов 4-байтного регистра TimerHH/TimerH/TimerM/TimerL (в нем находится 4-байтное, двоичное число, которое нужно преобразовать в двоично-десятичное). То есть, в данном случае, числовое значение этой константы, должно быть равно .32.
На каждом из 32-х "витков" внутреннего цикла ПП преобразований чисел, содержимое счетчика "проходов" Count декрементируется, и если результат декремента не равен 0, то происходит переход рабочей точки программы на следующий "виток" внутреннего цикла ПП преобразований чисел.
Таким образом, войдя в ПП преобразований чисел, рабочая точка программы "наматывает" 32 "витка" внутреннего цикла ПП преобразований чисел, которые, в сумме, составляют полный цикл ПП преобразований чисел.
После этого, она выходит из ПП преобразований чисел по сценарию "программа исполняется далее".
При этом, содержимое счетчика "проходов" Count равно нулю.
Что происходит, в процессе "прохождения" рабочей точкой программы, каждого из 32-х "витков" внутреннего цикла ПП преобразований чисел?
Сначала производится групповой, циклический сдвиг содержимого 8-байтного регистра
TimerL/TimerM/TimerH/TimerHH/LED0/LED1/LED2/LED3 влево (через бит С регистра STATUS).
Перед этим, (в начале исполнения полного цикла ПП преобразований чисел), в регистры LED0...7 записываются нули.
То есть, их "старое" содержимое удаляется, после чего они готовы к работе.
В результате каждого такого группового сдвига (последовательный сдвиг содержимого 8-ми регистров. 8 команд RLF), происходит перенос содержимого старшего бита регистра TimerHH в младший бит регистра LED0.
Таким образом, через 32 таких сдвига, содержимое TimerL/TimerM/TimerH/TimerHH
переместится в LED0/LED1/LED2/LED3.
Если это трудно себе представить, то вспомните про "бегущую строку" или "бегущие огни". Если просто переместить содержимое TimerL/TimerM/TimerH/TimerHH в LED0/LED1/LED2/LED3, то это ничего полезного не даст, так как конечным результатом такого перемещения будет исходное, двоичное число.
Следовательно, после очередного группового сдвига, необходимо преобразовать содержимое 4-байтного регистра LED0/LED1/LED2/LED3 таким образом, чтобы на момент завершения всех 32-х групповых сдвигов (счетчик проходов Count очищен), во всех 8-ми полубайтах 4-байтного регистра LED0/LED1/LED2/LED3, с соблюдением порядка старшинства, "осели" двоично-десятичные числа (любое из них можно отобразить в полубайте), точно отражающие значение исходного, двоичного числа.
То есть, речь идет о процедуре типа "чтение – модификация – запись.
Так как запись результатов числовых преобразований производится в те же регистры, из которых производилось чтение (LED0...3), то при модификации, должен задействоваться регистр оперативной памяти (в нашем случае - Mem), в котором будут храниться как промежуточные, так и конечные результаты преобразований чисел.
По окончании текущего цикла модификации, модифицированное число, "осевшее" в регистре Mem, копируется в текущий LED.
Предположим, что это происходит.
После того как будет "отмотано" 32 "витка" внутреннего цикла ПП преобразований чисел, во всех 8-ми полубайтах 4-байтного регистра LED0/LED1/LED2/LED3 будут "лежать" 8 двоично-десятичных чисел.
249