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

Coding a PIC

Discussion in 'Homework Help' started by Logjkos, Jun 24, 2017.

  1. Logjkos

    Logjkos New Member

    Joined:
    Jun 22, 2017
    Messages:
    9
    Likes:
    0
    Hi

    (Apologise in advance for the long post)

    I am after some help please, we have been given a task to program a PIC "to find the time duration for an automatic vacuum cleaning process".

    The automatic vacuum cleaning process is intitiated in some way, either through a timer or manually started and left to run, the process continues until completion at which point the time taken for this process to be completed is displayed on a 7 segment display.

    We are given the following assumptions,

    That the time recorded should be reasonably accurate, 10ths of a second should be sufficient for this.
    That the process will not take longer than 10 minutes, I am not sure how relevant this for either being able to count up or down.
    This piece of program is to be called by the main program when required.

    We have been told that the code will need three parts:
    an initialisation section
    an interrrupt section
    a delay loop itself

    We have been told that the code does not actually need to function but we do need to have some code.
    We have also been told that we should be able to find modules of code necessary from the Microchip website and simply copy and paste these to create our own program.

    The only problem that I have with this is that I will not learn very much if anything at all.

    The code that I have managed to create so far is:
    For the delay loop, using the internal 31KHz oscillator:


    "
    Delay loop


    Mov lw 0xff

    Mov 0x78

    Mov wf count

    Move wf count 1



    Loop 0



    Dec fsz count 60

    Goto loop 1

    Return



    Loop 1



    Dec fsz count 1

    Goto loop 1

    Reset

    Goto loop0


    End
    "

    It is help with the initialisation and interrupt parts of the program that I need, as well as constructive comments on the above piece of 'code'.

    I know that Jon Wilder created a basic template for the PIC16F887, located at this link:
    http://www.electro-tech-online.com/...-i-o-setup-template-for-16f887-in-asm.120899/

    That contains both an interrupt handler and an intialisation routine.
    There is obviously a lot more code in there than what I require.

    I could simply take both of these sections of code and add it to what I have created above but I was wondering if someone could possibly offer some advice on the code I have created above for a start.

    I would also like to add that prior to this course I have no relevant programming experience, a small amount in C many many years ago is all.

    Thanks in advance for any help

    Logjkos
     
  2. Ian Rogers

    Ian Rogers Super Moderator Most Helpful Member

    Joined:
    Mar 28, 2011
    Messages:
    9,251
    Likes:
    911
    Location:
    Rochdale UK
  3. Logjkos

    Logjkos New Member

    Joined:
    Jun 22, 2017
    Messages:
    9
    Likes:
    0
    Hi Ian

    Thank you for the reply, I shall have a look through the website.

    Regards
     
  4. dave

    Dave New Member

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


     
  5. Logjkos

    Logjkos New Member

    Joined:
    Jun 22, 2017
    Messages:
    9
    Likes:
    0

    Hi

    I understand that some instrucrtions take 2 cycles, others one, so if I wanted my delay to last 1/10 of a second I wuold need to change increase the count on the first loop to 300?
    Then:
    The section labelled delay: 3 cycles
    Loop 0: 1200 cycles
    Loop 1: 1800 cycles

    With a 31 KHz clock:
    The above would work out at a little under 0.1 of a second.
     
  6. jpanhalt

    jpanhalt Well-Known Member Most Helpful Member

    Joined:
    Jun 21, 2006
    Messages:
    5,983
    Likes:
    511
    Location:
    Cleveland, OH, USA
    The code fragment you post is a bit hard to follow. For example, this code
    Code (asm):

    Loop1
         Decfsz      count1
         Goto        Loop1
         Reset
         Goto        Loop0     ; won't get here
     
    will never get to the instruction "goto loop0." Are you in fact using the 16F887? Does it have a "reset" instruction?

    Maybe as you resvise the code, posting the complete revision will help avoid confusion. Also, please use code
    tags, e.g., [code=ASM] insert code here[/code]

    For your delays, you might find this code calculator, which uses nested loops, helpful: http://www.piclist.com/techref/piclist/codegen/delay.htm

    John
     
  7. Logjkos

    Logjkos New Member

    Joined:
    Jun 22, 2017
    Messages:
    9
    Likes:
    0
    John

    Thank you for your reply, the problem is that I have absolutely no knowledge of programming in assembly, we had very little guidance from the three different lecturers that we had in the year.

    So from the link you have given me, for a 31 KHz clock, I need to use the code:

    ; Delay = 0.1 seconds
    ; Clock frequency = 0.031 MHz

    ; Actual delay = 0.1 seconds = 775 cycles
    ; Error = 1.46692693834e-014 %

    cblock
    d1
    endc

    Delay
    ;769 cycles
    movlw 0x00
    movwf d1
    Delay_0
    decfsz d1, f
    goto Delay_0

    ;2 cycles
    goto $+1

    ;4 cycles (including call)
    return


    How would I organise this with respect to initialisation and interrupt code?

    As for the choice of PIC, due to problems we have had during the academic year this has not been defined in the assignemnt given.

    Regards
    (edited for typo)
     
  8. Les Jones

    Les Jones Well-Known Member

    Joined:
    May 15, 2015
    Messages:
    1,451
    Likes:
    189
    Location:
    Lancashire UK
    Hi Logjkos,
    As You are required to use interrupts I would suggest using a 16 bit counter if the chosen PIC has one (If not an 8 bit counter and it's prescaler.) You could use this to count CPU cycles and interrupt every o.1 seconds. As these counters only count up you would have to pre load them with the overflow value (65536 decimal.) minus the number of cycles you need to count. When the counter overflows it would cause an interrupt. The interupt service routine (ISR) Would just increment a counter that would count in 0.1 seconds. At the start of the event you would set this counter to zero. At the end of the event you would copy the contents of this counter to give you the time.You could be running code to display the current time value without having the CPU counting cycles.

    Les.
     
    Last edited: Jun 25, 2017
    • Agree Agree x 1
  9. Colin

    Colin Member

    Joined:
    Sep 25, 2003
    Messages:
    397
    Likes:
    22
    Location:
    Australia
    Why not use the internal 4MHz osc?
     
  10. Logjkos

    Logjkos New Member

    Joined:
    Jun 22, 2017
    Messages:
    9
    Likes:
    0
    Hi Colin

    I guess the only advantage of using the 4MHz clock is more accuracy with counting the actual time elapsed?
    This is a genuine question as I have no knowledge on this subject at all.

    Hi Les

    The PIC we had to use was initially specified, however in the actual assignment we have been given there is no mention of the PIC we have to use.
    Therefore using a PIC with a 16 bit counter is possible, it is just a matter of how to implement this and I have no clue as to how to do this.

    Thanks in advance.
     
  11. Les Jones

    Les Jones Well-Known Member

    Joined:
    May 15, 2015
    Messages:
    1,451
    Likes:
    189
    Location:
    Lancashire UK
    Hi Logjkos,
    Here is some code I wrote several years ago for a tachometer. You will be able to see the sort of thing that is required ti initialize a 16 bit counter module and see the sort of code required in the iterrupt routine to generate interrupts at the time period. (0.8616 ms in this case with a 20 Mhz clock) The interrupt routine in this case first has to decide if it is an interrupt on change or a timer interrupt. (You will probably only have to deal with timer interrupts) The interrupt routine starts at location "Interrupt" and the part of the routine that deals with the timer (Counter) is at loaction "Timer_Int"

    Code (text):

    ;Rev counter LED display
    ;For Sig X3 Mill

    ;   Spindle gear on mill 34 teeth
    ;   To get 60 pulses (Revs per second to revs per minute) need gate time of 60/34 = 1.7647058823529411764705882352941 seconds gate time.
    ;  
    ; Using port B interrupt on change we get 2 interrupts per tooth so now need gate time of 60/68 =0.88235294117647058823529411764706 seconds gate time.
    ; Version 00  

    ;Gate_Count divides by 256 , multiplexing divides by 4 so total division here is 1024
    ;0.88235294117647058823529411764706/1024 = 861.67279411764705882352941176471 us

    ;Using 20 Mhz xtal system clock is 5 Mhz   (200ns)

    ;861.67279411764705882352941176471 / 0.2 = 4308.3639705882352941176470588235
    ;Using 4308 will be accurate enough. (4308 * 0.2 us = 861.6 us)
       
    ;PIC16f628A, set for 20.00MHz XTAL, WDT OFF, POR on
    ;Instruction time at 20MHZ is 0.2 us




       list P=16f628
       #include "p16f628a.inc"
    ;   __config _RC_OSC & _WDT_OFF & _PWRTE_ON
       __config _HS_OSC & _WDT_OFF & _PWRTE_ON & _LVP_OFF

    ;written in MASM



    ;Preset    = 65536 - 4308 = 61228               (4308 * 0.2 us = 861.6 us)
    ;But 7 CPU cycles required to reload timer so value to load timer with will be 61235
    Preset       EQU   d'61235'




    delay1       EQU 0x20        ;Used in delay routine
    delay2       EQU 0x21        ;Used in delay routine
    delay3       EQU 0x22        ;Used in delay routine
    Counter_Low   EQU 0x23   ;Counts incoming pulses           (In BCD )
    Counter_High   EQU 0x24   ;Counts incoming pulses
    Count_Low   EQU 0x25   ;Latched count to be displayed
    Count_High   EQU 0x26   ;Latched count to be displayed
    Dig_Count   EQU 0x27   ;Current digit being displayed  (Only bits 0 & 1 used)
    Gate_Count   EQU 0x28   ;Final divide by 256 to give 0.88235 seconds gate time


    LED_Port   EQU PORTA
    Dig_Port   EQU PORTB


    ;==========================================================================
    ;
    ;I/O Pin useage

    ;   RA0       Output   BCD to 7447 IC LSB      (Pin 17)
    ;   RA1       Output   BCD to 7447 IC           (Pin 18)
    ;   RA2       Output   BCD to 7447 IC            (Pin 1)
    ;   RA3       Output   BCD to 7447 IC MSB   (Pin 2)
    ;   RA4/TOCK1   Input   Not yet used       (Pin 3)

    ;                  
    ;   RB0/INT       Output     Digit drive bit 4 LSB            (Pin 6)   Ative low
    ;   RB1       Output     Digit drive bit 3            (Pin 7)   Ative low
    ;   RB2       Output     Digit drive bit 2            (Pin 8)   Ative low
    ;   RB3       Output     Digit drive bit 1 MSB            (Pin 9)   Ative low

    ;   RB4       Input     Pulse input            (Pin 10)
    ;   RB5       Input     Not used           (Pin 11)  
    ;   RB6       Input     Not used            (Pin 12)  
    ;   RB7       Input        Not used           (Pin 13)
    ;


    ; define reset and interrupt vector start addresses

       org   0         ; start at address 0000h
       goto   INIT       ; normal service routines from Reset vector
       org     4       ; interrupt vector 0004h, start interrupt routine here
       goto   Interupt

    ; **********************************************************************************************



    ;   Initialize
    ;
            ORG 0x0005         ;Start of program memory


           DE      "V01 22/04/08"
    ;
    INIT    BCF INTCON,GIE          ;turn off global interrupts
            BTFSC INTCON,GIE    ;Confirm global interrupts off
            goto INIT

       movlw    0x07           ; activate PORTA for PC16F628 as digital
       movwf   CMCON

       BSF    STATUS,5   ;Select register bank 1
            movlw   B'11110000'
            movwf   TRISB         ;Configure port B0-B3 as outputs ports B4-B7 as inputs
            movlw   B'00000000'
            movwf   TRISA         ;Port A0-A4 as output
    ;

            movlw   B'00000000'    ; Weak pull-up on PORTB (bit7=0)
            movwf   OPTION_REG


       movlw   b'00000001'   ;Enable timer1 interrupt
       movwf   PIE1

       BCF   STATUS,5   ;Select register bank 0

       movlw   b'00000001'   ;Configure timer 1
       movwf   T1CON       ;Prescaler 1:1, Timer stopped.


       movlw   0x0F
       movwf   Dig_Port   ;Set all digit drives off (Active low)
       clrf   LED_Port   ;Set value to 0


       clrf   Dig_Count   ;Clear digit count (Note only bits 0 & 1 are used)
       clrf   Counter_Low
       clrf   Counter_High
       clrf   Count_Low
       clrf   Count_High
       clrf   Gate_Count
       movlw   LOW Preset
       movwf   TMR1L       ;Set division value
       movlw   HIGH Preset
       movwf   TMR1H



    ;Enable RB4 - RB7  interupt on change Bit 3
    ;turn on global interrupts

       movlw   B'11001000'       ;Global interrupts, Peripheral interrupts, Port B interrupt on change.
         movwf    INTCON          ;turn on required interrupts

    ;                   ------------------------

    MAIN               ;Main program loop Just loop waiting for interupt.
       nop
       nop


       nop
       goto   MAIN




    ;   ***************************************************************************************************

    Interupt

                           ;Sort interupts

       btfsc   PIR1,TMR1IF   ;TMR1 interupt
       goto   Timer_Int

       btfsc   INTCON,RBIF      ; Change to port b interrupt on change.
       goto   Count_Int

       retfie           ;Return if no interupt bit set SHOULD NOT GET HERE !!!!!!!!!!!!


    ;               Counter input interupt handler

    Count_Int

       bcf   INTCON,GIE       ;Disable interrupts
       movf   PORTB,W           ;Read port just to clear the port change bits

       incf    Counter_Low, F
           movfw   Counter_Low
           andlw   0x0F
           sublw   0x0A           ;Units Check for overflow
           btfss   STATUS,Z
           goto    CntintDone
           movfw   Counter_Low

           andlw   0x0F0
           addlw   0x010
           movwf   Counter_Low  
           sublw   0xA0               ;tens  Check for overflow
           btfss   STATUS,Z
           goto    CntintDone
           clrf    Counter_Low
       
           incf    Counter_High,F
           movfw   Counter_High
           andlw   0x0F
           sublw   0x0A           ;hundreds Check for overflow
           btfss   STATUS,Z
           goto    CntintDone
           movfw   Counter_High

           andlw   0x0F0
           addlw   0x010
           movwf   Counter_High
           sublw   0xA0           ;Thousands  Check for overflow
           btfss   STATUS,Z
           goto    CntintDone
           clrf    Counter_High

    ;Add code here to deal with overflow


    CntintDone
       bcf   INTCON,RBIF       ;Clear port b interrupt on change flag
       bsf   INTCON,GIE       ;Enable interrupts

       retfie



    ;                   ---------------------------
    ;               Timer interupt handler
    ;               Should come here every 0.8616 ms
    Timer_Int
       bcf   INTCON,GIE       ;Disable interrupts               0.2 us
       bcf   T1CON,0           ;Stop timer                   0.2 us
       movlw   LOW Preset       ;                       0.2 us
       movwf   TMR1L           ;Preset counter to set division value       0.2 us
       movlw   HIGH Preset       ;                       0.2 us
       movwf   TMR1H           ;                       0.2 us
       bsf   T1CON,0           ;Start timer                   0.2 us (7 cpu cycles)
       bcf   PIR1,TMR1IF       ;Clear timer 1 interupt flag
       call   Display_Next_Dig
       bsf   INTCON,GIE       ;Enable interrupts

       retfie

    ;           ---------------------------------------------------------


       
    ;               +++++++++++++++ Subroutines from here +++++++++++++++++++++++++


    ;*****************************************************************************
    ;
    ;   Function : Display next digit       (4 Digit multiplex display driver)
    ;   Increment Gate_Count every fourth time through this routine
    ;
    ;*****************************************************************************

    ;
    Display_Next_Dig



       movlw   0x0F
       movwf   Dig_Port       ;All digit drives off (Active low) Bits 0 - 3

       incf   Dig_Count,f
       btfsc   Dig_Count,1
       goto   ThreeorFour
    OneorTwo
       btfsc   Dig_Count,0
       goto   Two
    One
       swapf   Count_High,w
       movwf   LED_Port       ;Output it.
       bcf   Dig_Port,3       ;Clear bit 3 (Enable digit position 1) (Most significant)
       goto   Disp_End
    Two
       movf   Count_High,w
       movwf   LED_Port       ;Output it. (Bits 0 to 3 of LED_Port
       bcf   Dig_Port,2       ;Clear bit 2 (Enable digit position 2)
       goto   Disp_End

    ThreeorFour
       btfsc   Dig_Count,0
       goto   Four
    Three
       swapf   Count_Low,w
       movwf   LED_Port       ;Output it.
       bcf   Dig_Port,1       ;Clear bit 1 (Enable digit position 3)
       goto   Disp_End
    Four
       movf   Count_Low,w
       movwf   LED_Port       ;Output it.
       bcf   Dig_Port,0       ;Clear bit 0 (Enable digit position 4)

       incfsz   Gate_Count,f       ;Increment Gate_Count and test for overflow
       Goto   Disp_End
       movlw   0x0F
       movwf   Dig_Port       ;All digit drives off (Active low) Blank display

    ;Move count to display latches  
       movfw   Counter_Low
       movwf   Count_Low
       Movfw   Counter_High
       movwf   Count_High
    ;Clear counters
       clrf   Counter_Low
       clrf   Counter_High

    Disp_End
       return


            END               ;final line. This line must be retained.





     
    This was the simplest program I had written using interrupts. I hope this helps you get started with your program.

    Les.
     
  12. Logjkos

    Logjkos New Member

    Joined:
    Jun 22, 2017
    Messages:
    9
    Likes:
    0
    Les

    Thank you for the above, so looking at the interrupt code first, what is happening with the following hex numbers?:
    0x0F
    0x0A

    0x0F0
    0x010
    and
    0xA0

    Thanks
     
  13. Logjkos

    Logjkos New Member

    Joined:
    Jun 22, 2017
    Messages:
    9
    Likes:
    0
    Les

    But from what you said earlier though I would only need to concern myself about the timer interrupt which would be under the section :
    Timer interupt handler
    However how and where have you have defined the interrupt to be every 0.2 uS defined?
     
  14. Les Jones

    Les Jones Well-Known Member

    Joined:
    May 15, 2015
    Messages:
    1,451
    Likes:
    189
    Location:
    Lancashire UK
    It is not the code to do exactly what you require. It is just to give you an idea about initializing the PIC so it will do what you want and the layout of the interrupt service routine. We do not give direct answers to homework questions. Just guidance.
    You only need a modified version of the code after "Timer_Int" The first thing it does is to disable interrrupts and stop the counter. It then loads TIMER1 with 16 bit value which has been given the name "Preset" This has to be loaded in two steps as a PIC is an 8 bit micro. So it first loads the low byte and then the high byte of the 16 bit timer. (You could load the high byte first. it would make no difference.) The actual value of "Preset" was defined near the start of the program. This is where is is given a value
    ;Preset = 65536 - 4308 = 61228 (4308 * 0.2 us = 861.6 us)
    ;But 7 CPU cycles required to reload timer so value to load timer with will be 61235
    Preset EQU d'61235'
    The first two of the three lines are just comments to explain how it is calculated.
    The interrupt does not occure every 0.2 uS TIMER1 increments every 0.2 uS. The interrupt occures when TIMER1 overflows from 0xFFFF back to zero. This is why you need to subtract the number of counts from 65536 decimal (= 0xFFFF) The 0.2 uS is because I have used a 20 Mhz crystal (One instruction cycle is 4 clock cycles.) You will also not need the line
    call Display_Next_Dig
    I am using this to multiplex a 4 digit 7 segment display. (To display the RPM value)

    The HEX numbers that you ask about at the start if the interrupt routine are to do with counting input pulsed from a gear tooth sensor. (You will not requre that part of the code.) This counting is done in BCD. The 0x0F and the 0xF0 are used to mask for the upper or lower nibble of a byte. (Two BCD digits stored in a byte) The 0x0A (10 decimal) is use to detect when a BCD digit oveflows fro 9 to zero. The 0x10 is added to increment a BCD digit when it is stored in the hugh nibble of the byte.

    Les.
     
    Last edited: Jun 25, 2017
  15. Logjkos

    Logjkos New Member

    Joined:
    Jun 22, 2017
    Messages:
    9
    Likes:
    0
    Hi Les

    Thank you for your help but I am understanding very little of this.

    Ok, so in order to produce what I need, I will have to modify the following code:

    Timer_Int
    bcf INTCON,GIE ;Disable interrupts 0.2 us
    bcf T1CON,0 ;Stop timer 0.2 us
    movlw LOW Preset ; 0.2 us
    movwf TMR1L ;Preset counter to set division value 0.2 us
    movlw HIGH Preset ; 0.2 us
    movwf TMR1H ; 0.2 us
    bsf T1CON,0 ;Start timer 0.2 us (7 cpu cycles)
    bcf PIR1,TMR1IF ;Clear timer 1 interupt flag
    call Display_Next_Dig
    bsf INTCON,GIE ;Enable interrupts

    retfie

    So in your code Preset is set to equal 61235 (decimal) at the start of the code which equates to 0.8616 mS, the maths at the start is one of the few things I can understand what is going on.

    So if I am using a 31 KHz oscillator and my timer /delay loop is lasting, in theory for one tenth of a second, before looping back on itself, how does this equate to what you have provided above?
     
  16. Colin

    Colin Member

    Joined:
    Sep 25, 2003
    Messages:
    397
    Likes:
    22
    Location:
    Australia
    You are turning a very simple thing into something comlplex.
    If you use the 4MHz inbuilt osc, each instruction wilt take 1uS
    You only use the 32kHz osc for very low current applications
     
  17. jpanhalt

    jpanhalt Well-Known Member Most Helpful Member

    Joined:
    Jun 21, 2006
    Messages:
    5,983
    Likes:
    511
    Location:
    Cleveland, OH, USA
    We don't even know what chip he is using. Is it a basic, mid-range, or enhanced mid-range? (I think most of us are assuming a mid-range with internal oscillator.)

    I agree, run the system oscillator at 4 MHz, if it has an internal oscillator. Then, you can get pretty close to 0.1 sec ticks with TMR1 or use another oscillator for 32,768 Hz. The op's new code talks about micoseconds. His original post needed 100-ms intervals:
    I don't have clue as to why he seems to want 2 us intervals
    Code (MPASM):

    movlw LOW Preset ; 0.2 us
    movwf TMR1L ;Preset counter to set division value 0.2 us
    movlw HIGH Preset ; 0.2 us
    movwf TMR1H ; 0.2 us
     
    What is the literal (i.e., "Preset") in WREG? We seem to be getting only fragments of his code despite my request that he post his entire revisions. With a clock frequency of 4 MHz, it seems "unlikely" that any "Preset" would give a 2 us 0.2us "tick."

    Of course, 0.1 second intervals for 10 minutes = 6000 datapoints (0x1770). He does not seem to have addressed how that number will be stored.

    So, I am a bit lost in where he is headed but take solice in this:
    John

    Fixed typo, changed 2 us to 0.2
     
    Last edited: Jun 26, 2017
  18. Logjkos

    Logjkos New Member

    Joined:
    Jun 22, 2017
    Messages:
    9
    Likes:
    0
    Hi

    Thank you for your feedback, we have had very little if any programming support from any of the three lecturers that we have had throughout the year, and everyone on the course had no prior programming experience, it has been a bit of a let down to put it mildly.

    The use of the 4MHz oscillator sounds perfectly reasonable now that someone has explained it to me why the 4MHZ oscillator is prefereable, I did ask this question earlier but no one had replied to it.

    As for the PIC Microchip that we are to use we have not been told which one to use, it is upto us to decide which one we want to use.

    As for code I have as yet only got what I have already posted, i.e. practically nothing.

    The section of code with the 0.2 uS is simply a copy and paste of that section of code that Les had posted earlier, not code that I have created, I still intend to have a timer incrementing 0.1 S.

    What I would have liked to have seen in our first assignment is a complete program, that:
    Is uncomented
    Is undocumented
    Contains bugs

    We could then go away, learn how to use MPLAB to compile and run the software (this has not been covered in lectures/class so I m unsure how to do this).
    Research each of the bugs and fix them (we could have gained a better understanding of test procedures and methods)
    Research the lines of code to comment them (learn about code in a practical way, better than simply talking about TRISA and B)
    Theis would then allow us to document the software.

    This however was not the case, c'est la vie.

    Once again thanks in advance for your help.
     
  19. Pommie

    Pommie Well-Known Member Most Helpful Member

    Joined:
    Mar 18, 2005
    Messages:
    10,083
    Likes:
    326
    Location:
    Brisbane Australia
    I'll add a little about clock selection. In your original post you stated you needed an accuracy of 0.1 seconds in 10 minutes. That is an accuracy of 1 in 6000 - the internal oscillator is only accurate to 1 in 100 - looks like you need a crystal.

    As for timing, I would avoid interrupts due to your lack of experience.

    My approach would be,
    Assuming mid range chip - 16F628 with a 4MHz crystal as shown in the datasheet. Crystal stuff on page 97.
    I would use timer 2 as this is nice and simple. Timer 2 gets clocked a 1/4 of the crystal speed so at 1MHz.
    It has a prescaler to divide that clock - I suggest setting it to 4. Clock now at 250kHz.
    It has a period register (PR2) which resets it at a predetermined count. Setting this to 249 will reset it every 250 counts - we include zero in the count. Timer two now gets reset every 1000 cycles = 1mS.
    Counting every mS is a little fast - luckily timer 2 has a postscaler - set that to 10 and we are counting 100th of a second.
    Checking the datasheet, we need the following setup,

    T2CON = 0b01001101 - see datasheet page 53 - 55 in pdf.
    PR2=249

    Now, timer 2 will run along quiet happy and everytime it resets it will set a bit called TMR2IF (bit 1 of PIR1).
    You can test this bit and when it's set, increment a counter, clear the bit and wait for it to be set again.

    See, two register to set and you have your basic timer.

    Good luck.

    Mike.
     
  20. Les Jones

    Les Jones Well-Known Member

    Joined:
    May 15, 2015
    Messages:
    1,451
    Likes:
    189
    Location:
    Lancashire UK
    Hi jpanhalt,
    I think the confusion is because I posted a complete program for a tachometer in post #10. I was just using the initialisaton of the timer module and the end of the interrupt routine as an example of how to generate timed interupts. The 16 bit constant "Preset" is defined at the start of the code (Post #10) The comments containing the 0.2 uS (Instruction time with the 20 Mhz crystal I was using.) were put in when I was writing the program for working out the time taken to load the preset value and restart the timer. In my next post I will answer Logjkos's question from post #14 . This should remove the confusion.

    Les.
     
  21. Les Jones

    Les Jones Well-Known Member

    Joined:
    May 15, 2015
    Messages:
    1,451
    Likes:
    189
    Location:
    Lancashire UK
    Hi Logjkos,
    You have already done most of the calculation requred in post #6 You worked out that with your 31 Khz clock frequency that you needed 775 instruction cycles fot 0.1 seconds. (I agree with this.) As in the timer interrupt code there are 7 instructions between the interrupt occuring and the counter being restarted we only now need to count 775 - 7 = 768 instruction cycles. So as the 16 bit counter will overflow at a count 0f 65536 so it need to be preset with 65536 - 768 = 64768 (0xFD00 HEX) The code will become.
    Code (text):


    Timer_interrupt:
    ;               Timer interupt handler
    ;               Should come here every 100 ms
    Timer_Int
       bcf   INTCON,GIE       ;Disable interrupts               129 uS
       bcf   T1CON,0           ;Stop timer                   129 uS
       movlw   0x00           ;                       129 uS
       movwf   TMR1L           ;Preset counter to set division value       129 uS
       movlw   0xFD           ;                       129 uS
       movwf   TMR1H           ;                       129 uS
       bsf   T1CON,0           ;Start timer                   129 uS (7 cpu cycles)
       bcf   PIR1,TMR1IF       ;Clear timer 1 interupt flag
    ;
    ;       Enter your code here to increment the 0.1 second counter
    ;
    ;
    ;
       bsf   INTCON,GIE       ;Enable interrupts
       retfie

     
    I have not used the constsnt "Preset" instead I have loaded the hex values directly. As an exercise to your understanding you could try to modify this bit of code for use with a 4 Mhz clock frequency. (Which is a much better choice. I thought that you had been forced to us a 31 Khz clock to make it more of a challenge.)
    What you program is required to do is very simialr the the tachometer example I posted. The only difference is the the tachometer program counts input pulses for a defined time. Your program counts timing pulses between two events. (The start and end of the opperation.) Other parts of the tachometer code could be used as example for displaying the result on a multiplexed 7 segment display. Doing the counting in decimal (Rather than binary and then converting to decimal.) The tachometer uses a 7447N IC to convert the BCD to the signals to drive the 7 segment displays. This function could be done with a lookup table in the code to save the use of this IC.

    Les.
     

Share This Page