Авторизация


...

Кто на сайте?

Сейчас 244 гостей и один зарегистрированный пользователь на сайте

  • heydeeste

Статистика

-Посетители : 22989
-Материалы : 209

Пользователь сайта продает...

  Универсальный цифровой спидометр

Пользователь сайта покупает...

Программные таймеры на ассемблере

Автор: Альберт Бикбулатов Просмотров: 5549

 

 

Каждый раз, отсчитывая хотя бы миллисекунду, программа как бы виснет на это время.А если надо отсчитать месяц? – устройство зависнет на месяц? Что же делать?

Лучше всего доверить отсчёт минимального интервала времени таймеру с компаратором. То есть таймеру с предустановкой числа для отсчёта.

Создаём проект в MPLAB IDE с таймером TMR2

Выберем контроллер 16F628A. Скачаем на него «даташит» (Data Sheet). В нём имеется таймер с компаратором TMR2. Создадим в MPLAB-е проект. Шаблон найдёте у себя на системном диске, например:

 

C:\Program Files\Microchip\MPASM Suite\Template\Code\16F628ATEMP.ASM

 

Лишние комментарии в шаблоне можно убрать и добавить свои.

Для создания проекта лучше воспользоваться Мастером проектов в меню MPLAB / Project / Project Wizard…

Попробуем скомпилировать то, что получилось.

Так, MPLAB ругается на свой же шаблон!!!??? Проверим в файле P16F628A.INC как должно быть.

Найти его можно там же, в каталоге Microchip:

 

C:\Program Files\Microchip\MPASM Suite\ P16F628A.INC

 

Можно скопировать этот файл, на всякий случай, в свой проект, пригодится.

Посмотрим как там записано и поправим в шаблоне:

__CONFIG   _CP_OFF & _DATA_CP_OFF

На

__CONFIG   _CP_OFF & DATA_CP_OFF

Разница небольшая, но существенная. Теперь всё нормально, компилируется.

В программировании мелочей не бывает. Так что не верьте всему, что пишут, проверяйте :-)

Включимвменюсимулятор Debugger / Select Tool / MPLAB SIM

В Debugger / Settings… выберемчастотукварца 4 MHz

Там в же в Debugger берём секундомер Stopwatch

В начале программы main настроим контроллер.

Перед таймером установим предделитель :4 и число .249 в регистр предустановки .

Теперь у нас : 4 Mhz / 4 = 1 машинный цикл = 1 микросекунда.

Умножаем на предделитель 4 и на предустановленное число 250 (от 0 до 249), получаем = 1 миллисекунда.

В начале подпрограммы прерывания, начинающегося с       ORG     0x004   , добавим проверку на прерывание от TMR2, чтобы не путать с другими прерываниями. У нас пока других прерываний нет, но, возможно, потом появятся. Так что лучше сделать сразу:

 

       btfss       PIR1,TMR2IF                 ; Проверка прерывания от TMR2.

       goto       other_interrupts             ; иначе переходим на проверку других прерываний.

       bcf         PIR1,TMR2IF                  ; Сброс прерывания по таймеру TMR2.

                                                       ; И сразу ставим метку, двойным щелчком на строке со сбросом прерывания от TMR2:

       bcf         PIR1,TMR2IF                  ; Сброс прерывания по таймеру.

 

Компилируем программу и запускаем симулятор. Программа остановилась на нашей метке.

Сбрасываем секундомер и снова запускаем симулятор.

На этот раз на секундомере показывает 1000 МЦ (машинных циклов), а ниже 1 миллисекунда.

То что нам надо. Прерывания происходят точно через равные промежутки времени в 1 миллисекунду.

Далее я расскажу, как это можно использовать.

Что мы имеем.

   Произошло событие, контроллер отсчитал 1 мсек. Так и озаглавим эти строчки:

Event_Time_1ms

 

     btfss       PIR1,TMR2IF                 ; Проверка прерывания от TMR2.

      goto       other_interrupts            ; иначе переходим на проверку других прерываний.

      bcf         PIR1,TMR2IF                 ; Сброс прерывания по таймеру.

 

   Всё что ниже, будет происходить с периодичностью в 1 мсек.

 

Здесь можно поднимать флаги, с этой периодичностью, для подпрограмм, которым нужны такие флаги.

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

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

каждые 17 миллисекунд.

В прерывании удобнее будет размещать счётчики кратные каким то стандартным или удобным интервалам

времени. Например: 10 мсек, 0,1 сек, 1 сек, 1 мин, 1 час и т.д.

