• 16-Digits Elapsed Timer Using 7-Segment Displays

    OMER YILDIZ
    ' June 2009 ' PIC 16F628A - 20Mhz
    ' This example shows how to drive 16-digits 7-Segment displays
    ' using 3 PIC pins only (via 74HC595)
    ' This example also shows DT's elapsed timer application from 1/100 second
    'to 255 years (Byte variable should be good enough to hold year value !)
    ' This example also shows how to start/stop DT's elapsed timer application
    ' using RB0 Ext. Interrupt pin using DT's int routine within the same program.

    ' Anode segment arrangement.
    EEPROM
    0, [$c0,$F9,$A4,$B0,$99,$92,$82,$F8,$80,$90]
    ' Cathode segment arrangement.
    EEPROM
    100,[$3F,$06,$5B,$4F,$66,$6D,$7D,$07,$7F,$6F]

    @ __config _HS_OSC & _WDT_OFF & _PWRTE_OFF & _MCLRE_OFF & _BODEN_ON & _LVP_OFF & _CP_ON & _DATA_CP_ON

    PAUSE 100
    DEFINE OSC 20
    ' Using 4Mhz osc is ok but may have some flickering
    ' on displays if all 16-digits are being used.
    ' Thus, 20Mhz osc is used in this application.

    CMCON = 7 ' Disable Comps.
    PAUSE
    1
    VRCON = 0 ' Turn off VRCON.
    PAUSE
    1

    ' RA4 Reset button, RA6-RA7 OSC.
    TRISA = %00010000

    ' RB0 Int. start/stop button.
    TRISB = %00000001

    PORTA = 0
    PORTB = 0

    StStp VAR T1CON.0 ' Start/Stop bit. Start stop flag for Timer counter.
    Digs VAR BYTE ' Holds the common pin index for the displays.
    DigLine VAR WORD ' Common pins of the displays will be turned
    'on/off by this variable via 74HC595.
    Display VAR BYTE ' Segment arrangement will be set by this variable via 74HC595.
    DT VAR Display.7 ' Dot led on displays via 74HC595.
    DTFlag VAR BIT ' Holds the set/clear value for Dot led.
    EEAdrs VAR BYTE ' EEPROM address for anode / cathode displays are different.

    '====== User changes dynamic settings here ===========
    NumOfDigits CON 16 ' How many digits are we driving?
    DigTerm CON NumOfDigits ' Add one more for coding pusposes.

    ' Select display type, anode or cathode?
    DispType VAR BIT ' This bit could be a jumper on a pic pin for external option.
    Anode CON 0
    Cathode CON 1

    'RA0-RA3 not used.
    Reset VAR PORTA.4 ' Reset button
    '( This pin can also be used for TMR0 counter mode).
    'RA5 not used.
    'RA6-RA7 external Crystal.

    ' RB0-RB3 notused.
    Dat VAR PORTB.4 ' 74HC595 DATA pin.
    Strobe VAR PORTB.5 ' 74HC595 Latch pin.
    'PORTB.6 '(This pin can also be used for TMR1 counter mode)
    ' Not used in this program.
    Clk VAR PORTB.7 ' 74HC595 Clock pin.

    PAUSE
    100

    INCLUDE "DT_INTS-14.bas"
    INCLUDE "ReEnterPBP.bas"

    ; Modified Elapsed Timer Routines. This is not the same as DT's original routine.
    INCLUDE
    "Elapsed_INTmod.bas"

    ASM
    INT_LIST macro ; IntSource, Label, Type, ResetFlag?
    INT_Handler INT_INT, _ToggleFlag, PBP, yes
    INT_Handler TMR1_INT, _ClockCount, PBP, yes
    endm
    INT_CREATE
    ; Creates the interrupt processor
    ENDASM

    @ INT_ENABLE INT_INT ; enable external (INT) interrupts
    @ INT_ENABLE TMR1_INT ; Enable Timer 1 Interrupts

    Begin:
    StStp = 0 ' Make sure timer is off.
    Digs = 0 ' Set the starting digit index to zero (from right to left).
    ' disptype = cathode ' Select a display type. I use Common Anode display.
    DispType = Anode

    GOSUB ResetTime ' Reset Timer.

    Main:
    ' Reset only when Timer is not counting.
    ' If reset button accidentally pressed
    ' when the timer is ON, it won't work. Safety first! Don't smoke.
    IF
    Reset + StStp = 0 THEN GOSUB resettime

    SELECT CASE DispType

    CASE Cathode
    ' We are driving Cathode diplay here, pull all pins high.
    DigLine = %1111111111111111
    DigLine.0[Digs] = 0 ' Leave the next digit low.
    EEAdrs = 100 'Eprom address for cathode display segments
    DTFlag = 1 ' Dot is set by 1 for cathode displays.

    CASE
    Anode
    ' We are driving Anode diplay here, pull all pins low.
    DigLine = %0000000000000000
    DigLine.0[Digs] = 1 ' Leave the next digit high.
    EEAdrs = 0 ' Eprom address for anode display segments
    DTFlag = 0 ' Dot is set by 0 for anode displays.
    END SELECT

    ' Read digit number in line, and assign segment arrangement to display variable.
    READ
    ( (ary[Digs]) + EEAdrs),Display

    'Ary[0],[1] = Milisecond Dig 0 and Dig1
    'Ary[2],[3] = Second Dig 0 and Dig1
    'Ary[4],[5] = Minute Dig 0 and Dig1
    'Ary[6],[7] = Hour Dig 0 and Dig1
    'Ary[8],[9],[10] = Day Dig 0,Dig1,Dig2
    'Ary[11],[12],[13] = Years Dig 0,Dig1,Dig2
    'Ary[14],[15] = None

    ' Turn dot ON/OFF for floating point purposes etc. Adjust as desired.
    SELECT CASE
    Digs
    CASE 2,4,6,8,11
    DT = DTFlag
    END SELECT

    ' ========== Drive the displays and the segments ===========
    'Send digit index and segment arrangement at one shot.
    SHIFTOUT
    Dat,Clk,1,[DigLine\16,Display\8]
    Strobe = 1 'Latch'em all.
    Strobe = 0

    '========Scan Frequency - Optional =======================
    ' Adjust the scan frequency using TMR0 interrupt.
    'This way, PAUSE command is not used.
    ' Driving digits more then 8, does not require scan frequency;
    ' PIC's process time is good enough to provide a scan delay.
    ' IF flickering occurs on display, increase the scan frequency
    ' by reducing the TMR0 int time, OR use a higher osc speed.;
    ' TOIF = 0
    ' TMR0 = 0
    ' Delay: ' Should a RB0 interrupt or TMR1 interrupt
    ' occur here, we can catch it. Thus, no PAUSE.
    ' if TOIF = 0 then delay ' Scan delay.

    Digs = Digs + 1
    IF Digs = DigTerm THEN Digs = 0


    GOTO Main


    '--- INT RB0 - interrupt handler, Start/Stop button pressed =>>
    ' Start or stop the timer. ---
    ToggleFlag:
    StStp = StStp ^1 ' ON/OFF Timer.
    T1CON.1 = 0
    T1CON.3 = 0
    @ INT_RETURN


    END

    by Sayzer