1. Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.
    Dismiss Notice

[PIC] Timer1 used as a 1.024ms delay me thinks... (code sample attached)

Discussion in 'Microcontrollers' started by William At MyBlueRoom, Jan 16, 2007.

  1. William At MyBlueRoom

    William At MyBlueRoom New Member

    Joined:
    Feb 28, 2006
    Messages:
    721
    Likes:
    1
    Location:
    Toronto, Canada
    I'd like comments on this simple delay routine. Instead of loops I've used Timer1 with an 8MHz crystal and a 1:8 prescaler. It should increment the LSB every 4us and the TMR1H register every 1.024ms. My math could be off (and my thinking too :confused:) Comments?

    Code (text):
    TMRDLY   ;*** using TMR1 as a delay for LCD setup call with W
             ;*** 1.024ms per TMR1H, Delay in ms = 255 - (W * 1.024)
             bcf      STATUS, RP0                ;B0
             clrf     TMR1L                      ;B0 added as per eblc1388 suggestion.
             movwf    TMR1H                      ;B0 TMR1H = W (976us)
             bcf      PIR1, TMR1IF               ;B0 clear the interrupt flag
             btfss    PIR1, TMR1IF               ;B0 test TMR1IF for overflow
             goto     $-1                        ; wait for TMR1IF (overflow)
             return
     
    Last edited: Jan 18, 2007
  2. kchriste

    kchriste New Member Forum Supporter

    Joined:
    Jul 23, 2006
    Messages:
    3,677
    Likes:
    47
    Location:
    Victoria BC, Canada
    I haven't checked your math and I assume you've intialized Timer1 first, but I've used this method before. It allows for accurate timing when you have an ISR running in the background.
     
  3. donniedj

    donniedj Banned

    Joined:
    Jan 16, 2004
    Messages:
    336
    Likes:
    3
    Location:
    So Cal
    Timer1 trips its flag when the whole 16-bit word overflows pass 0xFFFF, not just the high side byte TMR1H. You have to load TMR1L and TMR1H with the correct values which intales performing subtraction for the CALL, RETURN, loading TMR1L TMR1H and general code delays. When you finally find the correct values to plug into the timers, you will have to do it all over again if you want a delay other than this fixed time. To load them with any value other than 1 to indicate 1 millisecond goes against logic.

    TMR1H= 1, TMR1L= 2 : so the delay = 257 milliseconds is logical.

    TMR1H= 153, TMR1L= 231: so the delay = desired time not representative of the variables is illogical .

    The LCD does not have to be precise down to a few microseconds. Using a general millisecond delay routine will work for this and all your other code. Now though the timer is used here, this is still a looping routine. Detecting if a register hits zero or if a flag bit gets set never the less is still a loop once you use Goto $ - 1. Using a timer as a true interrupt is what will qualify the delay as non looping.

    Timers are too precious for grunt work like general delays.
     
  4. dave

    Dave New Member

    Joined:
    Jan 12, 1997
    Messages:
    -
    Likes:
    0


     
  5. William At MyBlueRoom

    William At MyBlueRoom New Member

    Joined:
    Feb 28, 2006
    Messages:
    721
    Likes:
    1
    Location:
    Toronto, Canada

    I agree, Timers are far too few to be used this way. The exception is using it to initialize delays on a cold start. Once the LCD is setup I'll switch to reading the busy flag instead.
     
  6. eblc1388

    eblc1388 Active Member

    Joined:
    Jan 25, 2005
    Messages:
    2,228
    Likes:
    18
    Location:
    UK
    Just add a "CLRF TMR1L" instruction before loading the W value into TMR1H and the code would be fine.
     
  7. phalanx

    phalanx Member

    Joined:
    Oct 22, 2003
    Messages:
    405
    Likes:
    7
    Location:
    New Hampshire, USA
    What PIC are you using? Unless you get lucky with the pre and postscaler settings on a timer that will allow for properly timed periodic interrupts without preloading the timer registers, you are pretty much stuck using a timer with a period register. For most PICs, Timer 2 is the one with that functionality. The dsPIC and PIC24 line have period registers on every timer.

    Is Timer 2 available in your application or is it tied up with other resources?
     
  8. William At MyBlueRoom

    William At MyBlueRoom New Member

    Joined:
    Feb 28, 2006
    Messages:
    721
    Likes:
    1
    Location:
    Toronto, Canada
    All the Timers are free at first, It's mostly for setting up a LCD in 4 bit mode (real slow devices) then I switch to reading the BF (busy flag).
     
  9. Nigel Goodwin

    Nigel Goodwin Super Moderator Most Helpful Member

    Joined:
    Nov 17, 2003
    Messages:
    39,324
    Likes:
    653
    Location:
    Derbyshire, UK
    Why not just use a simple software loop?.
     
  10. Mike - K8LH

    Mike - K8LH Well-Known Member

    Joined:
    Jan 22, 2005
    Messages:
    3,642
    Likes:
    109
    Location:
    Michigan, USA
    I agree. Why bother with all the Timer 1 mess for a one-time delay?
     
  11. William At MyBlueRoom

    William At MyBlueRoom New Member

    Joined:
    Feb 28, 2006
    Messages:
    721
    Likes:
    1
    Location:
    Toronto, Canada
    Seemed pretty straight forward, no variables required, easy to solve the timing loop, irq friendly (if you want to do it that way). I call it four times to get the 4 bit mode setup.

    Got a decent decfsz version? Here's the LCD init routine

    Code (text):
    LCD_INIT          ;send 0x03 three times to enter 4 bit mode
             bcf      STATUS, RP0                ;B0
             bsf      LCD_E                      ;B0 enable bit high
             movlw    0x03                       ;B0 send 03 to PORTA
             movwf    PORTA                      ;B0
             movlw    .240                       ; 15ms delay
             bcf      LCD_E                      ;B0 latch data to LCD PORTA
             call     TMRDLY
             bsf      LCD_E                      ;B0 enable bit high
             movlw    0x03                       ;B0 send 03 to PORTA
             movwf    PORTA                      ;B0
             movlw    .254                       ; .5ms delay
             bcf      LCD_E                      ;B0 latch data to LCD PORTA
             call     TMRDLY                                
             bsf      LCD_E                      ;B0 enable bit high
             movlw    0x03                       ;B0 send 03 to PORTA
             movwf    PORTA                      ;B0
             movlw    .250                       ; 5ms delay
             bcf      LCD_E                      ;B0 latch data to LCD PORTA
             call     TMRDLY
             bsf      LCD_E                      ;B0 enable bit high
             movlw    0x02                       ;B0 send 02 (4 bit mode set)
             movwf    PORTA                      ;B0
             movlw    .254                       ; .5 ms delay
             bcf      LCD_E                      ;B0 latch data to LCD PORTA                                
             call     TMRDLY
             return
     
    Last edited: Jan 18, 2007
  12. eng1

    eng1 New Member

    Joined:
    Apr 7, 2006
    Messages:
    951
    Likes:
    19
    Location:
    Italy
    You may use the delay code generator on the PICList.
    1.024 ms = 2048 cycles @ 8 MHz, you'll need only two variables.
     
  13. Nigel Goodwin

    Nigel Goodwin Super Moderator Most Helpful Member

    Joined:
    Nov 17, 2003
    Messages:
    39,324
    Likes:
    653
    Location:
    Derbyshire, UK
    Yes, use the delay code generator on the PICList, its nice and easy, it's used in my tutorials. You might also consider looking at my tutorial LCD code, here's the initialisation section for that.

    Code (text):
    ;Initialise LCD
    LCD_Init    movlw   0x20            ;Set 4 bit mode
            call    LCD_Cmd

            movlw   0x28            ;Set display shift
            call    LCD_Cmd

            movlw   0x06            ;Set display character mode
            call    LCD_Cmd

            movlw   0x0d            ;Set display on/off and cursor command
            call    LCD_Cmd

            call    LCD_Clr         ;clear display

            retlw   0x00
     
     
  14. William At MyBlueRoom

    William At MyBlueRoom New Member

    Joined:
    Feb 28, 2006
    Messages:
    721
    Likes:
    1
    Location:
    Toronto, Canada
  15. Nigel Goodwin

    Nigel Goodwin Super Moderator Most Helpful Member

    Joined:
    Nov 17, 2003
    Messages:
    39,324
    Likes:
    653
    Location:
    Derbyshire, UK
    That seems really strange?, and has no bearing with what the datasheets say to do?.

    My routines work perfectly, and many users all round the world have used them.
     
  16. eng1

    eng1 New Member

    Joined:
    Apr 7, 2006
    Messages:
    951
    Likes:
    19
    Location:
    Italy
    Those routines reset the controller in software. If the electrical requirements are met, the inizialization is performed by the built-in reset circuitry.
     
  17. William At MyBlueRoom

    William At MyBlueRoom New Member

    Joined:
    Feb 28, 2006
    Messages:
    721
    Likes:
    1
    Location:
    Toronto, Canada
    Which routines? Nigels or Mykes (3x 0x03)

    I've shrunk mine down with a loop...
    Code (text):
    LCD_INIT          ;send 0x03 three times to enter 4 bit mode
          movlw    .220                        ; 15ms (255 - 15/0.512) delay (before LCD is ready)
          call     TMRDLY                      ; program will halt till TMR1 overflows
          movlw    0x03                        ;B0 W = 3
          movwf    count                       ;B0 count = 3
          movwf    PORTA                       ;B0 PORTA = 3 (RS = 0)
    LCD_loop        
             bsf      LCD_E                      ;B0 enable bit high
             movlw    .245                       ; 5ms delay
             bcf      LCD_E                      ;B0 latch data to LCD PORTA
             call     TMRDLY
             decfsz   count
             goto     LCD_loop
             return
     
    Last edited: Jan 21, 2007
  18. eng1

    eng1 New Member

    Joined:
    Apr 7, 2006
    Messages:
    951
    Likes:
    19
    Location:
    Italy
    The ones you've posted, with 3x 0x03.


    To enter the 4-bit mode, you have to send 0x02.
     
    Last edited: Jan 20, 2007
  19. William At MyBlueRoom

    William At MyBlueRoom New Member

    Joined:
    Feb 28, 2006
    Messages:
    721
    Likes:
    1
    Location:
    Toronto, Canada
    It appears the 3x 0x3 gets the LCD setup. I usually send a 0x28 (4bit 2line) using a more generic byte to nibble routine (working on the BF code now) and no longer use the delay code.

    Still LCD character modules are SLOW devices.
     
  20. eng1

    eng1 New Member

    Joined:
    Apr 7, 2006
    Messages:
    951
    Likes:
    19
    Location:
    Italy
    It's called "Initialization by instructions" in the datasheet. You can always use these instructions to initialize the LCD, but they're not required if the power supply conditions are met.

    This means 2-lines of 5x8 dots. Before this, the 4 bit mode must be set by sending 0x2 (that is read as an 8-bit command by the LCD, b00100000).
     
    Last edited: Jan 21, 2007
  21. William At MyBlueRoom

    William At MyBlueRoom New Member

    Joined:
    Feb 28, 2006
    Messages:
    721
    Likes:
    1
    Location:
    Toronto, Canada
    Which datasheet do you use?

    What is the difference to an LCD between 0x28 and 0x20?
     

Share This Page