Kronos Robotics and Electronics
Site Map
 
Home Zeus Projects App Notes Downloads Dios Athena Forums
 

DAN122

Dios Timer Primer

  By Michael Simpson

Timers can be very useful.  You can use them to time events or to create intervals.  In this application note I'm going to take you through the various ways the Dios can utilize one of its 4 hardware timers.  The examples use Timer 0 but they should apply to all the timers with minor variations.

Timer 0 can be used as both a counter and a timer.  In this case we will be using it as a timer.  Even so there is not much difference between the two.  It all has to do with the source that clicks away at the timer.  When used as a counter you provide the source of high/low transitions to port 17.  When used as a timer the source is the system clock.  Each tick is equal to 1 nano second in the Dios.

How does a timer work

Each timer has an internal counter.  Some are 8 bit some are 16 bit.  Some can be both.  When a timer is enabled the counter starts ticking based on the source.  When the counter overflows (goes from 65535 to 0 for 16 bit) (255 to 0 for 8 bit) it generates an interrupt.  In the Interrupt handler we can do things like set other counters or IO ports.

An interesting point is that we can pre set the Timer counter with a value so it does not have to go through its complete cycle.  In this way we can control the timing very closely.

Timers don't have to generate IRQ's  you can start a timer then read it at any time.  I will show you an example of this later.

Registers

Since the Dios is build on the 18Fxxx architecture we will use the 18Fxxx registers to set up the timer.  Lets take a look at each one

TCON0

This register sets the specifics for the timer.

Bits 0-2 set up the presale value.  What is a presale?  The timers are very fast.  Timer 0 increments a count once each nano second.   So lets say the you need to time a longer event.  We use a prescale.  A prescal of 1:2 will yield 1/2 the counts so we need to multiply the result by 2 to get the actual number of nano seconds elapsed.

000 1:2

001 1:4

010 1:8

011 1:16

100 1:32

101 1:64

110 1:128

111 1:256

Bit 3 Turns on or off the prescale value completely.  If set to 0 then a reading of 1:1 will result.  IF set to 1 then the bits 0-2 are used to set the prescale.

Bit 4 Sets the source edge select.  1=increment on high to low.  0=increment on low to high

Bit 5 Sets the source of the pin counter.  0=Use internal clock (timer).  1=Use transition of Port 17 (counter)

Bit 6 Sets 8 bit or 16 bit operation.  0=16 bit operation. 1=8 bit operation

Bit 7 Turns the timer on and off.  0=off  1=on

TMR0L and TMR0H

These registers contain the actual value of the timers counter.   When writing to them always write to TMR0H first.   When reading always read from TMR0L first.

INTCON

Only a couple of these bits are used for Timer 0.

Bit 5 This bit enables timer 0 to generate an interrupt each time it over flows.  0=no interrupt  1=interrupt

Bit 7 This bit turns on or off all interrupts.  0=all off  1=all on

 

Ok that's enough gobly gook.  Lets get to some program examples.

 


Example 1


This first program will demonstrate the use of a non IRQ based timer.  We start the timer then take readings by calling the readtimer function.   Note that I reset the timer after each call my setting the TMR0L and TMR0H to 0.  Also no prescale has been set so the returned value is in actual nano seconds

I can see the starttimer and readtimer functions making there way into a library.

Program 1 download it here

func main()
  dim retvalue

  starttimer(0)
  pauseus 500
  retvalue = readtimer()
  print "Pause took ",retvalue,"ns"
  retvalue = readtimer()
  print "print took ",retvalue,"ns"
endfunc


func starttimer()
  'Setup timer 0
  T0CON = 0
  T0CON.bit(3)= 1 'No prescale' Fastest operation

  'When writing to the timer register alwasy write the high byte first
  TMR0H=0
  TMR0L=0
  T0CON.bit(7) = 1 'Turn timer on
  endfunc

func readtimer()
  dim timervalue

  'When reading timer register always read the low byte first
  timervalue.byte(0) = TMR0L
  timervalue.byte(1) = TMR0H

  'Resset the timer
    TMR0H=0
    TMR0L=0
  exit timervalue
endfunc

 


