Главная » Статьи » Proton PICBasic

Подсчет импульсов по двум каналам с использованием двух таймеров. Практический пример

Заказали мне однажды такой прибор – типография наша местная. Нужен им стал такой прибор, чтоб считал импульсы с двух источников – с датчиков, которые установлены на барабанах. Одни импульсы идут с барабана, на котором намотана газетная чистая бумага, а другие – с выходного барабана, который выкидывает газеты. Стал я думать, что да как. Сначала взял первый попавшийся под руку, ставший уже классическим раритетом, PIC16F84. Замутил так, что один канал считал таймер TMR0, а второй – в теле основной программы. Потом передумал, поскольку ничего не получилось, так как все это нужно было отправлять на компьютер для дальнейшей обработки и была вероятность пропустить несколько импульсов ввиду затрат времени на передачу. Поэтому взял я другой контроллер, получше – PIC16F628. Он имеет два таймера и поэтому считать может независимо по двум каналам. Частота следования импульсов была небольшой: по одному каналу в районе 10-15 Гц, по другому – около 50. Эту скорость можно обработать не напрягаясь (позже я выяснил, что считать можно и со скоростью 100 кГц, а может и выше).


Схема получилась простая. Для входных буферов использовались оптотранзисторы, поскольку с датчиков сигнал шел 24 вольта. Для передачи данных я не стал сооружать буферный преобразователь TTL-RS232. Поскольку управлять контроллером не было надобности и требовался только один провод для передачи на com-порт, я поставил последовательно с линией TX микроконтроллера резистор 22 кОм. Прибору требовалось управление с кнопок, поскольку, когда начинается печать газет, то сначала идет брак, так как нужно то краски добавить, то шаблон сместить. Поэтому данный девайс на подсчет экземпляров газет нужно запускать после того, как пойдут нормально отпечатанные газеты. С подсчетом метров тоже там что-то было не в порядке, поэтому его нужно было запускать не сразу (Хотя, я сейчас думаю, можно было сразу запускать. Ну ладно, такое было тех задание). Программа терминал для компьютера была написана на Delphi 7. Она принимает две строки, распознает их и обрабатывает. Эта программа автоматом подсчитывала, сколько пачек, по сколько газет в пачке, какого формата, сколько осталось до окончания печати по плану, сколько израсходовано бумаги в метрах погонных и квадратных и сколько и куда пойдет этих газет по направлениям (То есть по торговым точкам). 

Прибор отправляет две строки вида:

ME000000 – количество подсчитанных метров.

EX000000 – количество подсчитанных экземпляров.

Все это я пишу потому, что кому-то, возможно понадобится такая штука. Исходники прилагаются. Но самая главная мысль, которую я преследовал, заключается в том, КАК же все-таки считать импульсы по двум каналам одновременно. Сразу же здесь будет показано, как обрабатывать три прерывания (Кнопки запуска подсчета я повесил на вход INT микроконтроллера, чтобы немедленно прекратить или запустить счет). По прерыванию от двух и более кнопок вы можете посмотреть еще одну мою статью. Здесь использован тот же самый принцип.

Схема прибора выглядит так:

 

Программа для микроконтроллера очень простая:

'-------------------------- Описание проекта ---------------------------------

'Проект :  Прибор для подсчета количества экземпляров газет и израсходованной бумаги
'          и последующей передачи на ПК для обработки. Терминал прилагается                      
'Автор : Анисимов Максим Александрович                             
'                                                             
'Версия : 1.0.0 от 21.10.2009 
'----------------------------------------------------------------------------- 
 

Declare  SHOW_SYSTEM_VARIABLES = OFF   ' При симуляции в Proteus не показывать внутренние переменные
Declare  FSR_CONTEXT_SAVE = OFF   ' Не заботиться о сохранении содержимого регистра FSR
Declare  Reminders = OFF    ' Выключить напоминания компилятора
Declare  Warnings = OFF   ' Выключить предупреждения компилятора
Declare  Optimiser_Level 0    ' Выключить оптимизацию программы
Serial_Baud = 9600     
Rsout_Pin = PORTB.2
Rsout_Mode = inverted
Rsout_Pace = 1
Rsin_Mode = TRUE                                                                  

'-------------------------- Общие настройки------------------------------------

Device = 16F628   ' Используемый микроконтроллер
Xtal =10   ' Частота осциллятора  10 МГц

'-------------------------- Конфигурация программирования --------------------


Config  BODEN_OFF, CP_OFF, PWRTE_ON, WDT_OFF, LVP_OFF, MCLRE_ON, XT_OSC


'-------------------------- Настройки портов ---------------------------------

