My incrementer increments only once ...

Hi folks,
I'm new here. I read a lot of interesting posts, but it's the first time I post.

I'm currently writing a code, which goal is to run a list of instruction one by one in the background while another programm is running in the "loop".
Currently only one instruction is coded "Txxxx", where "T" stands for Timing, and "xxxx" for "minutes and seconds". It decounts every second and writes it to Serial. when it reaches 0, it stops and move to the next instruction. The aim of the timer is to check if the instruction is done (in this case the time but it could be some other function). I will add an instruction decoder and each instruction will have its callback function.

The programm is a s follow :

  1. attach an interrupt to the Timer1
  2. each callback check if it's finished or decounts one second
  3. when its finished dettach the innterrupt
  4. move to next instruction "curCmd++"

The problem is "curCmd++" increments only once:
It perfoms Instruction 0, then Instruction 1 and then 1 again... and again... and again...

Any ideas ???

And here is the code :

#include <TimerOne.h>
#include <avr/pgmspace.h>

// this is a list of instructions to do
// T stands for "Time" then 2digits for minutes
// and 2 digits for seconds
#define MY_INSTR_LENGTH  6
prog_char cmd_0[] PROGMEM = "T0002";
prog_char cmd_1[] PROGMEM = "T0004";
prog_char cmd_2[] PROGMEM = "T0006";
prog_char cmd_3[] PROGMEM = "T0008";
prog_char cmd_4[] PROGMEM = "T0010";
prog_char cmd_5[] PROGMEM = "T0100";

char cmd[] = {
  0,0,0,0,0}; // This is the instruction buffer
int curCmd = 0; // this is the current instruction to read

// Then set up a table to refer to your strings.
PROGMEM const char *cmd_table[] = 	   // change "string_table" name to suit
{ 
  cmd_0,
  cmd_1,
  cmd_2,
  cmd_3,
  cmd_4,
  cmd_5 };

void setup(){
  Timer1.initialize(1000000); // initialize timer1 to 1 sec
  Serial.begin(9600);         // init Serial
  nextStep();                 // read next instruction (currently 0)
  curCmd++;                   // increment to next instruction
}

void loop(){
}

int remTime = 0; // remainig time to decount

void remTimeDecount(){
  Serial.print(remTime/60); //display minutes
  Serial.print(":");
  Serial.println(remTime%60);    //display seconds
  if(remTime-- <= 0){            //if 0 or less the timer has finished  
    Serial.println(remTime);     //display remaining time (-1 means finished)
    Timer1.detachInterrupt();    // no more need for the interrupt. stop the decounter
    nextStep();                  // read next instruction (this has to be incremented now)
    curCmd++;                    // increment to next instruction
  }
}

void nextStep(){
  if(curCmd < MY_INSTR_LENGTH){ // check if there are some any more instructions to perform
    Serial.print("Command ");
    Serial.println(curCmd);
    strcpy_P(cmd, (char*)pgm_read_word(&(cmd_table[curCmd]))); // get the instruction in the Progmem
    if(cmd[0] == 'T'){ // This "if" section will be replaced by a instruction decoder
      remTime = (cmd[1]-48)*600+(cmd[2]-48)*60+(cmd[3]-48)*10+(cmd[4]-48); // set the decounter
      Timer1.attachInterrupt(remTimeDecount); // attach interrupt to start the decounter
    }
  }
  else
  {
    Serial.println("The end !!");
  }
}

Why do you keep detaching and reattaching the interrupt handlers?

Why are you doing slow Serial.print()s in what is supposed to be a very fast interrupt handler?

This was a nice tricky one! thank you!

When you have a string in C++, it adds an invisible 0 to the end, so that it can easily determine where the string ends. So what happens is that when you copy the string into cmd, it copies 6 bytes, instead of just 5. Because cmd is 5 long, and curCmd is declared right after cmd, curCmd happens to end up in the next memory space. So when you copy 6 bytes, it copies a zero into the memory that is allocated to curCmd!

Fortunately the fix is easy, delcare your Cmd array with one extra byte:

