PIC Timer 1 preload value

Status
Not open for further replies.

augustinetez

Active Member
Would somebody please check my maths for the preload value of Timer1 on a 16F1827 running at 4MHz.

I'm looking for a delay of 5mS, pretty sure I've screwed this up because it's taking a lot longer than 5mS on the hardware.

65536-(delay*clock freq)/(prescaler*4) = 65536-((.005*4000000)/(1*4))=60536 (EC78 HEX)

Thanks
 
Use the MCC to create the code for you, or one of the many PIC Timer Calculators (either on-line, or downloadable).

'Generally' when you end up with a much longer delay than you wanted, it's because you've got the clock oscillator set to the wrong frequency (been there, done that - many times )

Here's code generated by MikroElektronika's calculator - note it gives the same value as you - check your clock!!

C:
//Timer1
//Prescaler 1:1; TMR1 Preload = 60536; Actual Interrupt Time : 5 ms
 
//Place/Copy this part in declaration section
void InitTimer1(){
  T1CON     = 0x01;
  TMR1IF_bit     = 0;
  TMR1H     = 0xEC;
  TMR1L     = 0x78;
  TMR1IE_bit     = 1;
  INTCON     = 0xC0;
}
 
void Interrupt(){
  if (TMR1IF_bit){
    TMR1IF_bit = 0;
    TMR1H     = 0xEC;
    TMR1L     = 0x78;
    //Enter your code here
  }
}
 
I get the same pre-load, which won't be exact because of housekeeping. As for the much longer delay,check your system oscillator. The default is 500 kHz. I had a similar problem last year, and it was some careless error in my oscillator settings. For 4 MHz, OSCON=b'0110 101x' . Less likely, be sure your TMR1 prescale is 00 (1:1) e.g. T1CON=b'0000 0001' or similar.
 
Forget using a preload value, check out the Special Events Trigger function of timer1.

Mike.
BTW, 5mS is 5000 clock cycles with a 4 MHz clock..
 
This relates back to my variable encoder post a few days ago.

Small test program to display what the encoder count is (on an 16x2 LCD) in a 5mS period according to how fast the encoder is turned.

Here's the code - very messy, especially the encoder routine - it's all bits'n'pieces from various other programs.

Using Timer1 as it it appears to be the only one you can actually stop and start easily rather than a continually running timer.

All I'm doing is starting the timer, continually looping through the encoder routine while polling the TMR1IF flag and then displaying the count on the LCD when it's set.

Code:
;
; *******************************************************************************
; *    Encoder variable rate test V0.01                    *
; *    Version 0.01                                *
; *    19 September 2022                            *
; *    Author: T Mowles VK5TM                            *
; *******************************************************************************
;
;                                                                             
;    Target Controller - PIC16F1827
;                        __________                                         
;    SPARE-------RA2 |1       18| RA1----ENCODER A                   
;    SPARE-------RA3 |2       17| RA0----ENCODER B                   
;    SPARE-------RA4 |3       16| RA7----SPARE                       
;    SPARE-------RA5 |4       15| RA6----SPARE                       
;    Ground------Vss |5       14| VDD----+5 V                       
;    LCD D4------RB0 |6       13| RB7----SPARE                   
;    LCD D5------RB1 |7       12| RB6----LCD_rs  (LCD Pin 4)         
;    LCD D6------RB2 |8       11| RB5----LCD_rw  (LCD Pin 5)           
;    LCD D7------RB3 |9       10| RB4----LCD_e   (LCD Pin 6)         
;                        ----------                                         
;                                                                             
;; *******************************************************************************
;; *    Device type and options.                        *
;; *******************************************************************************
;;
;    processor 16F628A
;    radix     dec
;    errorlevel -302  ; Skip out of bank nuisance messages
;;
;; *******************************************************************************
;; *    Configuration fuse information for 16F628A:                *
;; *******************************************************************************
;;
;    include   <P16F628A.INC>
;
;    __config _CP_OFF&_LVP_OFF&_BODEN_OFF&_MCLRE_OFF&_PWRTE_ON&_WDT_OFF& _INTOSC_OSC_NOCLKOUT
;;
; *******************************************************************************
; * Device type and options                            *
; *******************************************************************************
;
        processor 16F1827
        radix     dec
;    errorlevel -207    ; Skip found label after column 1
    errorlevel -302    ; Skip out of bank nuisance messages
    errorlevel -303    ; Skip program word too large. Truncated to core size
            ; Above error caused by faulty Microchip inc file