PortB_Pullups = OFF   ' Выключить подтягивающие резисторы на PORTB
Declare  All_Digital = On   ' Установить все порты цифровыми входами/выходами

'-------------------------- Регистры специального назначения-------------------

'-------------------------- INTCON --------------------------------------------


Symbol RBIF = INTCON.0 ' Флаг внешнего прерывания по PORTB.4-PORTB.7
Symbol INTF = INTCON.1 ' Флаг внешнего прерывания по PORTB.0(INT)
Symbol T0IF = INTCON.2 ' Флаг переполнения TMR0
Symbol RBIE = INTCON.3 ' Бит разрешения прерывания по PORTB.4-PORTB.7
Symbol INTE = INTCON.4 ' Бит разрешения прерывания по PORTB.0(INT)
Symbol T0IE = INTCON.5 ' Бит разрешения прерывания по переполнению TMR0
Symbol PEIE = INTCON.6 ' Бит разрешения прерывания от периферийных устройств
Symbol GIE = INTCON.7  ' Бит глобального разрешения прерываний
'-------------------------- PIE1, PIR1 ----------------------------------------------

Symbol TMR1IE = PIE1.0 ' Бит разрешения прерывания по переполнению TMR1
Symbol TMR1IF = PIR1.0 ' Флаг прерывания по переполнению TMR1

'-------------------------- T1CON ---------------------------------------------------


Symbol TMR1ON = T1CON.0     ' Бит включения модуля TMR1
Symbol TMR1CS = T1CON.1     ' Выбор источника тактового сигнала для TMR1
Symbol NOT_T1SYNC = T1CON.2 ' Синхронизация внешнего тактового сигнала
Symbol T1INSYNC = T1CON.2   ' Синхронизация внешнего тактового сигнала
Symbol T1SYNC = T1CON.2     ' Синхронизация внешнего тактового сигнала
Symbol T1OSCEN = T1CON.3    ' Включение тактового генератора TMR1
Symbol T1CKPS0 = T1CON.4    ' Выбор коэффициента деления предделителя TMR1
Symbol T1CKPS1 = T1CON.5    ' Выбор коэффициента деления предделителя TMR1

'-------------------------- Начало -------------------------------------------


Dim   COUNT_EX  As  Word ' Промежуточный счетчик экземпляров
Dim   COUNT_METR  As  Dword ' Промежуточный счетчик метров
Dim countE As Dword  ' Счетчик экземпляров
Dim countM As Dword  ' Счетчик метров
Dim   start_EX As Bit  'Флаг запуска подсчета экземпляров
Dim   start_METR As Bit 'Флаг запуска подсчета метро                                                                
Dim   start_flag As Bit  ' Флаг того, что счет вообще есть или нет по какому либо каналу

'-------------------------- Определение символов -----------------------------


Symbol TIMER1 = TMR1L.Word
Symbol   BUT_METR = PORTB.4 ' Кнопка старта счета метров
Symbol   BUT_EX = PORTB.5   ' Кнопка старта счета экземпляров
Symbol ledex = PORTA.3 ' Светодиод подсчета импульсов количества экземпляров газет
Symbol   ledmetr = PORTA.2 'Светодиод подсчета импульсов количества метров бумаги      
'-------------------------- Настройка TMR0 для прерываний --------------------


Clear
OPTION_REG = %11101000  'Разрешим работу таймера 0 от внешних импульсов
TMR0 = $00' Очистим TMR0

'-------------------------- Настройка TMR1 для прерываний --------------------


TRISB = %01110001  ' Настроим порты
TRISA = %11110000 
TMR1L = $00   ' Значение младшего регистра TMR1
TMR1H = $00    ' Значение старшего регистра TMR1
T1CON = %00000110 ' Настроим TMR1 на работу от внешнего источника импульсов
PORTA = %00001100
PORTB = 0
TMR1IE = 1    ' Разрешение прерывания при переполнении TMR1
T0IE = 1      ' Разрешение прерывания при переполнении TMR0
INTE = 1      ' Разрешение прерываний по входу INT
PEIE = 1    ' Разрешение прерываний от периферийных устройств
GIE = 1    ' Разрешение глобального прерывания
TIMER1 = 0
TMR0 = 0
TMR1ON = 1  ' Включим TMR1                                                                

On_Interrupt GoTo  Int_Label
GoTo  MainProgram

'-------------------------- Прерывания--------------------------

Int_Label:    ' Метка прерывания