Впрочем, при желании счётчик на те же 17 миллисекунд можно добавить тут же, в прерывании.

Добавляем счётчики таймеров

   Для каждого интервала времени потребуется регистр для счёта:

 

   reg_Time_10ms                     ; Регистры счётчиков времени.

   reg_Time_01sec

   reg_Time_1sec

   reg_Time_1min

   reg_Time_1hour

   reg_Time_1day

   В эти регистры будем загружать константы. Назовём их соответствующим образом.

   #Define     TIME_10ms    .10   ; Константы для регистров счётчиков времени.

   #Define     TIME_01sec   .10   ;

   #Define     TIME_1sec      .10 ;

   #Define     TIME_1min     .60   ;

   #Define     TIME_1hour    .60   ;

   #Define     TIME_1day     .24   ;

 

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

Ограничимся днями, т.к. они все одинаковые, по 24 часа. Недели тоже одинаковые, но неделями редко считают,

разве что беременность :-).

С месяцами сложнее, там количество дней разное, счёт усложнится и для примера не подходит. Так что далее,

проще использовать микросхемы реального времени типа PCF8583 и т.п.

     Счетчики могут быть с другими интервалами, не 10 ms, а 100 ms например. Это как вам удобно.

Смотрите прилагаемый файл Time_intervals1.asm

Счётчики запишем в таком виде:

 

   Event_Time_10ms

   decfsz     reg_Time_10ms,F               ; Вычитаем 1, если не ноль, пропускаем следующую инструкцию.

   Goto       other_interrupts                 ; иначе переходим на проверку других прерываний.

   Movlw       TIME_10ms                     ; Константу загружаем

   movwf       reg_Time_10ms               ; обратно в регистр.

 

   Все остальные счётчики - такие же.

Теперь, если выставить точку останова в конце любого счётчика (ставьте точки останова только по одной),

программа будет останавливаться там

с соответствующей периодичностью.

Как использовать программные счётчики?

   Создадим в Proteus-е модель со светодиодами и помигаем ими. Смотрите файл Time_intervals1.DSN

Можно конечно переключать пины порта прямо в прерывании, но сделаем по-другому.

Выделим ещё один регистр для индикатора и назовём его indicator.

Индикатор будет переключаться только по необходимости.

Пишем подпрограмму LED_Indicator.

     В начале подпрограммы проверяется флаг события EV_indicator и подпрограмма продолжит выполнение,

только если это событие было, и флаг был поднят.

Организуем переключение светодиода один раз в секунду. Для этого выставим флаг LED_1sec после

прерывания в 1 сек.

Это событие надо обработать. Напишем ещё одну программу Switch_ LED_1sec

Как и предыдущая подпрограмма, она будет проверять флаг своего события EV_ LED_1sec.

Переключим светодиод на индикаторе маской LED_1sec.

 

     movlw       LED_1sec                    ; Переключим светодиод LED_1sec

      xorwf       indicator,F                   ; на индикаторе.

 

В конце подпрограммы поднимем флаг события для индикатора EV_indicator.

   Что если светодиод надо переключать не каждую секунду, а с частотой в 1 сек, т.е. переключать каждые 0,5 сек? Выделяем регистр и делаем врезку для отдельного счётчика. Тактовую частоту можно выбрать 0,1 сек, умножив на 5, или 0,01 сек, умножив на 50, её и возьмём. Константа у нас получается 50. Счётчик располагаем в месте поднятия флага 10 мсек. В конце счётчика как всегда поднимаем флаг. Да, и не забудьте про предустановку в начале программы.

 

Event_Time_05sec

     decfsz     reg_Time_05sec,F             ; Вычитаем 1, если не ноль, пропускаем следующую инструкцию

     goto         Event_Time_01sec           ; иначе переходим к следующему счётчику.

     movlw       TIME_05sec

     movwf       reg_Time_05sec

     bsf           event,EV_LED_05sec        ; Поднимаем этот флаг события раз в 0,5 сек.

 

     Ну и подключим ещё один светодиод и добавим подпрограмму переключающую его.