;
; *******************************************************************************
; * Configuration fuse information for 16F1827:                    *
; *******************************************************************************
;
        include   <P16F1827.INC>

 __CONFIG _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOREN_ON & _CLKOUTEN_OFF & _IESO_OFF & _FCMEN_OFF
 __CONFIG _CONFIG2, _WRT_OFF & _PLLEN_OFF & _STVREN_OFF & _BORV_LO & _LVP_OFF
;
; *******************************************************************************
; Info for power-up display                                                   
MCODE_REV_0  equ  ' '     ;
MCODE_REV_1  equ  'V'     ;
MCODE_REV_2  equ  '0'     ;
MCODE_REV_3  equ  '.'     ;
MCODE_REV_4  equ  '0'     ;
MCODE_REV_5  equ  '1'     ;
MCODE_REV_6  equ  ' '     ;
MCODE_REV_7  equ  ' '     ;
;
; *******************************************************************************
; *    General equates                                *
; *******************************************************************************
;
;    16F1827 Oscillator setup
    ; OSCCON - Oscillator control reg.
    ; ---------------------------------
    ; SPLLEN bit 7 enable PLL x4
    ; 1 = enabled 0 = disabled
    ; IRCF | bits 6-3 frequency selection
    ; 1111 = 16MHz HF
    ; 1110 = 8 or 32MHz HF
    ; 1101 = 4MHz HF
    ; 1100 = 2MHz HF
    ; 1011 = 1MHz HF
    ; 1010 = 500kHz HF
    ; 1001 = 250kHz HF
    ; 1000 = 125kHz HF
    ; 0111 = 500kHz MF (default)
    ; 0110 = 250kHz MF
    ; 0101 = 125kHz MF
    ; 0100 = 62.5kHz MF
    ; 0011 = 31.25kHz HF
    ; 0010 = 31.25kHz MF
    ; 000x = 31.25kHz LF
    ; Reserved bit 2 reserved, 0
    ; SCS      bits 1-0: 1x = int. OSC.
    ; 01 = Timer1 oscillator
    ; 00 = determined by FOSC <2:0> in Configuration
    ; POR default 00111-00 500 kHz (POR = Power On Reset)

OSCCONVAL    EQU    b'01101000'    ; 4MhZ CLOCK
;
; *******************************************************************************
; *    Assign names to IO pins                            *
; *******************************************************************************
;
;    B register bits:
;
LCD_busy    equ    0x03    ; LCD busy bit
LCD_e        equ    0x04    ; 0=disable, 1=enable
LCD_rw        equ    0x05    ; 0=write, 1=read
LCD_rs        equ    0x06    ; 0=instruction, 1=data
;
; *******************************************************************************
; *    Allocate variables in general purpose register space            *
; *******************************************************************************
;
    CBLOCK    0x20        ; Start Data Block
    LCD_char        ; Character being sent to the LCD
    timer1            ; Used in delay routines
    CounterA        ;   "
    CounterB        ;   "
    CounterC        ;   "
    CounterD        ;   "
    CounterE        ;   "
    count            ; loop counter  (gets reused)
    rs_value        ; The LCD rs line flag value
    NumH
    NumL
    TenK
    Thou
    Hund
    Tens
    Ones
    byte2send
    bit_count
    enc_count1
    enc_count0
    enc_read
    enc_new
    enc_old
    next_dir
    last_dir
    dir
    flags

    ENDC            ; End of Data Block

    CBLOCK  0x70
;    freq_1            ; Use bank common locations - saves bank switching when
;       freq_0            ; saving/retreiving to/from EEPROM

    ENDC            ; End of Data Block


; *******************************************************************************
; * The 16F628 resets to 0x00                            *
; * The Interrupt vector is at 0x04                        *
; *******************************************************************************
;
    ORG    0x0000               
    goto    start        ;

    ORG    0x0004        ;
    GOTO    start
;
; *******************************************************************************
; * Purpose:                                    *
; *    This is the start of the program                    *
; *                                        *
; *******************************************************************************
;
start
    clrf    PORTA
    clrf    PORTB
    clrf    enc_count1
    clrf    enc_count0

; Set PIC oscillator frequency
    banksel    OSCCON        ; Select OSCCON
    movlw    OSCCONVAL    ;
    movwf    OSCCON        ; Loads the wanted PIC oscillator value