Context Save                                                  
If INTF = 1 Then   ' Если была нажата какая-то кнопка(прерывание по INT)
                   ' то определяем, какая была нажата

        If BUT_EX = 1 Then  'Если кнопка подсчета импульсов кол-ва экземпляров
                If start_EX = 1 Then ' то если подсчет уже включен, то
                      start_EX = 0     ' выключим флаг подсчета
                      ledex = 1        ' погасим светодиод
                Else                 ' Если же подсчет выключен, то
                      start_EX = 1     ' включим флаг подсчета
                      ledex = 0        ' и зажжем светодиод
               EndIf
        EndIf
        If BUT_METR = 1 Then     ' Если нажата кнопка подсчета метров бумаги
               If start_METR = 0 Then  ' если подсчет выключен, то
                      start_METR = 1      ' установим флаг начала подсчета
             ledmetr = 0         ' и зажжем светодиод
               Else                    ' Если же подсчет уже включен, то
                      start_METR = 0      ' сбросим флаг подсчета
                      ledmetr = 1         ' и погасим светодиод
               EndIf
        EndIf
        INTF = 0                    ' Сбросим флаг прерывания INT(нажатия кнопки)
EndIf

If start_EX = 0 And start_METR = 0 Then  ' Проверяем, если оба флага сброшены, то
      start_flag = 0                       ' сбросим общий флаг счета
Else                                     ' А если хоть по одному каналу идет счет
      start_flag = 1                       ' установим его
EndIf
If T0IF = 1 Then                         'Если был переполнен таймер TMR0
      COUNT_EX = COUNT_EX + 256                ' То к промежуточному счетчику экземпляров
                                         ' прибавляем макс. значение таймера                                 
      T0IF = 0                                 ' Сбрасываем флаг переполнения TMR0
EndIf

If TMR1IF = 1 Then                       ' Если был переполнен таймер TMR1
      COUNT_METR = COUNT_METR.HighWord + 1     ' то прибавляем максимальное значение таймера к
' промежуточному счетчику метров                      
          
      TMR1IF = 0                               ' Сбрасываем флаг переполнения TMR1
EndIf
Context Restore                ' Возврат из обработчика прерывания



'-------------------------- Главная программа -------------------------

'Здесь нужно понять: мы постоянно складываем значение счетчика COUNT_EX,

' полученного в прерываниях, с текущим значением таймера TMR0, то есть постоянно

'обновляем общее значение итогового счетчика. Если импульсы прекратяться

' то счет остановится, если возобновятся - счет возобновится. Передача непрерывна

'пока разрешен счет хоть по одному каналу

MainProgram:

If start_EX = 1 Then    ' Если запущен счет экземпляров, то
      countE = COUNT_EX + TMR0  ' прибавляем значение промежуточного счетчика
                                  ' к текущему значению таймера и помещаем в итоговый счетчик экземпляров

Else
        TMR0 = 0
EndIf

If start_METR = 1 Then  ' Если запущен счет метров, то
      countM = COUNT_METR + TIMER1 ' прибавляем значение промежуточного счетчика
                                     ' к текущему значению таймера и помещаем в итоговый счетчик метров

Else
        TIMER1 = 0
EndIf                                                                  
DelayMS 500                 ' Ждем 0.5 секунд, чтобы на компьютер отправлялось пореже
If start_flag = 1 Then      ' Если счет по какому-либо каналу включен
        RSOut "ME",Dec6 countM ,13  ' то отправляем количество метров
        DelayMS 10                  ' ждем 10 мС
        RSOut "EX",Dec6 countE ,13  ' отправляем количество экземпляров
EndIf                                                                 

GoTo  MainProgram   ' Возврат на начало основной программы

Скачать все исходники можно здесь

Программа написана на протоне, но тем, кто использует PBP, смысл уловить не составит труда 

Обсуждение здесь

Кстати, на схеме выходы оптопар никуда не подключены. На входы таймеров (PORTA.4 и PORTB.6) идут импульсы с генератора на U4. В схеме оптопары показаны для справки (а еще точнее, я просто в протеусе развожу всегда :)).




Категория: Proton PICBasic | Добавил: ADMIN (22.04.2011)
Просмотров: 8937 | Комментарии: 4 | Теги: Программа, таймер, TMR0, TMR1, подсчет, статья, пример | Рейтинг: 5.0/3
Всего комментариев: 4
0
1 ADMIN   (11.10.2014 16:38)
Была ли полезна эта статья кому-нибудь?

2 Makksud   (11.10.2014 23:27)
Конечно, для самообучения.

0
3 ADMIN   (12.10.2014 14:48)
Меня это радует.

4 PINCOD   (18.12.2014 19:52)
Всё время пользовался одним таймером для прерывания,ну вот  понадобилось ещё одно независимое  прерывание в проге,И твоя статья,как вовремя мне попалась.А то голову ломал,как двумя таймерами жонглировать в прерываниях.Спасибо твоя статья пригодилась. surprised

Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]