+ Post New Thread
Results 1 to 13 of 13
  1. #1
    Newbie level 4
    Points: 34, Level: 1

    Join Date
    Nov 2019
    Posts
    5
    Helped
    0 / 0
    Points
    34
    Level
    1

    PIC16F1934 Timer0 and some other stuff

    Hello folks,

    Being bored with databases and data warehouses I decided to poke around in an area I always liked.

    picked up a starter pickit3 with the up mentioned MCU, quickly blinked a LED, then decided I really enjoy this whole stuff and started digging deeper. I am having some difficulties however controlling the blinking LED with a Timer interrupt. I came across https://www.edaboard.com/showthread....-sec-interrupt

    First and foremost that formula calculating what value should I assign to the TMR0 bit saved my bacon and created some questions.

    I came up with the following code

    Code:
    #include 
    #define _XTAL_FREQ 20000000 //Specify the XTAL crystall FREQ
    #pragma config FOSC = INTOSC // Configure PIC to use internal oscilator
    
    int count = 0;
    void timer_isr()
    {  
        if(TMR0IF == 1) { // TMR0 overflowed
        TMR0IF = 0;       // Clear timer interrupt flag
        TMR0 = 0;     //This value represents the in ms that will last the interrupt.
        count++;      // stores how many interrupts occurred for instance if you need 30 ms seconds interrupt
                      // TMR0IF has to 
        }
        if (count == 211)
        {
            PORTAbits.RA0 = 1; // LED on
            count=0;
        }
    }
    
    /***** MAIN PROGRAM *****/
    
    void main()
    {
        OSCCONbits.IRCF0 = 0; // 8 MHz oscilator config
        OSCCONbits.IRCF1 = 1; // 8 MHz oscilator config
        OSCCONbits.IRCF2 = 1; // 8 MHz oscilator config
        OSCCONbits.IRCF3 = 1; // 8 MHz oscilator config
        
        /** TIMER0 setup **/
        
        OPTION_REGbits.TMR0CS = 0; // 8bit Timer mode selected
        OPTION_REGbits.TMR0SE = 0; // Setting low2high edge
        OPTION_REGbits.PSA = 0; // Select prescaler
        OPTION_REGbits.PS0 = 1; // Setting prescaler Rate
        OPTION_REGbits.PS1 = 1; // Setting prescaler Rate
        OPTION_REGbits.PS2 = 0; // Setting prescaler Rate
        
        
        INTCONbits.TMR0IE = 1;       //Enable timer interrupt bit in PIE1 register
        INTCONbits.GIE=1;          //Enable Global Interrupt
        INTCONbits.PEIE=1;        // Emable peripherial Interrupt
        
        TRISA = 0; // Setting PORTA as an output.
        PORTAbits.RA0 = 0; //LED off
        //*** Main loop
        while(1)
        {                   
            timer_isr();
        }
    }
    first question would be do I correctly set up Timer0 ?

    Code:
     OPTION_REGbits.TMR0CS = 0; // 8bit Timer mode selected
     OPTION_REGbits.TMR0SE = 0; // Setting low2high edge
     OPTION_REGbits.PSA = 0; // Select prescaler
     OPTION_REGbits.PS0 = 1; // Setting prescaler Rate
     OPTION_REGbits.PS1 = 1; // Setting prescaler Rate
     OPTION_REGbits.PS2 = 1; // Setting prescaler Rate
    second question would be if my oscilator is properly set at 8 Mhz ? -> reason I chose 8 MHz is to have Timer0
    'work' at 2 Mhz, according the datasheet Timer0 uses Fosc / 4.

    I'd appreciate any comment if the settings bits are fine.

    Now to the real struggle based on the above mentioned thread configuring Timer0 shouldn't be that hard.

    First question, do I understand this correctly: the value assigned to TMR0 bit, is sort of representation of the cycles needed to reach certain time, the interrupt flag of the timer0 is set up when Timer0 performs enough cycles hitting the value in TMR0. knowing that the value in TMR0 represents lets say 5 ms ?

    Looking at my interrupt handling routing, I'd like to get half a second delay.

    Oscilator works at 4Mhz, the clock works at 1 Mhz with prescaller set to 1:128 - by the way I am still having huge difficulties understanding what is that prescaller for.

    So 1MHz is approx. 1 uSec, my timer should increment once every 1 usec

    Now I want 50ms delay or 0.05 seconds

    50ms/1uSec = 50000 cycles ? -> is that correct ?

    Now knowing Timer0 overflows at 0xFFFF, the value I have to assign to TMR0 is 0xFFFF-0xC350 = 3CAF or for normal people 15535 is that correct ?

    So if I put a variable to increment on every interrupt occurrence can I deduce that 2 interrupts should provide me 0.1 seconds delay, and 10 will provide me half a second ?

    This my function should light up the LED for half a second ?


    Code:
    void timer_isr()
    {  
        if(TMR0IF == 1) { // TMR0 overflowed
        TMR0IF = 0;       // Clear timer interrupt flag
        TMR0 = 15535;     //This value represents the in ms that will last the interrupt.
        count++;      // stores how many interrupts occurred for instance if you need 30 ms seconds interrupt
                      // TMR0IF has to 
        }
        if (count == 10)
        {
            PORTAbits.RA0 = 1; // LED on
            count=0;
        }
    }
    Thank you in advance to whoever decides to look into this, my ultimate goal is to build myself a robot (optionally to bring me beer) :D

    George

    •   AltAdvertisement

        
       

  2. #2
    Super Moderator
    Points: 29,883, Level: 42
    andre_teprom's Avatar
    Join Date
    Nov 2006
    Location
    Brazil
    Posts
    8,917
    Helped
    1130 / 1130
    Points
    29,883
    Level
    42
    Blog Entries
    9

    Re: PIC16F1934 Timer0 and some other stuff

    Once you are apparently using interruption with just one timer, checking the interrupt flag right after entering into interruption vector seems unnecessary, there it is supposed to be set as 'true' .

    Code:
    void timer_isr()
    {  
        if(TMR0IF == 1)
        ...

    Im obviously assuming you wanted to instantiate timer_isr() called form interruption itself, not called inside the endless loop form main():

    Code:
    void main()
    {
    ...
        while(1)
        {                   
            timer_isr();
    Another tip, did you check these timer settings with some of the online timer calculator available on the Web? In general it is my first attempt and only after I compare with datasheet:

    http://eng-serve.com/pic/pic_timer.html
    https://embedjournal.com/pic-timer-c...r-give-away-1/
    --------------------------------------------------------------------------------------------------
    Part of the world that you live in, You are the part that you're giving ( Renaissance )



  3. #3
    Super Moderator
    Points: 79,262, Level: 68
    Achievements:
    7 years registered
    Awards:
    Most Frequent Poster 3rd Helpful Member

    Join Date
    Apr 2014
    Posts
    16,084
    Helped
    3644 / 3644
    Points
    79,262
    Level
    68

    Re: PIC16F1934 Timer0 and some other stuff

    Hi,

    while(1)
    {
    timer_isr();
    }
    You donīt have to call the timer_isr. The timer_isr is automatically performed after every timer interrupt.


    Klaus

    Added:
    The prescaler is there to adjust timer_range and timer_resolution.

    If I got your description correctly: (code#1)
    F_OSC (8MHz / 125ns) --> divide by 4 (F_OSC/4) (2MHz, 500ns) --> prescaler "011" = divide by 16 (125kHz, 8us) each timer counter tick.
    If you want 500ms then you need 62500 clock ticks. So if you set the value to 65535-62500 the the ISR is performed after 500ms.
    (If it is automatically restarted then the ISR runs twice per second = once every 500ms)
    Now if you run a SW counter witin the ISR counting from 0 to 211. this means 212 x 500ms = 106 seconds. I donīt think this is what you want.

    **
    In the second code you used prescaler = "111" which is divide by 256

    Klaus
    Please donīt contact me via PM, because there is no time to respond to them. No friend requests. Thank you.



  4. #4
    Newbie level 4
    Points: 34, Level: 1

    Join Date
    Nov 2019
    Posts
    5
    Helped
    0 / 0
    Points
    34
    Level
    1

    Re: PIC16F1934 Timer0 and some other stuff

    Hello and thanks for spending time on this,

    Basically I am learning how to operate with this.

    I was not aware of this calculator, so I haven not tried it.

    If I omit the timer_isr() from the while loop, LED does not blink.

    KlausST, I was playing around with both the oscilator and the the prescaler, as for why there is an additional counter, I thought since timer0 is 8bit, I cannot get more than a quarter of a second delay, thus 2 interrupts should provide me this half a second, that is why I had that counter, with the help of that calculator, the function looks like this

    Code:
    void timer_isr()
    {  
        if(TMR0IF == 1){ // TMR0 overflowed
        TMR0IF = 0;       // Clear timer interrupt flag
        TMR0IE = 1;
        TMR0 = 0;     //This value represents the in ms that will last the interrupt.
        PORTAbits.RA0 = 0;
        }
    }
    I was looking for a clearly explained formula how to calculate the values at which to set the control bits and registers of the Timer0 :) I think I somehow got it, my ADC experiment will show if I understood it correctly or not.

    However I noticed in the example code they put TMR0 outside of the interrupt routine for additional setup (can someone explain that) ?

    Code:
    // code starts here...
    void main()
    {
    ....
    
    //Timer0 Registers Prescaler= 256 - TMR0 Preset = 0 - Freq = 30.52 Hz - Period = 0.032768 seconds
    OPTION_REG.T0CS = 0;  // bit 5  TMR0 Clock Source Select bit...0 = Internal Clock (CLKO) 1 = Transition on T0CKI pin
    OPTION_REG.T0SE = 0;  // bit 4 TMR0 Source Edge Select bit 0 = low/high 1 = high/low
    OPTION_REG.PSA = 0;   // bit 3  Prescaler Assignment bit...0 = Prescaler is assigned to the Timer0
    OPTION_REG.PS2 = 1;   // bits 2-0  PS2:PS0: Prescaler Rate Select bits
    OPTION_REG.PS1 = 1;
    OPTION_REG.PS0 = 1;
    TMR0 = 0;             // preset for timer register -----------------------------> why do they put this here >?
    
    
    // Interrupt Registers
      INTCON = 0;           // clear the interrpt control register
      INTCON.TMR0IE = 1;        // bit5 TMR0 Overflow Interrupt Enable bit...1 = Enables the TMR0 interrupt
      INTCON.TMR0IF = 0;        // bit2 clear timer 0 interrupt flag
      INTCON.GIE = 1;           // bit7 global interrupt enable
    
    
      while(1)  //endless loop
      {
      }
    }



  5. #5
    Super Moderator
    Points: 82,085, Level: 69
    Achievements:
    7 years registered
    Awards:
    2nd Helpful Member
    betwixt's Avatar
    Join Date
    Jul 2009
    Location
    Aberdyfi, West Wales, UK
    Posts
    13,461
    Helped
    4492 / 4492
    Points
    82,085
    Level
    69

    Re: PIC16F1934 Timer0 and some other stuff

    The missing link here is you are not utilizing the interrupt at all. The interrupt routine (ISR) is called automatically by the timer module, you don't have to read it or put it in your program loop. Think of it as a subroutine that gets magically called whenever something triggers it, in this case the timer reaching maximum value and rolling over back to zero.

    The process is:
    1. set up the timer prescaler so it counts at the rate you want, if necessary factor in to it that it might take several interrupts to create the delay you want to create. For example, if you want a one second delay it could be from 100 x 10mS interrupts or maybe 50 x 20mS interrupts.

    2. Load the number of remaining counts it takes for the timer to overflow. Remember it counts upwards so the value is 256 minus the required counts.

    3. Write an ISR (be careful of it's naming, it is a single pre-defined routine) in it you want to reload the value you worked out in step 2 so the timer repeats the same interval. If you are counting interrupts, add one to the count until it reaches the delay time you need then set a variable to say the delay period is finished. Then clear the count so it starts over again.

    4. Back in your main program loop, check the variable you set in step 3. If it isn't set, just carry on, if it is set it means the delay you wanted has finished so do whatever you have to do (toggle the LED for example) then reset the variable ready for the next time.

    Enable the timer interrupt just before your main program loop starts.

    Brian.
    PLEASE - no friends requests or private emails, I simply don't have time to reply to them all.
    It's better to share your questions and answers on Edaboard so we can all benefit from each others experiences.



  6. #6
    Super Moderator
    Points: 79,262, Level: 68
    Achievements:
    7 years registered
    Awards:
    Most Frequent Poster 3rd Helpful Member

    Join Date
    Apr 2014
    Posts
    16,084
    Helped
    3644 / 3644
    Points
    79,262
    Level
    68

    Re: PIC16F1934 Timer0 and some other stuff

    Hi,

    Iīm not experienced with PIC. But there are a lot of informations that donīt match.

    You say:
    Now knowing Timer0 overflows at 0xFFFF, the value I have to assign to TMR0 is 0xFFFF-0xC350 = 3CAF or for normal people 15535 is that correct ?
    So this canīt be correct.
    Now you say timer0 is an 8 bit counter (and it seems to be correct): Thus valid values are 0...255 or 0x00 ... 0xFF

    ***
    In the ISR of post#1:
    * in Main_init: You initialize RA0 =0
    * In the ISR you SET RA0.
    * but you never clear it afterwards. --> It canīt blink this way. You need to clear it. Or "toggle" it within the ISR

    ***
    You say
    TMR0 = 0; //This value represents the in ms that will last the interrupt.
    the comment is not correct. In the ISR you will always read tmr0 to be 0 (unless you insert a long delay in the ISR), because it just has overflown from 255 to 0 (and this overflow started the ISR)

    ***
    are you sure the timer restarts automatically? If not, try to restart it within the ISR.

    Klaus
    Please donīt contact me via PM, because there is no time to respond to them. No friend requests. Thank you.



    •   AltAdvertisement

        
       

  7. #7
    Super Moderator
    Points: 29,883, Level: 42
    andre_teprom's Avatar
    Join Date
    Nov 2006
    Location
    Brazil
    Posts
    8,917
    Helped
    1130 / 1130
    Points
    29,883
    Level
    42
    Blog Entries
    9

    Re: PIC16F1934 Timer0 and some other stuff

    Unless I overlooked something, you did not mention what compiler you are using. Most often an interrupt vector is defined preceeded with a '#' directive. The way you did, it was nothing else than declaring the ISR function handler, but not instantiating it as such, I mean, assigning to the compiler the task of calling the function itself whenever an interruption happens.
    --------------------------------------------------------------------------------------------------
    Part of the world that you live in, You are the part that you're giving ( Renaissance )



  8. #8
    Newbie level 4
    Points: 34, Level: 1

    Join Date
    Nov 2019
    Posts
    5
    Helped
    0 / 0
    Points
    34
    Level
    1

    Re: PIC16F1934 Timer0 and some other stuff

    betwixt,

    Only when you said it's a system routing called automatically I realized void interrupt() is what you were talking about, point taken.

    So as far as I understand the steps, there are 2 'steps' setting up the timer.

    first one is in the main body of the program, set the timer0 value, and second one is in the ISR to set the same value so you dont get a longer interval (or shorter) from the ISR.

    Question for you here, is there I way I can control how long the interrupt to last, for example I want to attach a Sharp IR distance sensor, if I want the analog2digital converter to operate in an interrupt I have to make sure that the interrupt is long enough so the IR is taking its measurements correct, can we control this or it is magic again ? :)

    I have reached this point:

    Code:
    #include 
    void __interrupt () my_isr_routine (void) {
    
      // Timer0 Interrupt - Freq = 318.88 Hz - Period = 0.003136 seconds
      if (INTCONbits.TMR0IF == 1) // timer 0 interrupt flag
      {
        PORTAbits.RA0 = 1;      // Toggle PORTB bit0 LED
        INTCONbits.TMR0IF = 0;         // clear the flag
        INTCONbits.TMR0IE = 1;         // reenable the interrupt
        TMR0 = 10;           // reset the timer preset count
      }
    }
    
    // code starts here...
    void main()
    {
      // setup portb to show the interrupts by blibking LEDs
      TRISA = 0x00;    // PORT is all output...to show the interrupts
      PORTA = 0;       // start with all outputs low
    
    //Timer0 Registers Prescaler= 32 - TMR0 Preset = 60 - Freq = 318.88 Hz - Period = 0.003136 seconds
    OPTION_REG.T0CS = 0;  // bit 5  TMR0 Clock Source Select bit...0 = Internal Clock (CLKO) 1 = Transition on T0CKI pin
    OPTION_REG.T0SE = 0;  // bit 4 TMR0 Source Edge Select bit 0 = low/high 1 = high/low
    OPTION_REG.PSA = 0;   // bit 3  Prescaler Assignment bit...0 = Prescaler is assigned to the Timer0
    OPTION_REG.PS2 = 1;   // bits 2-0  PS2:PS0: Prescaler Rate Select bits
    OPTION_REG.PS1 = 0;
    OPTION_REG.PS0 = 0;
    TMR0 = 60;             // preset for timer register
    
    // Interrupt Registers
      INTCON = 0;           // clear the interrpt control register
      INTCONbits.TMR0IE = 1;        // bit5 TMR0 Overflow Interrupt Enable bit...1 = Enables the TMR0 interrupt
      INTCONbits.TMR0IF = 0;        // bit2 clear timer 0 interrupt flag
      INTCONbits.GIE = 1;           // bit7 global interrupt enable
    
    
      while(1)  //endless loop
      {
      }
    }
    Now since I keep the LED off and only flash it in the ISR, I'd expect a lot of the time the LED to be off, here is what is actually happening, LED is on for nearly 3 seconds then a blink of an eye off stage then on again for nearly 3 second, what do I miss, frankly I expected exactly the opposite. Oscilator is at 8MHz ?

    KlausST, indeed only after I posted my initial comment I noticed I coppied from an old thread from the forum here the 16 bit timer while mine was only 8. As for the bits, in the main body I am setting low only the bit the LED is attached to in PORTAbitsRA0, and I am leaving it off, in the ISR I am setting that same bit to high, isn't this how it is done ?

    I'd rather use bits from the port than setting the whole port high ?

    As for the toggle, my idea is in the main body of the program the LED is off, upon interrupt, it is on then after interrupt 'gone' LED is off again.

    With the explanation of betwixt, I understood why do we set value to TMR0 - basically we want TMR0 to cycle up to that value.

    I do not know if the timer restarts automatically I thought setting up TMR0IF to low resets it no ?

    Andre, I am using MPLAB X v5.30, as for compiler I think XC8-cc(v2.10) - from properties of the main.c file.


    -George



  9. #9
    Super Moderator
    Points: 82,085, Level: 69
    Achievements:
    7 years registered
    Awards:
    2nd Helpful Member
    betwixt's Avatar
    Join Date
    Jul 2009
    Location
    Aberdyfi, West Wales, UK
    Posts
    13,461
    Helped
    4492 / 4492
    Points
    82,085
    Level
    69

    Re: PIC16F1934 Timer0 and some other stuff

    TMR0IF is a flag (a bit that signifies something happened) in the interrupt register, not the timer itself. The timer runs continuously, counting 0 -> 0xFF repeatedly as long as it is enabled.

    You should check the flag is set inside the ISR for the simple reason that the one ISR is used by all the interrupts so you need to establish the source of the interrupt, it could be from other peripherals.

    You shouldn't re-enable the interrupt inside the ISR because on PIC16 series processors the ISR is not re-entrant. That means you can't interrupt the ISR itself with a second one. However, before entering the ISR, the PIC hardware disables the GIE bit to prevent it trying and it re-enables it when it leaves the ISR. For normal use you don't have to re-enable it yourself. Note that the GIE stops interrupts being processed but it doesn't stop interrupts being noted. If an interrupt flag is set while you are inside an ISR it will be actioned as soon as the ISR exits. If interrupts have to be prioritized (in PICs that only have one interrupt level) you have to do it by arranging the order you check the interrupt flags inside the ISR code.

    A word of caution: for exactly the reason in the paragraph above, don't spend too long inside an ISR and the rules of programming say that anyone deliberately adding a delay in an ISR has to be taken out and shot. Remember there is only one interrupt flag for each peripheral so for example if your TMR0 interrupt was every 10mS and you added a 100mS delay inside the ISR it means you lose the next nine interrupts. Perhaps not disastrous in a timer application but imagine if the interrupts were created by an incoming data stream and most of the data was ignored.

    If you want to toggle a bit, for example the one driving your LED, there are two ways to do it:
    1. Read it, check it and if set then reset it, otherwise set it,
    2. XOR it with itself.

    Some PICs, I think yours is OK, have a potential problem with "RMW" (Read, Modify, Write) so it is considered bad practice to do that. It is a problem that can occur when you read the present state of a bit, change it then write it back. It is an electrical issue to do with residual voltage levels on the pin rather than the logic level it was last driven to but it can be a read headache to debug when it happens!

    Brian.
    PLEASE - no friends requests or private emails, I simply don't have time to reply to them all.
    It's better to share your questions and answers on Edaboard so we can all benefit from each others experiences.


    1 members found this post helpful.

  10. #10
    Super Moderator
    Points: 79,262, Level: 68
    Achievements:
    7 years registered
    Awards:
    Most Frequent Poster 3rd Helpful Member

    Join Date
    Apr 2014
    Posts
    16,084
    Helped
    3644 / 3644
    Points
    79,262
    Level
    68

    Re: PIC16F1934 Timer0 and some other stuff

    Hi,


    2. XOR it with itself.
    XOR with it self = switching OFF
    XOR with 1 = toggle

    ******
    As for the bits, in the main body I am setting low only the bit the LED is attached to in PORTAbitsRA0, and I am leaving it off, in the ISR I am setting that same bit to high, isn't this how it is done ?
    So far so good. But you want it to blink. Blink means: OFF - wait - ON - Wait ....repeatedly.
    But you do: OFF (init, main) - wait (timer) - ON (ISR) - wait (timer) - ON (ISR)- wait (timer) - ON (ISR)....
    It never is switched OFF

    Thus I recommend: OFF (init, main) - wait (timer) - TOGGLE (ISR) - wait (timer) - TOGGLE (ISR)- wait (timer) - TOGGLE (ISR)....

    *****
    As for the toggle, my idea is in the main body of the program the LED is off, upon interrupt, it is on then after interrupt 'gone' LED is off again.
    There is no "interrupt gone". The interrupt is a flag and it just makes the ISR to run. Once ... unless you donīt restart the timer.

    With the explanation of betwixt, I understood why do we set value to TMR0 - basically we want TMR0 to cycle up to that value.
    The "timer" is hardware, not software.
    When you do nothing... tmr0 is counting up from 0 to 255 then the interrupt flag is set and it starts again from 0.

    Letīs imagine the counter frequency is 1kHz. then it takes 1ms to count one step. 0 (1ms later) -> 1 (1ms later) -> 2 (1ms later) -> 3 (1ms later) -> 4 (1ms later) -> 5...
    So it takes 256 counts then an overflow happens .. and the ISR runs.
    Now letīs imagine you donīt want the ISR run every 256ms but every 5ms.
    Then:
    *Init: it to (256-5 =) 251
    * (1ms later) -> 252
    * (1ms later) -> 253
    * (1ms later) -> 254
    * (1ms later) -> 255
    * (1ms later) -> 0 --> ISR trigger. Within the ISR set it to (256-5)= 251
    * (1ms later) -> 252
    * (1ms later) -> 253
    * (1ms later) -> 254
    * (1ms later) -> 255
    * (1ms later) -> 0 --> ISR trigger. Within the ISR set it to (256-5)= 251
    * (1ms later) -> 252
    * (1ms later) -> 253
    * (1ms later) -> 254
    .. and so on

    I do not know if the timer restarts automatically I thought setting up TMR0IF to low resets it no ?
    TMR0IF is just the INTERRUPT-FLAG. For sure it needs to be cleared to enable a now trigger of the ISR. But it wonīt set the TMR0 to the desired value to get the desired delay. (251 in my example)

    Klaus
    Please donīt contact me via PM, because there is no time to respond to them. No friend requests. Thank you.


    1 members found this post helpful.

  11. #11
    Advanced Member level 4
    Points: 7,924, Level: 21

    Join Date
    Jan 2015
    Posts
    1,109
    Helped
    349 / 349
    Points
    7,924
    Level
    21

    Re: PIC16F1934 Timer0 and some other stuff

    Quote Originally Posted by KlausST View Post
    TMR0IF is just the INTERRUPT-FLAG. For sure it needs to be cleared to enable a now trigger of the ISR. But it wonīt set the TMR0 to the desired value to get the desired delay. (251 in my example)
    Just to be clear: with the IF bit set (and also the IE bit set of course) the ISR will be called. You *should* clear the IF flag in the ISR to make sure that the next time it is set by the hardware, the ISR will be called again.
    If you DON'T clear it i teh ISR, then as soon as the ISR exists, the hardware will check the IE and IF flags, find them both set and so call the ISR again immediately.
    Susan


    1 members found this post helpful.

  12. #12
    Newbie level 4
    Points: 34, Level: 1

    Join Date
    Nov 2019
    Posts
    5
    Helped
    0 / 0
    Points
    34
    Level
    1

    Re: PIC16F1934 Timer0 and some other stuff

    Quote Originally Posted by betwixt View Post

    You shouldn't re-enable the interrupt inside the ISR because on PIC16 series processors the ISR is not re-entrant. That means you can't interrupt the ISR itself with a second one. However, before entering the ISR, the PIC hardware disables the GIE bit to prevent it trying and it re-enables it when it leaves the ISR. For normal use you don't have to re-enable it yourself. Note that the GIE stops interrupts being processed but it doesn't stop interrupts being noted. If an interrupt flag is set while you are inside an ISR it will be actioned as soon as the ISR exits. If interrupts have to be prioritized (in PICs that only have one interrupt level) you have to do it by arranging the order you check the interrupt flags inside the ISR code.

    Brian.
    I decided for a long enough interrupt so my eye can actually see the LED toggled on/off, I do realize interrupts has to be lighting fast (that's the idea huh), and slowing down an interrupt loosing other interrupts is the culprit of a bad program thus bad programmer.

    I appreciate marking the specifics of TMR0IF. This is how my ISR looks now:

    Code:
    if (INTCONbits.TMR0IF == 1) // timer 0 interrupt flag
      {
        PORTAbits.RA0 = 1;  // ON PORTA bit0 LED 
        TMR0 = 60;           // reset the timer preset count
        INTCONbits.TMR0IF = 0;
      }
    KlausST,

    If I understand you right you imply here must be 1 more line either above or under line PORTAbits.RA0 = 1; putting that bit to 0 correct ?

    My initial design was the LED to turn on only during interrupt of Timer0.

    The way the code acts currently is LED is ON for quite some time (since I toggle on the LED only in the interrupt I presume interrupt takes THAT long), then a very short and barely noticeable pause (LED barely goes OFF), as if my interrupt length in time is huge. The period the LED is on is quite long and the off state of the LED is barely noticeable as if all the MCU is doing is interrupts... Is that the correct behavior ?

    Susan,

    the way you say it if I leave TMR0IF outside the ISR (clear it in the main code after IRS), I might never reach it because MCU will endup in an infinte loop servicing one and the same interrupt right ?

    My latest code, any advise on the TMR0 and the Oscilator setup, are they correctly set ?

    Code:
    #include 
    #define _XTAL_FREQ 20000000 //Specify the XTAL crystall FREQ
    #pragma config FOSC = INTOSC // Configure PIC to use internal oscilator
    void __interrupt () isr_routine (void) {
    
      // Timer0 Interrupt - Freq = 30.52 Hz - Period = 0.032768 seconds
      if (INTCONbits.TMR0IF == 1) // timer 0 interrupt flag
      {
        PORTAbits.RA0 = 1;  // ON PORTA bit0 LED 
        TMR0 = 100;           // reset the timer preset count
        INTCONbits.TMR0IF = 0;
      }
    }
    
    // code starts here...
    void main()
    {
         
    //  Oscilator set at 8 MHz oscilator config
     OSCCONbits.IRCF0 = 1; 
     OSCCONbits.IRCF1 = 1;  
     OSCCONbits.IRCF2 = 1; 
     OSCCONbits.IRCF3 = 0; 
     
    //Timer0 Registers Prescaler= 8 - TMR0 Preset = 100 - Freq = 1602.56 Hz - Period = 0.000624 seconds
    OPTION_REGbits.T0CS = 0;  // bit 5  TMR0 Clock Source Select bit...0 = Internal Clock (CLKO) 1 = Transition on T0CKI pin
    OPTION_REGbits.T0SE = 0;  // bit 4 TMR0 Source Edge Select bit 0 = low/high 1 = high/low
    OPTION_REGbits.PSA = 0;   // bit 3  Prescaler Assignment bit...0 = Prescaler is assigned to the Timer0
    OPTION_REGbits.PS2 = 0;   // bits 2-0  PS2:PS0: Prescaler Rate Select bits
    OPTION_REGbits.PS1 = 1;
    OPTION_REGbits.PS0 = 0;
    TMR0 = 100;             // preset for timer register
    
    
    // Interrupt Registers
      INTCON = 0;           // clear the interrpt control register
      INTCONbits.TMR0IE = 1;        // bit5 TMR0 Overflow Interrupt Enable bit...1 = Enables the TMR0 interrupt
      INTCONbits.TMR0IF = 0;        // bit2 clear timer 0 interrupt flag
      INTCONbits.GIE = 1;           // bit7 global interrupt enable 
    
      TRISA = 0x00;    // PORT is all output...to show the interrupts
      PORTAbits.RA0 = 0;       // start with all outputs low
      
      while(1)  //endless loop
      {
      }
    }
    With all the reading today I am reaching a state of mind where (thanks to your explanations) using timer interrupts would not be very useful flashing a LED, due to the fact interrupts are happening quite fast (configurable), and the interrupt length(in time) is quite short, thus actual observation of a LED being OFF, flash it ON for noticeable enough period is not something interrupts should be used for, am I right ?

    Tomorrow I plan poking around with a ADC, I hope I have more luck there

    - - - Updated - - -

    Quote Originally Posted by KlausST View Post
    Letīs imagine the counter frequency is 1kHz. then it takes 1ms to count one step. 0 (1ms later) -> 1 (1ms later) -> 2 (1ms later) -> 3 (1ms later) -> 4 (1ms later) -> 5...
    So it takes 256 counts then an overflow happens .. and the ISR runs.
    Now letīs imagine you donīt want the ISR run every 256ms but every 5ms.
    Then:
    *Init: it to (256-5 =) 251
    * (1ms later) -> 252
    * (1ms later) -> 253
    * (1ms later) -> 254
    * (1ms later) -> 255
    * (1ms later) -> 0 --> ISR trigger. Within the ISR set it to (256-5)= 251
    * (1ms later) -> 252
    * (1ms later) -> 253
    * (1ms later) -> 254
    * (1ms later) -> 255
    * (1ms later) -> 0 --> ISR trigger. Within the ISR set it to (256-5)= 251
    * (1ms later) -> 252
    * (1ms later) -> 253
    * (1ms later) -> 254
    .. and so on


    Klaus
    This is precisely what I don't get: Timer0 ticks once every 1ms, since Timer0 goes from 00 to FF or 0 to 255, when you reach FF(255) it will take 255ms (time) or 255 ticks - is this right ?

    How can I adjust a tick to takes place once every 5ms - I know it is hell slow but just asking?

    Your example is supreme, you are setting up the ISR to takes place every 5 ms (TMR0 = 251 and it ticks up until 256 and interrupt happens).

    btw I fully understood your post while I was writing this reply :D

    -George



    •   AltAdvertisement

        
       

  13. #13
    Super Moderator
    Points: 79,262, Level: 68
    Achievements:
    7 years registered
    Awards:
    Most Frequent Poster 3rd Helpful Member

    Join Date
    Apr 2014
    Posts
    16,084
    Helped
    3644 / 3644
    Points
    79,262
    Level
    68

    Re: PIC16F1934 Timer0 and some other stuff

    Hi.

    If I understand you right you imply here must be 1 more line either above or under line PORTAbits.RA0 = 1; putting that bit to 0 correct ?
    No. Definitely not.
    Apparently you misunderstand what "toggle" means.
    Toggle means
    * invert
    * in other words: when the LED previously was ON, then you switch it OFF and leave the ISR. When the LED previously was OFF, then you switch it ON and leave the ISR.

    ...but you don't switch it twice within one ISR.

    Read what I have written. You need to run the ISR twice. One for switching the LED ON, one for switching the LED OFF.

    Klaus
    Please donīt contact me via PM, because there is no time to respond to them. No friend requests. Thank you.



--[[ ]]--