; Configures I/O as analog/digital
    Banksel    ANSELA
    clrf    ANSELA        ; PORTA all digital
    clrf    ANSELB        ; PORTB all digital

; Disable all wakeup pull-ups
    Banksel    WPUA
    clrf    WPUA
    clrf    WPUB

    banksel    OPTION_REG
    movlw    b'10000000'    ; Pull-ups disabled
    movwf    OPTION_REG    ;


    banksel    TRISA        ; Switch to bank 1
    movlw    0xFF        ; Tristate PORTA (all Inputs)
    movwf    TRISA        ;
    clrf    TRISB        ; Set port B to all outputs
    banksel    PORTB        ; Switch back to bank 0

    movlw    b'00000000'
    movwf    T1CON
    movwf    T1GCON
    clrf    TMR1H
    clrf    TMR1L


    call    init_LCD    ; Initialize the LCD
    call    display_version


    movf    PORTA,w        ; Get the power on encoder value
    andlw    b'00000011'    ; Get encoder mask (PORTB,0 and PORTB,1)   
    movwf   enc_old        ; Save encoder bits and zero all other bits
    clrf    dir        ; Clear the knob direction indicator


    call    wait_a_sec

    movlw    1
    call    cmnd2LCD    ; Send command in w to LCD

; -------------------------------------------------------------------------------
main
    call    poll_encoder

    call    bin2BCD

    call    show_count

    goto    main

;
; *******************************************************************************
; *                                        *
; * Purpose:    This routine does the following:                *
; *                                        *
; *        Tests to see if the Step Size switch is pressed and changes the    *
; *        step size if it is pushed                    *
; *                                        *
; *        Monitors the RIT/Clarifier control for any change and exits    *
; *        the routine if it changes                    *
; *                                        *
; *        Continously polls the encoder for any change and if it does    *
; *        determines the direction the knob was moved. Routine exits if    *
; *        encoder moves                            *
; *                                        *
; *******************************************************************************
;
poll_encoder
    bcf    flags,6
    clrf    enc_count0
    bcf    PIR1,TMR1IF
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop    ; dummy NOPs for commands in actual program
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
;
read_encoder
    movf    PORTA,w        ; Get the current encoder value
    andlw    b'00000011'    ; mask encoder B and A switches
    movwf    enc_read    ; Save it
    movlw    b'00000011'    ; Get encoder mask (to isolate RB0 and RB1)
    andwf    enc_read,w    ; Isolated encoder bits into W
    movwf    enc_new        ; Save new value
    xorwf    enc_old,w    ; Has it changed?
    btfsc    STATUS,Z    ; Check zero-flag (zero if no change)
    goto    poll_encoder    ; No change, keep looking until it changes
                ; Else, Zero-flag is not set, so continue on
    btfss    flags,6
    call    load_timer
    incf    enc_count0,f



; It changed. Now determine which direction the encoder turned.

    bcf    STATUS,C    ; Clear the carry bit to prepare for rotate
    rlf    enc_old,f    ; Rotate old bits left to align "Right-Bit"
    movf    enc_new,w    ; Set up new bits in W                     
    xorwf    enc_old,f    ; XOR old (left shifted) with new bits     
    movf    enc_old,w    ; Put XOR results into W also               
    andlw    b'00000010'    ; Mask to look at only "Left-Bit" of pair
    movwf    next_dir    ; Save result (in W) as direction (bit=UP) 
    xorwf    last_dir,w    ; See if direction is same as before
      
;****************** For optical encoder *****************************************
;       Prevent encoder slip from giving a false change in direction.

    btfsc    STATUS,Z    ; Zero flag set? (i.e, is direction same?) 
    goto    enc_continue    ; Yes, same direction so no slip; keep going
    movf    next_dir,w    ; No Zero-flag, so direction changed       
    movwf    last_dir    ; Update the direction indicator           
    movf    enc_new,w    ; Save the current encoder bits (now in W) 
    movwf    enc_old        ; for next time                           
    goto    poll_encoder    ; Try again
;********************************************************************************
;
enc_continue
    clrf    last_dir    ; Clear last_dir (default is DN)
    bcf    dir,0
    btfsc    enc_old,1    ; Are we going UP?             
    goto    enc_up        ; Yes, go process it.
                ; Else, we are goiong down
    goto    enc_movement    ; Indicate that the encoder has moved