Example 2


In this program I enhanced the starttimer0 and readtimer0 functions.   You can now set the speed of the timer.

starttimer0(speed)

This function starts timer 0.  You supply an optional argument to set the speed that the timer operates.

speed:  Optional

0 1:1  default

1 1:2

2 1:4

3 1:8

4 1:16

5 1:32

6 1:64

7 1:128

8 1:256

readtimer0(reset)

Returns the timer 0 counter.  0-65535

reset

0:  Dont reset.  default

1:  reset counter

stoptimer0()

Turns timer0 off

 

Program 2 download it here

func main()
  dim retvalue

  starttimer0(0)
  pauseus 500
  retvalue = readtimer0(1)
  print "Pause took ",retvalue,"ns"
  retvalue = readtimer0(1)
  print "print took ",retvalue,"ns"
endfunc


func starttimer0(speed)
     if OPP8 = 0 then
         speed = 0
     endif

     branch speed,speed0,speed1,speed2,speed3,speed4,speed5,speed6,speed7,speed8

  'No prescale Fastest operation
  '1:1
 speed0:
   T0CON = 0
   T0CON.bit(3)= 1 'No prescale
   goto cont

'1:2
speed1:
   T0CON = 0
   T0CON.bit(3)= 0 'Use Prescale
   goto cont

'1:4
speed2:
   T0CON = 1
   T0CON.bit(3)= 0 'Use Prescale
   goto cont


'1:8
speed3:
   T0CON = 2
   T0CON.bit(3)= 0 'Use Prescale
   goto cont

'1:16
speed4:
   T0CON = 3
   T0CON.bit(3)= 0 'Use Prescale
   goto cont

'1:32
speed5:
   T0CON = 4
   T0CON.bit(3)= 0 'Use Prescale
   goto cont

'1:64
speed6:
   T0CON = 5
   T0CON.bit(3)= 0 'Use Prescale
   goto cont

'1:128
speed7:
   T0CON = 6
   T0CON.bit(3)= 0 'Use Prescale
   goto cont

'1:256
speed8:
   T0CON = 7
   T0CON.bit(3)= 0 'Use Prescale
   goto cont

cont:

'When writing to the timer register alwasy write the high byte first
   TMR0H=0
   TMR0L=0
   T0CON.bit(7) = 1 'Turn timer on
endfunc


'Pass 1 if you want to reset counter to 0
func readtimer0(reset)
dim timervalue
   if OPP8 = 0 then
     reset = 0
   endif

'When reading timer register always read the low byte first
   timervalue.byte(0) = TMR0L
   timervalue.byte(1) = TMR0H
   if reset = 1 then
     TMR0H=0
     TMR0L=0
   endif
   exit timervalue
endfunc

func stoptimer0()
   T0CON.bit(7) = 0 'Turn timer off
endfunc

 


Example 3


In this example we are going to set up a software IRQ handler.    Software IRQ handlers are flaged to run after a hardware IRQ has fired on the next Dios Command Cycle. 

To set up a software IRQ we use the onirq command.

Program 3 download it here

func main()
   global counter
   dim x
   clear

   setTMR0reg()  'Go set up the hardware registers for Timer 0

   onirq TMR0,timerfunc  'Here is where we tell it which software function to call

loop:
   print counter
   for x = 1 to 5000
     pauseus 10
   next
   goto loop

endfunc

'--------------------------------------------
irqfunc timerfunc()
   counter = counter + 1
   exitirq TMR0
endirq
 

'---------------------------------------------
func setTMR0reg()

'Setup timer 0
   T0CON = 3 'Set the timer0 prescale to 1:16
   T0CON.bit(3) = 0 'Make sure you use prescale
   T0CON.bit(7) = 1 'Turn timer on


'IRQ stuff
   INTCON.bit(5) = 1 'Enable Timer 0 IRQ
   INTCON.bit(7) = 1 'Enable global interupts

endfunc

 


Example 4


In this example we made the IRQ a bit more useful.   We took the basic counter an had it increment the variables sec,min and hours.  This allowed us to create a clock that can me used for short intervals.  You will have to tweek the counter a bit to make it more accurate.

