This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

ISR Question (update)

Follow up to a previous thread posted last week.

The issue is that my timer interrupt won't work if serial interrupts are enabled, unless the timer interrupt priority is set to high.

As per Erik's request here is the source code:

CKCON = 0x08; /T2/12, T1/12, T0/4, MOVX Stretch 2

Serial Port setup:

void SetSerialPorts(void)
{

SCON0 = 0x50;
PCON |= 0x80;

SCON1 = 0x50;
EICON |= 0x80;

//Set Timer 1 for Baud Generation
TMOD |= 0x20;
TH1  = 0xF8;    //19.2k  Baud @ 29.4912 MHz
TR1  = 1;       //Run Timer 1

TI_0 = 1;
TI_1 = 1;
RI_0 = 0;
RI_1 = 0;

}

Timer2 Initialization:

void InitTimer2(void)
{

timer_flags = 0;
timer_tick_count = 0;

T2CON = 0x00;

RCAP2H = (TIMER_COUNT >> 8);
RCAP2L = (TIMER_COUNT & 0x00FF );

PT2 = 1;  //Have to set high so it will trigger
ET2 = 1;

}

Serial ISR:

void Serial_isr(void) interrupt 4
{


if ( RI_0 )
   RI_0 = 0;

if ( RI_1 )
{

   rx_buffer[ rx_write_cnt++ ] = SBUF1;
   if ( rx_write_cnt == MAXCOM ) rx_write_cnt = 0;

   RI_1 = 0;

} //__if (RI_1)__

}

Timer2 ISR:

void Timer2_isr(void) interrupt 5
{

T2CON = 0x00;

timer_tick_count++;

if ( timer_tick_count%10 == 0 )  //10Hz clock
   tmr_sample_adc = 1;

if ( timer_tick_count%20 == 0 )  //5Hz clock
   tmr_update = 1;

if ( timer_tick_count%100 == 0 ) //1Hz clock
{

   tmr_seconds = 1;
   timer_tick_count = 0;

}

TR2 = 1;

}

Can anyone figure out what I've done wrong from this? If you need me to post any other part of the code please let me know.

Thanks,
Paul

  • It was a long time since I had to develop with '51 chips, so I leave your problem for others to look into.

    But one thing about the timer ISR. The modulo operator can be quite expensive on a number of microcontrollers.

    It is often better to do:

    if (++count >= 10) {
        count = 0;
        event_flags = 1;
    }
    


    than doing:

    if (++count % 10 == 0) event_flag = 1;
    

    Another important thing is that your counter variable is 8, 16 or 32 bits large. This means that the total number of steps on the counter will not divide exactly with 10, 20 or 100. When timer_tick_count turns over, you will get a glitch in your three events. In your case, it may be harmless, but in situations where the hardware needs to reset between operations, the modulo operator could result in a system failure when the counter turns around.

  • Thanks for the input Per.

    For our purposes the timer doesn't need to be that precise.. just approximate values will do... but it's good to know for the future.

  • Try handling the TI flags in the interrupt. If on of them is set the interrupt will keep re triggering

  • As Neil Kurzman said,your program would stuck in the serial ISR because you have not parse the TI flag. It would generate interrupt as RI flag.

    Do a simulation to see whether it is the situation...

  • I handle the TI flag in another routine which uses Port 1 to interface to my RS485 network...

    void pwrite(char* c, int count)
    {
    
    // Enable port 1 for writing
       com_ctrl = 1;
    
    // Write data
       for ( i = 0; i < count; i++ )
       {
    
          SBUF1 = *c;
          while ( TI_1 == 0 );
    
          TI_1 = 0;
          c++;
    
       } //__for ( int i = 0; i < count; i++ )__
    
    // Enable port 1 for receiving
       com_ctrl = 0;
    
    }
    

    Is this sufficient or should I move the clearing of the flag into the serial ISR?

  • Is this sufficient or should I move the clearing of the flag into the serial ISR?

    The rule of thumb is:

    If you're doing interrupt-driven UART transfers, then handle the flags inside the ISR.

    If you're doing polled UART transfers, then handle the flags in the part of the program that does the polling.

    Mixing the two is usually equal to asking for trouble and debugging nightmares.

  • Mixing the two is usually equal to asking for trouble and debugging nightmares.

    Short addition: If one part of your UART handling (e.g. transmit) is interrupt-driven and the other one is polled, then handle both flags inside the ISR. Do not use the actual UART flag for the polled part, but use a bit flag (set in the ISR) that signals the polled part when it can use the UART.