enc_up
    movlw    b'00000010'    ; Get UP value
    movwf    last_dir    ; and set in last_dir
    bsf    dir,0

enc_movement            ; Arrive here when encoder is being turned
    movf    enc_new,w    ; Get the current encoder bits
    movwf    enc_old        ; Save them in ren_old for the next time

    btfss    PIR1,TMR1IF
    BRA    read_encoder
    bcf    T1CON,TMR1ON
    bsf    flags,2        ; Set encoder changed flag

    return            ; Return to the caller
;
load_timer
    bsf    flags,6
;    movlw    0xD8        ; 10mS
    movlw    0xEC        ; 5mS
    movwf    TMR1H
;    movlw    0xF0
    movlw    0x78
    movwf    TMR1L
    bsf    T1CON,TMR1ON
    return
;

;; *******************************************************************************
;; * Purpose:                                    *
;; *    This subroutine converts a 16 bit binary number to decimal in       *
;; *    TenK, Thou, Hund, Tens, Ones                        *
;; *    Written by John Payson.                            *
;; *******************************************************************************
;;
bin2BCD    ; Takes number in freq_1:freq_0 returns decimal in TenK:Thou:Hund:Tens:Ones
    movfw    enc_count1
    movwf    NumH
    movfw    enc_count0
    movwf    NumL

    swapf    NumH,w
    IORLW    0xF0
    movwf    Thou
    addwf    Thou,f
    addlw    0xE2
    movwf    Hund
    addlw    0x32
    movwf    Ones

    movf    NumH,w
    andlw    0x0F
    addwf    Hund,f
    addwf    Hund,f
    addwf    Ones,f
    addlw    0xE9
    movwf    Tens
    addwf    Tens,f
    addwf    Tens,f

    swapf    NumL,w
    andlw    0x0F
    addwf    Tens,f
    addwf    Ones,f

    rlf    Tens,f
    rlf    Ones,f
    comf    Ones,f
    rlf    Ones,f

    movf    NumL,w
    andlw    0x0F
    addwf    Ones,f
    rlf    Thou,f

    movlw    0x07
    movwf    TenK

; At this point, the original number is equal to TenK*10000+Thou*1000+Hund*100+Tens*10+Ones
; if those entities are regarded as two's compliment binary.
; To be precise, all of them are negative except TenK. 
; Now the number needs to be normalized, but this can all be done with simple byte arithmetic.

    movlw    0x0A        ; Ten
Lb1:
    addwf    Ones,f
    decf    Tens,f
    btfss    STATUS,C
    goto    Lb1
Lb2:
    addwf    Tens,f
    decf    Hund,f
    btfss    STATUS,C
    goto    Lb2
Lb3:
    addwf    Hund,f
    decf    Thou,f
    btfss    STATUS,C
    goto    Lb3
Lb4:
    addwf    Thou,f
    decf    TenK,f
    btfss    STATUS,C
    goto    Lb4

    return
;;
; *******************************************************************************
; * Purpose:                                    *
; *    Display the frequency on the LCD.                    *
; *                                        *
; *******************************************************************************
;
show_count
    movlw    0xC5        ; Point the LCD to digit location
    call    cmnd2LCD    ; Send digit location to LCD

    movfw    TenK
    addlw    0x00        ; Test if 'w'is 0 or 1
    btfss    STATUS,Z    ; The Z or Zero bit is set to "1" when the result
    goto    not_zero    ; of an arithmetic or logical operation is zero

    movlw    ' '        ; TenK = 0, insert space
    call    data2LCD    ; Send byte in W to LCD
    goto    show_thou

not_zero
    call    process        ; TenK is not 0, insert number

show_thou
    movfw    Thou
    call    process        ;

    movfw    Hund
    call    process        ;
 
    movfw    Tens
    call    process        ;

    movfw    Ones
    call    process        ;

    return
process
    addlw    0x30
    call    data2LCD
    return
;
; *******************************************************************************
; * Purpose:                                    *
; *    Power on initialization of Liquid Crystal Display            *
; *    The LCD controller chip must be equivalent to an Hitachi 44780        *
; *                                        *
; *******************************************************************************
;
init_LCD
    movlw    100
    call    wait        ; Wait for LCD to power up (100mS)