Program 4 download it here

func main()
   global counter as integer
   global sec as integer
   global min as integer
   global hour as integer

   dim x
   clear

   setTMR0reg() 'Go set up the hardware registers for Timer 0

   onirq TMR0,timerfunc 'Here is where we tell it which software function

   decmask %10000011 'Set display mask to 2 digit
loop:
   print hour,":",min,":",sec
   for x = 1 to 5000
     pauseus 10
     next
   goto loop

endfunc



irqfunc timerfunc()
   counter = counter + 1

    if counter = 10 then
      counter = 0
     sec = sec + 1
     if sec = 60 then
       sec = 0
       min = min + 1
       if min = 60 then
         min = 0
         hour = hour + 1
       endif
     endif
   endif

   exitirq TMR0
endirq


func setTMR0reg()

'Setup timer 0
   T0CON = 3 'Set the timer0 prescale to 1:16
   T0CON.bit(3) = 0 'Make sure you use prescale
   T0CON.bit(7) = 1 'Turn timer on


'IRQ stuff
   INTCON.bit(5) = 1 'Enable Timer 0 IRQ
   INTCON.bit(7) = 1 'Enable global interupts

endfunc

 


Example 5


One problem with software IRQ handlers that if extream accuracy is needed they can be delayed from opperating while certain commands are run.  For instance if you use a pause 5000 command the software IRQ will not fire for 5 seconds.   One solution is to break the pause 5000 command down with multiple smaller pause commands.

However you may want to create a hardware IRQ handler.  Hardware handlers must be written in assembly so they are not for the faint of heart.  It my goal to provide enough examples the eventually you can just modify one of the handlers already written.

Hardware handlers are written using the startirqasm command.

Note on hardware handlers.   It is possible to steal every cycle away from the main program if events are happing faster than the handler can process them.

Program 5 download it here

func main()
    global counter as integer
    global sec as integer
    global min as integer
    global hour as integer


    dim x
    clear

'Set the timer
    hour = 5
    min = 50

    setTMR0reg() 'Go set up the hardware registers for Timer 0

decmask %10000011
loop:
    print hour,":",min,":",sec
    pause 500
    goto loop

endfunc


func setTMR0reg()

'Setup timer 0
    T0CON = 3 'Set the timer0 prescale to 1:16
    T0CON.bit(3) = 0 'Make sure you use prescale
    T0CON.bit(7) = 1 'Turn timer on


'IRQ stuff
    INTCON.bit(5) = 1 'Enable Timer 0 IRQ
    INTCON.bit(7) = 1 'Enable global interupts

endfunc



'Can be placed outside functions
'---------------------------------------------------
'IRQ handler for INT0 IRQ
'---------------------------------------------------
startirqasm TMR0
    movlb .2 ;We need this to access global variables
 

;======================================

incf G_counterl,f


;If counter < 10 then just exit
    movlw .10
    subwf G_counterl,w
    btfss STATUS,Z
    goto exithandler

    clrf G_counterl
 

;======================================
    incf G_secl,f

;If sec < 60 just exit
    movlw .60
    subwf G_secl,w
    btfss STATUS,Z
    goto exithandler

    clrf G_secl
 

;======================================
   incf G_minl,f

;If min < 60 just exit
   movlw .60
   subwf G_minl,w
    btfss STATUS,Z
    goto exithandler

    clrf G_minl
 

;======================================
    infsnz G_hourl,f
    incf G_hourh,f
 


exithandler

;Use this to tweek time
    movlw .1 ;Major adjustmets bigger for faster
    movwf TMR0H
    movlw .0 ;Minor adjustment bigger for faster
    movwf TMR0L

endirqasm

 

 

Well that's it for the timer primer.  I hoped you learned a little something. 

parts list

Breadboard Speaker

 

 

DiosPro 40 Pin Chip

Dios Workboard Deluxe

 

Easy RS232 Driver  

DiosPro 28 Pin Chip

Dios 32 Pin Carrier (Carrier #1)

 

9 Pin Cable

Breadboard Regulator

 

 

Copyright © 2001 - 2007 Kronos Robotics