PDA

View Full Version : Timers !



n qwerty
- 21st August 2007, 14:51
I cant get my head around timers at all. Tryin to get an accurate clock which will increment every 0.01 (10ms) Using a 4Mhz crystal with a pic16f77 and trying to set up the Timer1 module. so far ive got

countertotal var word
countertotal.Lowbyte = TMR1L
countertotal.highbyte = TMR1H

TMR1Preset con $D8F1


DEFINE OSC 4
'================================================= =============================
'Setting LCD parameters
'================================================= =============================

DEFINE LCD_DREG PORTD 'sets LCD data port
DEFINE LCD_DBIT 4 'sets starting bit
DEFINE LCD_RSREG PORTD 'sets LCD register select port
DEFINE LCD_RSBIT 0 'sets LCD register select bit
DEFINE LCD_EREG PORTD 'sets LCD enable port
DEFINE LCD_EBIT 1 'sets LCD enable bit
DEFINE LCD_BITS 4 'sets LCD bus size (4 bits)
DEFINE LCD_LINES 2 'sets number of lines on the LCD display

'Tie R/W pin to oV since the LCDIN will not be used.

DEFINE LCD_COMMANDUS 2000 'sets command delay time in us
DEFINE LCD_DATAUS 50 'sets data delay time in us

'================================================= =============================
'Initialisation of PORT's
'================================================= =============================

TRISA=%00000000 'bits 0 and 1 need to be outputs for RS and E on LCD
TRISB=%11111000
TRISC=%00000000
TRISD=%00000000 'set to outputs to drive the LCD

OPTION_REG.7=0 'Enable Pull-Up's on PORTB

ADCON1 = $07

T1CON = %00000000 'bits 6 & 7 are unimplemented
'bits 4 & 5 set the prescale value to 1:1
'bit 3 shuts off oscillator
'bit 2 is set to 0 to put tmr1 into timer mode - 0 is counter mode
'bit 1 is set to 0 for internal clock1
'bit 0 is set to 0 in order to stop the clock - 1 enables the timer

PIE1.0 = 1 'enables the tmr1 overflow interrupt
PIR1.0 = 0 'resets tmr1 interrupt flag
INTCON.6 = 1 'enables all unmasked peripheral interrupts
INTCON.7 = 1 'enables all unmasked global interrupts

'================================================= =============================
'Main Program
'================================================= =============================

pause 500 'initialise LCD

LCDOUT $FE, 1, "Hello"
LCDOUT $FE, $C0, "World"

pause 2000 'displays the above for 5 seconds



TMR1H = $D8
TMR1L = $F1






waitforstart:
if PORTB.5 = 0 then
T1CON.0 = 1 'starts timer
LCDOUT $FE, 1, "Timer started"
goto loop
else
goto waitforstart
endif

loop:

ticker var byte
if PIR1.0 = 1 then
PIR1.0 = 0
ticker = ticker + 1
endif

LCDout $FE, $C0,Dec5 ticker


goto loop

end.

I believe that you need to preset the timer and using mister_e calculator it seems to want to be preloaded with 55537 (D8F1 hex)

It does count up, but nowhere near every 10ms

Any ideas?

Bruce
- 22nd August 2007, 01:51
If you enable interrupts, then you need an interrupt handler. If you prefer just to monitor the
timer1 overflow flag, then disable global interrupts.

Here's one example of monitoring the timer1 overflow flag without interrupts.

Just replace the LCD port assignments & port settings to match your board. I tested this on
a LAB-X1 board.

Note: You can remove the TOGGLE 0 stuff. I used the output for a scope probe.


DEFINE OSC 4
DEFINE LOADER_USED 1

'=================================================
'Setting LCD parameters
'=================================================

' Define LAB-X1 LCD registers and bits
Define LCD_DREG PORTD
Define LCD_DBIT 4
Define LCD_RSREG PORTE
Define LCD_RSBIT 0
Define LCD_EREG PORTE
Define LCD_EBIT 1
Define LCD_COMMANDUS 2000
Define LCD_DATAUS 50

ticker VAR WORD
T1LO CON $F1 ' constant values for 10mS timer1 overflows
T1HI CON $D8 ' use with 1:1 prescale at 4MHz

ticker = 0 ' clear ticker on power-up

ADCON1 = 7 ' Set PORTA and PORTE to digital
Low PORTE.2 ' LCD R/W line low (W)
Pause 1000 ' Wait for LCD to start up

'=================================================
'Initialisation of PORT's
'=================================================

PORTB = 0
TRISB=%11110000
OPTION_REG.7=0 'Enable Pull-Up's on PORTB

T1CON = 0 '1:1 prescale, internal clock
PIE1.0 = 1 'enables the tmr1 overflow interrupt
PIR1.0 = 0 'resets tmr1 interrupt flag
INTCON.6 = 0 'disable peripheral interrupts
INTCON.7 = 0 'disable global interrupts