;    Put 4-bit command in RB3..RB0                                         
;    PIC's RB3..RB0 lines connect to LCD's DB7..DB4 (pins 14-11)           
    movlw    0x03        ; LCD init instruction (First)               
    movwf    PORTB        ; Send to LCD via RB3..RB0                   
    bsf    PORTB,LCD_e    ; Set the LCD E line high,
    nop
    bcf    PORTB,LCD_e    ; and then Clear E

    call    wait_100us

    movlw    0x03        ; LCD init instruction (Second)             
    movwf    PORTB        ; Send to LCD via RB3..RB0                   
    bsf    PORTB,LCD_e    ; Set E high,
    nop
    bcf    PORTB,LCD_e    ; and then Clear E

    call    wait_100us

    movlw    0x03        ; LCD init instruction (Third)               
    movwf    PORTB        ; Send to LCD via RB3..RB0                   
    bsf    PORTB,LCD_e    ; Set E high,
    nop
    bcf    PORTB,LCD_e    ; and then Clear E

    call    wait_100us    ; wait a while,

    movlw    0x02        ; 4-bit mode instruction                     
    movwf    PORTB        ; Send to LCD via RB3..RB0                   
    bsf    PORTB,LCD_e    ; Set E high,
    nop
    bcf    PORTB,LCD_e    ; and then Clear E

    call    wait_100us    ; wait a while,

    movlw    0x28        ; 1/16 duty cycle, 5x8 matrix
    call    cmnd2LCD    ; Send command in w to LCD

    call    wait_100us

;    movlw    0x08        ; Display off, cursor and blink off
;    movlw    0x0C        ; Display on, cursor and blink off
    movlw    0x0E        ; Display on, cursor on and blink off
;    movlw    0x0F        ; Display on, cursor and blink on
    call    cmnd2LCD    ; Send command to LCD

    call    wait_100us

    movlw    0x01        ; Clear and reset cursor
    call    cmnd2LCD    ; Send command in w to LCD

    movlw    2
    call     wait        ; wait a while,

    movlw    0x06        ; Set cursor to move right, no shift
    call    cmnd2LCD    ; Send command in w to LCD

    return            ;
;
; *******************************************************************************
; * Purpose:                                    *
; *    Send Command or Data byte to the LCD                    *
; *    Entry point cmnd2LCD: Send a Command to the LCD                *
; *    Entry Point data2LCD: Send a Data byte to the LCD            *
; *                                        *
; *******************************************************************************
;
cmnd2LCD   ; ****** Entry point ******
    clrf    rs_value        ; Remember to clear RS  (clear rs_value)   
    goto    write2LCD        ; Go to common code
data2LCD   ; ****** Entry point ********
    bsf    rs_value,0        ; Remember to set RS (set bit 0 of rs_value)
write2LCD
    movwf    LCD_char        ; Save byte to write to LCD
    call    busy_check        ; Check to see if LCD is ready for new data

    MOVLW    2            ;
    MOVWF    count            ; SET UP LOOP COUNTER
write_again
    SWAPF    LCD_char,F        ; SWAP MS & LS NIBBLES
    MOVF    LCD_char,W
    ANDLW    15            ; MAKE TOP 4 BITS OF W 0
    MOVWF    PORTB            ; SEND MS NIBBLE
    bcf    PORTB,LCD_rs        ; Guess RS should be clear - command mode
    btfsc    rs_value,0        ; Should RS be clear?  (is bit 0 == 0?)
    bsf    PORTB,LCD_rs        ; No, set RS - data mode
    NOP
    BSF    PORTB,LCD_e        ; SET E HIGH
    NOP
    BCF    PORTB,LCD_e        ; SET E LOW
    DECFSZ    count,F
    GOTO    write_again        ; GO BACK AND SEND LS NIBBLE
    clrf    PORTB
    return
;
; *******************************************************************************
; * Purpose:                                    *
; *    Check if LCD is done with the last operation.                *
; *    This subroutine polls the LCD busy flag to determine if previous    *
; *    operations are completed.                        *
; *                                        *
; *******************************************************************************
;
busy_check
    banksel  TRISB               ;Switch to bank for Tris operation
    movlw    b'00001111'         ;Set ALL 4 to input, others outputs
    movwf    TRISB
    banksel  PORTB
    bcf      PORTB,LCD_rs        ;Set up LCD for Read Busy Flag (RS = 0)
    bsf      PORTB,LCD_rw        ;Set up LCD for Read (RW = 1)
