Файл: Самоучитель по программированию PIC контроллеров для начинающих (Е.А. Корабельников,2008).pdf

ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 16.06.2025

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

Скачиваний: 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

; --------------------------------

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, то есть на следующее кольцо

;

числовых преобразований.

;================================================================================

259


;Основные операции преобразования двоичных чисел в двоично-десятичные:

;операции сложения 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

addwf

PC,F

; Содержимое

счетчика команд PC увеличивается

; на величину содержимого аккумулятора W.

retlw

b'00111111' ; ..FEDCBA =

0

Происходит скачек по таблице

retlw

b'00000110' ; .....CB. =

1

на строку со значением,

retlw

b'01011011' ; .G.ED.BA =

2

записанным в аккумуляторе,

retlw

b'01001111' ; .G..DCBA =

3

и далее - возврат по стеку.

retlw

b'01100110' ; .GF..CB. =

4

retlw

b'01101101' ; .GF.DC.A =

5

retlw

b'01111101' ; .GFEDC.A =

6

retlw

b'00000111' ; .....CBA =

7

retlw

b'01111111' ; .GFEDCBA =

8

retlw

b'01101111' ; .GF.DCBA =

9

;******************************************************************************** end ; Конец программы.

Все что Вы видите, было "разобрано" ранее.

Сразу бросается в глаза "разросшаяся шапка" программы, что вполне естественно. Регистр Count так же, как и регистр Temp, задействуется многократно (в данном случае, 2 раза).

Если Вы проассемблируете текст программы Din_Bin.asm, то получите сообщение о 7-ми ошибках, что вполне закономерно, так как в тексте этой программы, значения трех констант выражены в символьном виде (X, Y1, Y2).

Это 3 "ненормальности", которые MPLAB "воспринимает" как ошибки.

Остальные 4 ошибки связаны с "непонятностью" того, к чему обращается директива CONFIG (....) и "непонятностью" первой команды ПП START (....).

Если символьные константы X, Y1, Y2 будут заменены на числа, директива CONFIG будет обращаться к "нормальному" числу (например 03FF1H) и будет определена 1-я команда ПП START, то никаких сообщений об ошибках не будет.

Если Вы хотите перейти к другому количеству знакомест линейки, то руководствуйтесь изложенной ранее информацией, в которой "расписан" принцип такого перехода. Числовые значения констант X, Y1, Y2 определяет программист, исходя из стоящих перед ним задач.

На что влияют эти числовые значения, указано ранее.

Если изложенные выше методики "трансформации" этой универсальной "заготовки" освоены и понятны, то после достижения желаемого, ее нужно "доукомплектовать" подпрограммой формирования N-байтного (N определяет программист), двоичного числа.

"Конструкция" этой ПП может быть различной.

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

Выбор богатейший.

260


Таким образом, в том, что я назвал Группой подпрограмм формирования 4(N) - байтного двоичного числа, "сконцентрирован" очень объемный класс задач, на решение которых, в большинстве случаев, и направлены основные усилия программиста.

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

Освоение этих приемов - вполне посильная работа.

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

Если Вы, с первого захода, поняли хотя бы 50% из того, о чем шла речь, то это уже несомненный успех.

Программирование – "дело наживное" и совсем не "шапкозакидательское".

Если не получается, то повторите "заходы", и при наличии "упёртости", рано или поздно, "все встанет на свои места".

Противник грозный и очень достойный.

Он, по определению, будет сопротивляться. И это нужно как следует понимать. Несколько "голов", у этого "многоголового дракона, мы посшибали".

Давайте "посшибаем" еще.

"Самоучитель по программированию PIC контроллеров для начинающих" http://ikarab.narod.ru E-mail: karabea@lipetsk.ru

261

17.Принцип счета. Работа с таймером TMR0. Принцип установки групп команд счета

втекст программы.

Как это не странно, но изложенная ниже информация, почему-то, образно выражаясь, является "страшно секретной".

В том смысле, что в свое время, мне так и не удалось найти более-менее "внятной" информации по высокоскоростному счету.

Это вынудило хорошенько "поднапрячься". А куда деваться?

Заниматься программированием и игнорировать "базу", это нонсенс.

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

Низкоскоростной счет

Первичная информация о таймере TMR0 и принципе счета, основанном на его применении, была изложена ранее.

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

Оно умножается на 256, и к этому произведению приплюсовывается число, находящееся в TMR0 на момент окончания счета.

Примечание: речь о низкоскоростном счете идет в том случае, когда для подсчета импульсов применяется только TMR0 (без предделителя).

Сигнал от внешнего источника сигнала, на вход TMR0, подается через синхронизатор. Функцией синхронизатора является синхронизация сигнала, поступающего от внешнего источника сигнала, с внутренней, тактовой частотой м/контроллера.

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

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

Таким образом, при использовании кварца номиналом 4 Мгц., TMR0 не может работать с частотами выше 1 Мгц.

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

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

Каков выход?

Выход в использовании предделителя.

Например, если использовать предделитель с максимальным коэффициентом деления (256), то переполнение TMR0 наступит через 256х256=65536 импульсов.

