Electronic – Software timers and interrupts on a microcontroller

interruptsmicrochipmicrocontrollersoftwaretimer

I have few questions on software timers and interrupts on a microcontroller. Just for information, I use a dsPIC33E microcontroller.

The final goal is to implement a serial communication protocol: RS485 with Modbus. I managed to transmit and receive a message, and now I have to do a message processing part.

Since I need a bunch of timers for all sorts of different tasks (e.g., 3.5 character delay needed for serial communication, some delay needed for buttons debouncing etc.), I plan to implement timers in a software using a single hardware timer. For example, hardware timer period is set to 100 us, and an interrupt is generated on every "overflow", i.e., every 100 us. In the ISR I just update global counters, which are basically software timers with a resolution of 100 us, whereas the hardware timer ISR has the highest priority. Is this a good way to do this, or is there some better way?

Each counter (i.e., a software timer) has defined its own period, and once the counter reaches its "period value", I want to call some function. Now it is not a very good idea to call this function from inside the hardware timer ISR, because that function will be processed with the highest priority since the calling routine is the hardware timer ISR. What I want is to define some function, let's say:

void Modbus_Protocol(void);

and to be able to define it as an interrupt, which will not be of the highest priority. Only the main hardware timer has the highest priority in this concept. In that way, once the counter in the hardware timer ISR reaches its period value, it wouldn't call its function, but it would rather just set a flag to trigger an interrupt (e.g., void Modbus_Protocol(void)), which will be triggered after the main ISR returns, depending on its priority. Can something like this be done, i.e., can I define software interrupts?

I know there is a possibility to use hardware interrupts which are not used, and to just set an interrupt flag from within the software. But I don't think this is an elegant way to implement interrupts if user defined software interrupts are possible.

Best Answer

You do not need special "software interrupts". Have a look at the following code. I neglected some technical stuff like variable declaration for clarity.

Use your ISR to just count some timer (tick). In the main() you are waiting to sync to this timer. Use a dedicated timer for each task you have to process. All these timers are incremented every ISR tick.

If the task timer expire, the dedicated task is processed. There are some special features in this kind of implementation. When you subtract the EXPITED-time from your timer instead setting it to be 0, your software is more robust if any of the tasks takes longer thenn 100µs. It's a kind of soft-realtime criteria.

You get a pseudo multi-tasking system.

isr() //100µs
{
    tick++;
}

main()
{    
  while(true)
  {
    while(tick == last_tick);
    last_tick = tick;

    modbus_timer++;
    task1_timer++;
    task2_timer++;

    if(modbus_timer >= MODEBUS_TIMER_EXPIRED)
    {
      modbus_timer -= MODEBUS_TIMER_EXPIRED;
      Modbus_Protocol();
    }

    if(task1_timer >= TASK1_TIMER_EXPIRED)
    {
      task1_timer -= TASK1_TIMER_EXPIRED;
      Task1();
    }

    if(task2_timer >= TASK2_TIMER_EXPIRED)
    {
      task2_timer -= TASK2_TIMER_EXPIRED;
      Task2();
    }
  }//forever-loop
}// main()