Почему для каждого светодиода отдельная подпрограмма? Это для примера. События у нас разные, а к этому выводу может быть подключен не светодиод, а насос или вентилятор, сигнализация или нагреватель. И всё будет в программе подключаться отдельно, и работать независимо, не мешая друг другу. Ничто вам не мешает подключить блок светодиодов и выделить для этого блока только одну подпрограмму. Блок этот может содержать сотни светодиодов, а управляться будет по 2-3 проводам одной подпрограммой, которая будет вызываться всё тем же одним флагом. Я ещё не рассказал, как сделать задержки? Точно так же. Можно выделить один или несколько регистров, в зависимости от того, какие интервалы времени вам надо отсчитывать, и с какой точностью. Если на входе счётчика такты в 1 мсек, то и точность будет соответственная. Если точность нужна больше, то считайте машинные циклы. Как делать врезки, мы уже знаем. А запускается счётчик элементарно. Загружаете константы в счётчик и сбрасываете флаг. В конце счёта флаг подымется.

   Подведём итог Кажется, что получилось слишком много кода. На самом деле это не так. Некоторые строки написаны про запас, для отсчёта долей секунд, для минут, часов и дней. Пока они не используются, и вы можете их удалить, или использовать в своей программе. То же, что используется, выполняется точно в определённое время и очень быстро. Например, переключатель светодиода срабатывает только раз в секунду. Подпрограмма индикатора тоже срабатывает по мере необходимости. Для примера я сделал ещё одну программку (см. в папке Flasher101). Там 8 таймеров переключают 8 светодиодов. Первый светодиод мигает раз в секунду, а каждый следующий - на 1% дольше. То есть через 1% х 100 включений, они опять мигают вместе. Получаются интересные визуальные эффекты. И ещё один таймер выключает всю эту мигалку через 5 минут. Получилось просто, точно и эффективно.

 С обычными задержками программы это было бы сложно сделать, запутаешься. А добавить в такую программу что то ещё, вообще было бы невозможно, не меняя предыдущий алгоритм. Кроме того, подпрограмму индикатора можно вызывать не из других подпрограмм, а по времени. Например, каждые 10 мсек или чаще. Это бывает необходимо при динамической индикации. А можно наоборот, вызывать раз в секунду, чтобы показания не мельтешили, и их было удобно считывать. Это бывает необходимо при быстро меняющихся параметрах выводимых на индикацию. Так же можно объединить динамическую индикацию и смену текущих показаний раз в секунду. То есть - имеем временные промежутки в любых сочетаниях. И не только для индикации, а и для сканирования клавиатуры, энкодера, работы с датчиками и т.п. И при всём при этом, у контроллера останется куча машинного времени на другие нужды и вычисления. А подпрограммы, тщательно отлаженные под работу с флагами, будут легко переноситься в другие проекты.

Всем удачи! Исходные файлы, проекты в Протеусе и другие материалы к данной статье можно взять

Ссылка для скачивания доступна только авторизованным пользователям сайта !

Случайные статьи....

Prev Next

Генератор телевизионных сигналов PAL

12-05-2011 Николай Викторов

Генератор телевизионных сигналов PAL

Данный генератор можно применить  для регулировки и ремонта аналоговых мониторов и телевизионных приемников (телевизор).Генератор  собран  на "базе"  видеоадаптера на PIC18F46K20 и  кодера PAL. По сути  это измененная   прошивка , позволяющая  кроме основного предназначения (видеоадаптер) , применить данное устройство в качестве...

Часы,таймер,регулятор температуры.

16-01-2012 Super User

Часы,таймер,регулятор температуры.

   КОНКУРС Данное устройство разработано на базе PIC16F628A .Регулятор температуры поддерживает температуру зоны, где находится датчик, с точностью в 1°С. Диапазон работы регулятора 1 - 100°С, мини -мальный гистерезис срабатывания 1°С. При аварийном уходе температуры за пределы диапазона или неисправности датчика DS18B20,...

Подключение ENC28J60 + PIC к локальной сети .

27-10-2011 Николай Викторов

Подключение ENC28J60 + PIC к локальной сети .

1 часть.   Эта статья будет интересна в первую очередь тем, кто пишет программы  для микроконтроллеров на ассемблере и есть желание  собрать устройство , работающие в локальной сети или сети ethernet. Здесь будет применена связка  ethernet контроллер  enc28j60 и PIC18F46K20. Но можно...

Промышленный терморегулятор. Часть 3.

30-09-2011 Sergey Roslik

Промышленный терморегулятор. Часть 3.

 1 Часть - основные технические характеристики, схема, печатная плата, прошивка.  2 Часть - подключение устройства к ОРС серверу, конфигурирование ОРС сервера.  3 Часть - выборка данных с ОРС сервера и отображение их на мнемосхеме.  У меня на предприятии используется программный комплекс «НЕВА» (http://energosoyuz.spb.ru),...


Все права принадлежат ChipMK.ru. При копировании материала ссылка обязательна. 2011-2017 © ChipMK.ru

ChipMk.ru Яндекс.Метрика
PRCY.ru