LCD_is_busy
    bsf      PORTB,LCD_e         ;Set E high
    NOP
    movfw    PORTB               ;move busy flag into W
    bcf      PORTB,LCD_e         ;Set E low
    NOP
    bsf      PORTB,LCD_e         ;perform dummy read
    NOP
    bcf      PORTB,LCD_e         ;Set E low       
    andlw    1<<LCD_busy
    BTFSS    STATUS,Z
    GOTO     LCD_is_busy
    banksel  TRISB                ;Switch to bank 1 for Tristate operation
    clrf     TRISB                ;All pins (RB7..RB0) are back to outputs
    banksel  PORTB                ;Switch to bank 0
    RETURN
;
; ****************************************************************************P
; *                                                                           P
; * Purpose:  Display version and other info on LCD for 2 seconds             P
; *           upon power-up                                                   P
; *                                                                           P
; *   Input:  MCODE_REV_0 through MCODE_REV_4 set up                          P
; *                                                                           P
; *  Output:  LCD displays debug info                                         P
; *                                                                           P
; ****************************************************************************P
;
display_version
    movlw    0x80        ; Point LCD at digit 1               
    call    cmnd2LCD    ;
    movlw    'V'        ; digit 1             
    call    data2LCD    ;
    movlw    'A'        ; digit 2                 
    call    data2LCD    ;
    movlw    'R'        ; digit 3               
    call    data2LCD    ;
    movlw    ' '        ; digit 4               
    call    data2LCD    ;
    movlw    'R'        ; digit 5             
    call    data2LCD    ;       
    movlw    'A'        ; digit 6             
    call    data2LCD    ;
    movlw    'T'        ; digit 7               
    call    data2LCD    ;
    movlw    'E'        ; digit 8               
    call    data2LCD    ;
    movlw    MCODE_REV_0    ; Get mcode rev byte
    call    data2LCD    ; and display it (digit 9)
    movlw    MCODE_REV_1    ; Get mcode rev byte
    call    data2LCD    ; and display it (digit 10)
    movlw    MCODE_REV_2    ; Get mcode rev byte
    call    data2LCD    ; and display it (digit 11)
    movlw    MCODE_REV_3    ; Get mcode rev byte
    call    data2LCD    ; and display it (digit 12)
    movlw    MCODE_REV_4    ; Get mcode rev byte
    call    data2LCD    ; and display it (digit 13)
    movlw    MCODE_REV_5    ; Get mcode rev byte
    call    data2LCD    ; and display it (digit 14)
    movlw    MCODE_REV_6    ; Get mcode rev byte
    call    data2LCD    ; and display it (digit 15)
    movlw    MCODE_REV_7    ; Get mcode rev byte
    call    data2LCD    ; and display it (digit 16)

    nop

LINE2
    movlw    0xC0        ; Point LCD at digit 1 of second line
    call    cmnd2LCD    ;
    movlw    'E'        ; digit 1
    call    data2LCD    ;
    movlw    'N'        ; digit 2
    call    data2LCD    ;
    movlw    'C'        ; digit 3
    call    data2LCD    ;
    movlw    'O'        ; digit 4
    call    data2LCD    ;
    movlw    'D'        ; digit 5
    call    data2LCD    ;
    movlw    'E'        ; digit 6 0xC5
    call    data2LCD    ;
    movlw    'R'        ; digit 7
    call    data2LCD    ;
    movlw    ' '        ; digit 8
    call    data2LCD    ;
    movlw    'T'        ; digit 9
    call    data2LCD    ;
    movlw    'E'        ; digit 10
    call    data2LCD    ;
    movlw    'S'        ; digit 11
    call    data2LCD    ;
    movlw    'T'        ; digit 12
    call    data2LCD    ;
    movlw    ' '        ; digit 13
    call    data2LCD    ;
    movlw    ' '        ; digit 14
    call    data2LCD    ;
    movlw    ' '        ; digit 15
    call    data2LCD    ;
    movlw    ' '        ; digit 16
    call    data2LCD    ;
    return
;
; *******************************************************************************
; *                                        *
; * Purpose:  Delay routines                            *
; *                                        *
; *******************************************************************************
;
wait_a_sec ;PIC Time Delay = 0.99999900 s with Osc = 4000000 Hz
    movlw    D'6'
    movwf    CounterC
    movlw    D'19'
    movwf    CounterB
    movlw    D'172'
    movwf    CounterA
