; ТАХОМЕТР на PIC16F873, PIC16F873A (или PIC16F876, PIC16F876A в нем просто больше памяти) ; кварц 4 Мгц ; шкала 7 групп по 6х8 светодиодов, в 7й - 3 6х8+3= 51 диод ; индикация динамическая, группами с общим анодом ; масштаб шкалы ; 9 диодов при 200-1000 об/мин ; 7 диодов на 1000 об/мин для со 2й до 7й тысячи ; 9+6х7=51 диод (вся шкала) при 7000 об/мин ; Подсчитает интервал измерения ; всегда должно выдаваться 2 имп/об (2 искры на оборот для 4х-цилиндрового, 4х-тактного) ; при частоте вращения 6000 об/мин = 100 об/сек или 60 сотен об/мин ; 100 об/сек * 2 имп/об = 200 имп/сек ; ; 60 имп : 200 имп/сек = 0,3 сек = 300мс ; за 300 мс на вход должно придти столько же импульсов, ; сколько происходит сотен оборотов в минуту ; а за 600 мс столько импульсов, сколько пятидесяток ; будем подсчитывать пятидесятки, ; т.к. 7 диодов на 1000 об/мин - это 1 диод на 143 об/мин ; поэтому при подсчете в сотнях из-за дискретности шкалы ; получаются неравномерные показания ; при подсчете в пятидесятках неравномерность минимальна, ; т.к. 143 достаточно близко к 150 (=3х50) list p=16F873 #include __config _CP_OFF & _WDT_OFF & _PWRTE_ON & _XT_OSC & _LVP_OFF ; Константы iniTMR equ d'256'-d'205'; начальный отсчет таймера, загружается такое число, с которого до 256 идет отсчет iniRPT equ d'183' ; 183 повтора по ( 1 640 мкс(=205 тиков по 8мкс) + 2 мкс на разгон ) = 0,300486 сек iniDBL equ d'032' ; задержка в 32 повтора подобрана именно для 4 МГц ; Переменные GRNOM equ 0x20 ; номер группы диодов, которая выводится на индикацию GRFUL equ 0x21 ; число групп с включенными 8-ю диодами (целое от деления CLMP/8) GRLST equ 0x22 ; число диодов в последней, неполной группе 0-7 диодов (остаток деления CLMP/8) CRPT equ 0x23 ; счетчик повторений отсчетов по 1,6 мс (точнее 1638,4 мкс) R100 equ 0x24 ; сотни оборотов в минуту CLMP equ 0x25 ; число диодов для зажигания в шкале CDBL equ 0x26 ; удвоение времени измерения (дискретность отсчета 50 об/мин) cntDBL equ 0x27 ; счетчик времени дребезга контактов ; программа org 0x000 bcf STATUS, RP0 ; Банк 0 bcf STATUS, RP1 clrf PORTA clrf PORTB clrf PORTC bsf STATUS, RP0 ; банк 1 movlw 0x06 ; все ноги А на цирфу movwf ADCON1 ; выключили АЦП movlw b'00000000' movwf TRISA ; RА на вывод movlw b'00000001' movwf TRISB ; RB0 ввод, RB1-RB7 вывод movlw b'00000000' movwf TRISC ; RC - вывод ; будем использовать таймер TMR0 - для динамической индикации ; выключаем подтягивающие резисторы (не нужны на RB0, там будет плюсовой импульс) ; устанавливаем TMR0 на внутренний такт с предделителем 8 movlw b'11000010' ; один тик таймера 8 * 1 мкс = 8 мкс movwf OPTION_REG bcf STATUS,RP0 ; банк 0 clrf INTCON ; прелюдия ; включить всю шкалу movlw 7 movwf GRFUL movwf GRNOM movwf GRLST movlw 4 movwf R100 clrf CRPT TestLoop movlw iniTMR movwf TMR0 bcf INTCON,T0IF TestDelay btfss INTCON,T0IF ; повторяем маленький цикл, goto TestDelay ; пока TMR0 не скажет: хватит! call CH_GROUP decfsz CRPT,f ; вывод всей шкалы goto TestLoop ; в течение 1,2 сек decfsz R100,f goto TestLoop clrf CLMP ; глобальный цикл Main_loop clrf R100 ; обнуляем счетчик сотен оборотов в минуту movlw iniDBL movwf cntDBL ; инициализируем счетчик блокировки дребезга movlw 1 ; здесь нужно будет поставить 2, movwf CDBL ; если тах будет показывать половину нужного ms600 movlw iniRPT movwf CRPT ; цикл подсчета импульсов (183 раза отсчет таймером по 1,6мс) bcf INTCON,INTF ms300 movlw iniTMR ; при 4Мгц и предделителе 8 получается 205 тиков таймера = 1640 мкс + 2 мкс на разгон movwf TMR0 ; TMR0 должен отсчитать 205 тика от 51 до 256 bcf INTCON,T0IF s1m6 btfss INTCON,INTF ; если был фронт импульса датчика, то идем на обработку счетчиков goto NoINCR ; датчик молчит, идем проверять таймер DoINCR ; для сигнала с инжекторных мозгов всего две строчки ; incf R100,f ; +1 в счечик импульсов ; bcf INTCON,INTF ; сбросили флаг внешнего прерывания ; а для прерывателя нужно еще добавить btfss PORTB,0 goto ClrINT ; если RB0=0, то сбрасываем прерывание ; если RB0=1, то decfsz cntDBL,f ; задерживаем дальнейшие действия goto NoINCR ; до обнуления счетчика дребезга ; закончилась задержка на время дребезга incf R100,f ; +1 в счечик импульсов ClrINT bcf INTCON,INTF ; сбросили флаг внешнего прерывания movlw iniDBL movwf cntDBL ; инициализируем счетчик блокировки дребезга NoINCR btfss INTCON,T0IF ; повторяем маленький цикл, goto s1m6 ; пока TMR0 не скажет: хватит! call CH_GROUP ; здесь обслуживание динамической индикации decfsz CRPT,f ; отсчет по 1,6 мс нужно повторить 183 раза, goto ms300 ; чтобы мерный интервал получился 0,3 сек (183 х 1,642 мс = 300,486 мс = 0,3 с) decfsz CDBL,f goto ms600 ; повторяем 2х0,3=0,6 ; отсчитали 600 мс ; теперь переменная R100 содержит число оборотов в минуту ; выраженное в пятидесятках (R100=1 - это 50 об/мин) ; его нужно пересчитать в число диодов, которые нужно зажечь movf R100,w sublw d'20' ; CarryFlag =1, если W<=20 (оборотов <1000) btfsc STATUS,C goto LE1000 GT1000 ; оборотов больше, чем 1000 movlw 9 ; 9 диодов на 1ю тысячу movwf CLMP movlw d'20' ; со 2й тысячи об/мин масштаб шкалы 7 диодов на 1000 об/мин subwf R100,f ; вычитаем 1ю тысчу (10 сотен, или 20 пятидесяток) из R100 Loop1000 movlw d'20' ; вычитаем 20 пятидесяток на каждую полную subwf R100,f ; тысячу об/мин btfss STATUS,C goto LT_10 GE_10 movlw 7 ; прибавляем 7 к числу зажигаемых диодов addwf CLMP,f ; на каждую полную тысячу оборотов в минуту goto Loop1000 LT_10 ; остаток оборотов в последней тысяче, addwf R100,w ; выраженное в пятидесятках call Get50 ; по таблице находим число диодов, addwf CLMP,f ; которое нужно зажечь goto ClcGroups LE1000 ; для 1й тысячи rrf R100,f ; число оборотов/2, чтобы 50-ки пересчитать в 100-ки bcf R100,7 movf R100,w btfss STATUS,Z ; зажигаем диодов на 1 меньше, addlw -1 ; чем подсчитано сотен оборотов в минуту movwf CLMP ; (но при нуле обходим -1, а то вся шкала зажигается) ClcGroups ; теперь мы знаем CLMP - число зажигаемых диодов ; нужно его разбить по группам для динамической индикации movf CLMP,w movwf GRFUL rrf GRFUL,f ; /2 bcf GRFUL,7 rrf GRFUL,f ; /4 bcf GRFUL,7 rrf GRFUL,f ; /8 bcf GRFUL,7 ; в GRFUL число полных октетов диодов movf CLMP,w andlw 7 movwf GRLST ; в GRLST неполный октет goto Main_loop CH_GROUP ; переключение группы индикации clrf PORTB ; отключили анодые ключи movlw 1 ; организуем цикл GRNOM = 1,2,...,7,1,2,... incf GRNOM,f ; GRNOM=GRNOM+1 btfsc GRNOM,3 ; if GRNOM>7 movwf GRNOM ; then GRNOM=1 movf GRNOM,w addlw -1 ; меняем базу цикла 0,...,6 subwf GRFUL,w ; сравниваем GRNOM и GRFUL btfss STATUS,C goto GRNOM_GT_GRFUL GRNOM_LE_GRFUL ; <= btfss STATUS,Z ; выясняем < или = ? goto GRNOM_LT_GRFUL GRNOM_EQ_GRFUL ; = movf GRLST,w ; включаем только часть катодов по GRLST call GetCathod ; число преобразуем в код катодов movwf PORTC goto TURN_ON GRNOM_LT_GRFUL ; < clrf PORTC ; нужно включить все 8 диодов goto TURN_ON ; (все катоды подключить на землю) GRNOM_GT_GRFUL ; > return ; вышли без включения анода TURN_ON movf GRNOM,w ; включение анода call GetAnod ; номер преобразуем в код анода movwf PORTB return GetAnod ; из-за того, что аноды в схеме andlw 0x07 ; соединены с ногами порта RB addwf PCL,f ; не по порядку ; 3217654- retlw b'00000000' ; приходится использовать табличную retlw b'00100000' ; функцию преобразования retlw b'01000000' ; номер анода -> номер бита retlw b'10000000' retlw b'00000010' retlw b'00000100' retlw b'00001000' retlw b'00010000' GetCathod ; из-за того, что катоды в схеме andlw 0x07 ; соединены с ногами порта RА addwf PCL,f ; не по порядку ; 76540123 retlw b'11111111' ; приходится использовать табличную retlw b'11110111' ; функцию преобразования retlw b'11110001' ; номер диодов в группе -> retlw b'11110011' ; -> раскладка битов порта retlw b'11110000' retlw b'11100000' ; 0-зажигает, 1-гасит диод retlw b'11000000' retlw b'10000000' Get50 ; для 2й, 3й и т.д. неполных тысяч andlw 0x1F ; оборотов в минуту addwf PCL,f ; подсчитанное число пятидесяток retlw 0 ;0 ; в этих тысячах retlw 0 ;1 ; преобразуем в число зажигаемых retlw 0 ;2 ; диодов retlw 1 ;3 ; с помощью этой табличной функции retlw 1 ;4 retlw 1 ;5 retlw 2 ;6 retlw 2 ;7 retlw 2 ;8 retlw 3 ;9 retlw 3 ;10 retlw 4 ;11 retlw 4 ;12 retlw 4 ;13 retlw 5 ;14 retlw 5 ;15 retlw 5 ;16 retlw 6 ;17 retlw 6 ;18 retlw 6 ;19 nop ;20 ; в неполной тысяче не может быть nop ;21 ; более 19 пятидесяток nop ;22 ; но часть таблицы для 20-31 nop ;23 ; вставлена для страховки nop ;24 ; от ошибок вычислений nop ;25 nop ;26 ; чтоб не висло, когда не нужно nop ;27 nop ;28 nop ;29 nop ;30 retlw 6 ;31 end