'=================================================
'Main Program
'=================================================

pause 500 'initialise LCD

LCDOUT $FE, 1, "Hello"
LCDOUT $FE, $C0, "World"

pause 2000 'displays the above for 5 seconds

LCDOUT $fe,1
LCDOUT "-- press button"

TMR1H = T1HI ' load timer1 for 10mS interrupts
TMR1L = T1LO

waitforstart:
if PORTB.5 = 0 then
LCDOUT $FE, 1, "Timer started"
T1CON.0 = 1 'starts timer
goto loop
endif
goto waitforstart

loop: ' loop waiting for timer1 overflow
WHILE PIR1.0=0 ' timer1 overflow?
WEND ' no, keep waiting
PIR1.0 = 0 ' clear overflow flag
TOGGLE 0 ' 10mS pulse on RB0
ticker = ticker + 1 ' inc ticker
LCDout $FE,$C0,DEC5 ticker ' display ticker

' timer1 is still ticking, so we'll stop it, then add
' in our value for 10mS interrupts
T1CON.0 = 0 ' stop timer1
TMR1L = TMR1L + T1LO ' add in low byte
IF TMR1L < T1LO THEN ' did low byte overflow?
TMR1H = TMR1H + 1 ' yes, increment high byte
ENDIF
TMR1H = TMR1H + T1HI ' no, just add in high byte
T1CON.0=1 ' start timer1
GOTO Loop

END
If you want to use interrupts, here's another version using ON INTERRUPT,


DEFINE OSC 4
DEFINE LOADER_USED 1

'=================================================
'Setting LCD parameters
'=================================================

' Define LAB-X1 LCD registers and bits
Define LCD_DREG PORTD
Define LCD_DBIT 4
Define LCD_RSREG PORTE
Define LCD_RSBIT 0
Define LCD_EREG PORTE
Define LCD_EBIT 1
Define LCD_COMMANDUS 2000
Define LCD_DATAUS 50

ticker VAR WORD
T1LO CON $F1 ' constant values for 10mS interrupts with
T1HI CON $D8 ' timer1 1:1 prescale and 4MHz osc

ticker = 0 ' clear ticker on power-up

ADCON1 = 7 ' Set PORTA and PORTE to digital
Low PORTE.2 ' LCD R/W line low (W)
Pause 1000 ' Wait for LCD to start up

'=================================================
'Initialisation of PORT's
'=================================================

PORTB = 0
TRISB=%11110000
OPTION_REG.7=0 'Enable Pull-Up's on PORTB

T1CON = 0 '1:1 prescale, internal clock
PIE1.0 = 1 'enables the tmr1 overflow interrupt
PIR1.0 = 0 'resets tmr1 interrupt flag
INTCON.6 = 1 'enables all unmasked peripheral interrupts
INTCON.7 = 1 'enables global interrupts

'=================================================
'Main Program
'=================================================

pause 500 'initialise LCD

LCDOUT $FE, 1, "Hello"
LCDOUT $FE, $C0, "World"

pause 2000 'displays the above for 5 seconds

LCDOUT $fe,1
LCDOUT "-- press button"

TMR1H = T1HI ' load timer1 for 10mS interrupts
TMR1L = T1LO

waitforstart:
if PORTB.5 = 0 then
LCDOUT $FE, 1, "Timer started"
T1CON.0 = 1 'starts timer
goto loop
endif
goto waitforstart

ON INTERRUPT goto BasicInt

loop: ' loop waiting for interrupt & display updates
@ NOP
GOTO Loop

' update & display ticker on each interrupt
DISABLE
BasicInt:
TOGGLE 0 ' toggle RB0 every 10mS
ticker = ticker + 1 ' increment ticker
LCDout $FE,$C0,DEC5 ticker ' display ticker

' timer1 is still ticking, so we'll stop it, then add
' in our value for 10mS interrupts
T1CON.0 = 0 ' stop timer1
PIR1.0 = 0 ' clear overflow flag
TMR1L = TMR1L + T1LO ' add in low byte
IF TMR1L < T1LO THEN ' did low byte overflow?
TMR1H = TMR1H + 1 ' yes, increment high byte
ENDIF
TMR1H = TMR1H + T1HI ' no, just add in high byte
T1CON.0=1 ' start timer1
RESUME
ENABLE

END
Once you understand how these work, you can go for the big guns, and use Darrel Taylors'
instant interrupts here http://www.picbasic.co.uk/forum/showthread.php?t=3251

Then you'll really start having fun...;o}

n qwerty
- 22nd August 2007, 11:39
cheers bruce, willl give it a go today, hopefully will get it working, altho may have to give up on the interrupts till im more experience with pics.