loop
    decfsz    CounterA,f
    goto    loop
    decfsz    CounterB,f
    goto    loop
    decfsz    CounterC,f
    goto    loop
    return

wait_250
    movlw    250

wait
    movwf    timer1        ; Set up counter
    call    wait_1ms    ; Go to wait loops
    decfsz    timer1,f
    goto    $-2
    return

wait_1ms     ;PIC Time Delay = 0.00099800 s with Osc = 4MHz
    movlw    D'2'
    movwf    CounterD
    movlw    D'74'
    movwf    CounterE
loop1
    decfsz    CounterE,f
    goto    loop1
    decfsz    CounterD,f
    goto    loop1
    return

wait_100us    ;PIC Time Delay = 0.00009800 s with Osc = 4MHz
    movlw    D'31'
    movwf    CounterA
loop2
    decfsz    CounterA,1
    goto    loop2
    return
;       
; *****************************************************************************
;
    END
 
I have seen that one - the sliders drive me nuts - the handles need to be bigger.

Ended up doing an Excel sheet (below).
The page is protected to stop entering values in the wrong place, but if anybody wants to look 'underneath the hood', the password is 1234
 

Attachments

  • PIC Timer Calculator.zip
    7.9 KB · Views: 329
I did the pin toggling bit this afternoon, suffice to say, there's a problem somewhere in what I'm doing.

Total period for the toggle cycle on the scope is 131.20mS so divide that by 2 and allow a minute bit of overhead gives a Timer1 period of ~65mS instead of 1mS.

Code below for the toggle.
Code:
;
; *******************************************************************************
; *    Timer1 test                                 *
; *    Version 0.01                                *
; *    21 September 2022                            *
; *    Author: T Mowles VK5TM                            *
; *******************************************************************************
;
;                                                                             
;    Target Controller - PIC16F1827
;                        __________                                         
;    SPARE-------RA2 |1       18| RA1----ENCODER A                   
;    SPARE-------RA3 |2       17| RA0----ENCODER B                   
;    SPARE-------RA4 |3       16| RA7----SPARE                       
;    SPARE-------RA5 |4       15| RA6----SPARE                       
;    Ground------Vss |5       14| VDD----+5 V                       
;    LCD D4------RB0 |6       13| RB7----SPARE                   
;    LCD D5------RB1 |7       12| RB6----LCD_rs  (LCD Pin 4)         
;    LCD D6------RB2 |8       11| RB5----LCD_rw  (LCD Pin 5)           
;    LCD D7------RB3 |9       10| RB4----LCD_e   (LCD Pin 6)         
;                        ----------                                         
;                                                                             
; *******************************************************************************
; * Device type and options                            *
; *******************************************************************************
;
        processor 16F1827
        radix     dec
;    errorlevel -207    ; Skip found label after column 1
    errorlevel -302    ; Skip out of bank nuisance messages
    errorlevel -303    ; Skip program word too large. Truncated to core size
            ; Above error caused by faulty Microchip inc file
;
; *******************************************************************************
; * Configuration fuse information for 16F1827:                    *
; *******************************************************************************
;
        include   <P16F1827.INC>

 __CONFIG _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOREN_ON & _CLKOUTEN_OFF & _IESO_OFF & _FCMEN_OFF
 __CONFIG _CONFIG2, _WRT_OFF & _PLLEN_OFF & _STVREN_OFF & _BORV_LO & _LVP_OFF
;
; *******************************************************************************
; *    General equates                                *
; *******************************************************************************
;
;    16F1827 Oscillator setup
    ; OSCCON - Oscillator control reg.
    ; ---------------------------------
    ; SPLLEN bit 7 enable PLL x4
    ; 1 = enabled 0 = disabled
    ; IRCF | bits 6-3 frequency selection
    ; 1111 = 16MHz HF
    ; 1110 = 8 or 32MHz HF
    ; 1101 = 4MHz HF
    ; 1100 = 2MHz HF
    ; 1011 = 1MHz HF
    ; 1010 = 500kHz HF
    ; 1001 = 250kHz HF
    ; 1000 = 125kHz HF
    ; 0111 = 500kHz MF (default)
    ; 0110 = 250kHz MF
    ; 0101 = 125kHz MF
    ; 0100 = 62.5kHz MF
    ; 0011 = 31.25kHz HF
    ; 0010 = 31.25kHz MF
    ; 000x = 31.25kHz LF
    ; Reserved bit 2 reserved, 0
    ; SCS      bits 1-0: 1x = int. OSC.
    ; 01 = Timer1 oscillator
    ; 00 = determined by FOSC <2:0> in Configuration
    ; POR default 00111-00 500 kHz (POR = Power On Reset)

