Заказали мне однажды такой прибор – типография наша местная. Нужен им стал такой прибор, чтоб считал импульсы с двух источников – с датчиков, которые установлены на барабанах. Одни импульсы идут с барабана, на котором намотана газетная чистая бумага, а другие – с выходного барабана, который выкидывает газеты. Стал я думать, что да как. Сначала взял первый попавшийся под руку, ставший уже классическим раритетом, 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. В схеме оптопары показаны для справки (а еще точнее, я просто в протеусе развожу всегда :)).
|