Если измерять частоту 30 Мгц., то 65536 импульсов "проскочат" примерно за 2,2 мс., что уже есть "зер гут" (прикиньте, сколько команд можно исполнить за 2200 мкс.).

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

И количество проверок на переполнение TMR0 резко сокращается.

Мало того, при таком "раскладе", можно даже поднять частотную, "программную границу" (максимальную скорость счета, на которую рассчитана программа) выше частотной, "аппаратной границы" ПИКа (максимальной скорости счета, на которую рассчитан ПИК).

Высокоскоростной счет

Для того чтобы было понятно, с чем мы имеем дело, есть смысл кое-что напомнить и добавить.

Таймер TMR0 представляет собой делитель на 256.

262


Это означает, что "чистый" TMR0 (без использования предделителя) будет переполняться каждый раз после поступления на его счетный вход (вывод RA4/TOCKI) "пачки" из 256 импульсов (при переходе от .255 к .00).

TMR0 считает только в одну сторону (реверса нет), а именно, в сторону увеличения. Если в качестве "предмета счета", выбран внешний тактовый сигнал, присутствующий на выводе RA4/TOCKI, то подсчитывается количество импульсов, формируемых внешним источником импульсов.

Примечание: "внешний тактовый сигнал" буду называть "внешним тактом". Так короче.

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

TMR0 всегда включен. Выключить его нельзя.

По этой причине, для того чтобы, при наличии импульсной последовательности на выводе RA4/TOCKI (выбран внешний такт), остановить или разрешить счет, нужно заблокировать или разблокировать счетный вход ПИКа (вывод RA4/TOCKI).

То есть, примитивно выражаясь, его нужно либо "закоротить" на корпус, либо снять этот "коротыш" (с этим, детально разберемся позднее, "а пока и так сойдет").

Для этого, выводы RA3 (блокировка/разблокировка) и RA4/TOCKI (счетный вход ПИКа) электрически соединяются между собой, и блокировка осуществляется программно.

То есть, если на выводе RA3 (можно использовать и другой вывод порта) устанавливается 0 (блокировка), то это соответствует остановке счета, а если 1 (разблокировка), то это соответствует разрешению счета.

Критерием переполнения TMR0 является флаг прерывания по переполнению TMR0 (бит №2 регистра INTCON с названием T0IF).

Поднятие этого флага (1) свидетельствует о факте переполнения TMR0, а его "опущение" (0. Извиняюсь за неблагозвучие) свидетельствует о том, что переполнения TMR0 нет.

Вопределении флага T0IF, упоминаются прерывания, но этот флаг работает независимо от того, разрешены или запрещены прерывания по переполнению TMR0.

То есть, если прерывания по переполнению TMR0 запрещены, то флаг T0IF тоже будет "полноценно" работать.

Флаг T0IF относится к флагам 2-й группы.

То есть, после того как он поднялся (1), и факт этого события подсчитан ("задокументирован"), в конце процедуры проверки TMR0 на переполнение, флаг T0IF нужно опустить (0), а иначе, результат следующей(их) проверки(ок) TMR0 на переполнение, будет необъективен.

Напоминаю о том, что все флаги 2-й группы опускаются только программно. Разбираемся дальше.

Для того чтобы разговор был предметным, речь пойдет о частотомере. "Привяжусь" к 3-байтному результату подсчета импульсов.

Результаты этого подсчета будут записываться в 3-байтный регистр TimerH/TimerM/TimerL. Иными словами, после завершения подсчета, в этом регистре, с соблюдением порядка старшинства, "осядет" 3-байтное, двоичное число результата измерения частоты.

Интервал времени измерения: 0,1 сек. (100000 мкс.).

Максимальная, измеряемая частота: 30 Мгц. (паспортная, максимальная частота, которую "способен воспринять" счетный вход PIC16F84A).

Разрядность линейки 7-сегментных индикаторов: 7 десятичных разрядов (знакомест). Погрешность измерения: 10 гц.

Рассмотрим случай подсчета импульсов импульсной последовательности с частотой 30 Мгц. Обращаю Ваше внимание на то, что в этом случае, речь идет не о подсчете 30 000 000 импульсов, а о подсчете 3 000 000 импульсов, так как интервал времени измерения составляет не 1 сек., а 0,1 сек. (отсюда и погрешность в 10 гц.).

С учетом сказанного выше, для такой высокой частоты, вариант счета с использованием "чистого" TMR0 не подходит.

Значит, необходимо замедлить счет TMR0.

То есть, нужно сделать так, чтобы счетный вход TMR0 "реагировал" не на каждый импульс, поступающий на вывод RA4/TOCKI, а например, на каждый 10-й, 20-й, 34-й, ... и т.д. (цифры "взяты с потолка").

Соответственно, в 10, 20, 34, ... раз увеличится и время одного цикла переполнения, что и требуется (проверки на переполнение не будут очень частыми).

Для этого, между выводом RA4/TOCKI (счетным входом ПИКа) и счетным входом TMR0,

263