OSCCONVAL    EQU    b'01101000'    ; 4MhZ CLOCK
;
; *******************************************************************************
; * The 16F1827 resets to 0x00                            *
; * The Interrupt vector is at 0x04                        *
; *******************************************************************************
;
    ORG    0x0000               
    goto    start        ;

    ORG    0x0004        ;
    GOTO    start
;
; *******************************************************************************
; * Purpose:                                    *
; *    This is the start of the program                    *
; *                                        *
; *******************************************************************************
;
start
    clrf    PORTA
    clrf    PORTB

; Set PIC oscillator frequency
    BANKSEL    OSCCON        ; Select OSCCON
    movlw    OSCCONVAL    ;
    movwf    OSCCON        ; Loads the wanted PIC oscillator value

; Configures I/O as analog/digital
    BANKSEL    ANSELA
    clrf    ANSELA        ; PORTA all digital
    clrf    ANSELB        ; PORTB all digital

; Disable all wakeup pull-ups
    BANKSEL    WPUA
    clrf    WPUA
    clrf    WPUB

    BANKSEL    OPTION_REG
    movlw    b'10000000'    ; Pull-ups disabled
    movwf    OPTION_REG    ;


    BANKSEL    TRISA        ; Switch to bank 1
    movlw    0xFF        ; PORTA all Inputs
    movwf    TRISA        ;
    clrf    TRISB        ; PORTB all outputs
    movlb    0        ; Switch back to bank 0

;    movlw    b'00000000'
;    movwf    T1CON
;    movwf    T1GCON
    clrf    T1CON
    clrf    T1GCON
    clrf    TMR1H
    clrf    TMR1L

toggle_pin ;(RB7)
;    movlw    0x3C        ; 50mS
;    movlw    0xD8        ; 10mS
;    movlw    0xEC        ; 5mS
    movlw    0xFC        ; 1mS
    movwf    TMR1H
;    movlw    0xB0
;    movlw    0xF0
;    movlw    0x78
    movlw    0x18
    movwf    TMR1L
    bsf    T1CON,TMR1ON
    BANKSEL    LATB
    bsf    LATB,7
    movlb    0
    btfss    PIR1,TMR1IF
    goto    $-1
    bcf    T1CON,TMR1ON
    bcf    PIR1,TMR1IF
    BANKSEL    LATB
    bcf    LATB,7
    movlb    0
    bsf    T1CON,TMR1ON
    btfss    PIR1,TMR1IF
    goto    $-1
    bcf    T1CON,TMR1ON
    bcf    PIR1,TMR1IF
    goto    $-16

    END
 
It would appear you set the timer to XXXX but then don't.. the second, third etc is full timer ( lots of cycles )

This is one of those times $-16 can go un noticed
 
This is likely the culprit ... If you are connected to the ICSP Programmer, then after programming it counts as a "Reset" so your PIC is defaulting to 500kHz.

At the beginning of your code you will want to set the OSCCON register bits 6-3 to b'1101' for 4MHz operation.



Reference: (Page 57,60 and Page 65)


Edit: Check BIT 1 of the OSCCON register .... your setting it to 0 ... Think it should be set to 1

 
Last edited:
I think Ian has the correct answer, and I agree it's a bad idea to use a numerical branch in that way for that distance, if he had used a label for the branch the issue wouldn't have occurred. Numeric branches are great for just hopping over the next word or two, but for any sort of distance use a label.

Here's my OSCON setting for 4MHz from 11 years ago, when I first started using the 16F1827.

Code:
                banksel    OSCCON            ; select bank 1
                movlw     b'01101010'        ; set 4MHz clock
                movwf     OSCCON
                banksel    0x00            ; select bank 0

Bit 1 set to '1' sets the use of the internal oscillator, leaving it set to '0' (as the OP did) leaves the oscillator decision set by the FOSC bits in CONFIG word 1. Personally I set BOTH to internal oscillator
 
I've never used a 16F1827 ... I just went from the datasheet and my experience with other micros that have bit me in similar ways. My favorite family of micros are the PIC16F15xxx series.
 
Status
Not open for further replies.
Cookies are required to use this site. You must accept them to continue using the site. Learn more…