char cmd[] = {
  0,0,0,0,0,0}; // This is the instruction buffer

Why do you keep detaching and reattaching the interrupt handlers?

I just coded one function wich is countdown for xxminutes. But there will be others, for exemple to wait until a condition is met and update some variable.
The purpose is being able to run the main program in the loop (In may case it will be a PID) and the updates in the interrupt (for example to change the setpoint or to program a pause).
In this case detaching and reattaching the interruption handler is useless but in the end I will dettach the handler of the decounter for exemple and then attach the handler of "go to that setpoint and wait till it's reach" and so on. Like a little OS ... in order to be able to change the heating profiles without recoding the whole program, just the lines "cmd_0 to cmd_x".

Certainly not the best method but it seemed logical to me but maybe it isn't ;D

Why are you doing slow Serial.print()s in what is supposed to be a very fast interrupt handler?

For debuging purpose only ...

Thx Trex ! That was great!

I don't think, I could find it by my own ...

I tried several positions for the increment "curCmd++", but I didn't even think about searching the way you did.

Thanks again

Chokotoff:

Why are you doing slow Serial.print()s in what is supposed to be a very fast interrupt handler?

For debuging purpose only ...

I would pay attention to PaulS. Soon you will be debugging why it is hanging, and that is because of the "debugging" code in the interrupt handler.

Can it really become that slow ?

Yes. Serial comms are slooooooooooooooow

I really think you need a restructure. I don't like the way the interrupt routine calls another function which starts the timer again. But anyway.

I've restructured a bit so you only add 1 to curCmd in one place. This now keeps incrementing:

#include <TimerOne.h>
#include <avr/pgmspace.h>

// this is a list of instructions to do
// T stands for "Time" then 2digits for minutes
// and 2 digits for seconds
#define MY_INSTR_LENGTH  6
prog_char cmd_0[] PROGMEM = "T0002";
prog_char cmd_1[] PROGMEM = "T0004";
prog_char cmd_2[] PROGMEM = "T0006";
prog_char cmd_3[] PROGMEM = "T0008";
prog_char cmd_4[] PROGMEM = "T0010";
prog_char cmd_5[] PROGMEM = "T0100";

char cmd[MY_INSTR_LENGTH]; // This is the instruction buffer
volatile int curCmd = 0; // this is the current instruction to read

// Then set up a table to refer to your strings.
PROGMEM const char *cmd_table[] = 	   // change "string_table" name to suit
{ 
  cmd_0,
  cmd_1,
  cmd_2,
  cmd_3,
  cmd_4,
  cmd_5 };

void setup(){
  Timer1.initialize(1000000); // initialize timer1 to 1 sec
  Serial.begin(9600);         // init Serial
  nextStep();                 // read next instruction (currently 0)
}

void loop(){
}

int remTime = 0; // remainig time to decount

void remTimeDecount(){
  Serial.print(remTime/60); //display minutes
  Serial.print(":");
  Serial.println(remTime%60);    //display seconds
  if(remTime-- <= 0){            //if 0 or less the timer has finished  
    Serial.println(remTime);     //display remaining time (-1 means finished)
    Timer1.detachInterrupt();    // no more need for the interrupt. stop the decounter
    nextStep();                  // read next instruction (this has to be incremented now)
  }
}

void nextStep(){
  if(curCmd < MY_INSTR_LENGTH){ // check if there are some any more instructions to perform
    Serial.print("Command ");
    Serial.println(curCmd);
    strcpy_P(cmd, (char*)pgm_read_word(&(cmd_table[curCmd]))); // get the instruction in the Progmem
    Serial.print("cmd: ");
    Serial.println (cmd);
    delay (100);
    if(cmd[0] == 'T'){ // This "if" section will be replaced by a instruction decoder
      remTime = (cmd[1]-48)*600+(cmd[2]-48)*60+(cmd[3]-48)*10+(cmd[4]-48); // set the decounter
      Timer1.attachInterrupt(remTimeDecount); // attach interrupt to start the decounter
    }
    curCmd++;
  }
  else
  {
    Serial.println("The end !!");
  }
}