Using multiplexer and timer-interrupt

Hello,

I am trying to cycle through and print values of a multiplexer to the serial monitor. However, I need to go through all the values at a certain frequency, so I need to use timer1 and an interrupt verify the sampling frequency.

I am using a Pro Mini 328 8MHz. I have tested the timer-interrupt code with LEDs and other components, so I know I have that part working. However, when I put in the multiplexer code, the arduino outputs nothing. The multiplexer code is sound as well; when put into the loop(), it works perfectly. But whenever I mix it with the timer and interrupt code, things go all wrong.

By the way, we are using this multiplexer, if it changes anything: SparkFun Analog/Digital MUX Breakout - CD74HC4067 - BOB-09056 - SparkFun Electronics

Here is the code that outputs nothing:

int x, y, z;
//Mux control pins
int s0 = 13;
int s1 = 12;
int s2 = 11;
int s3 = 10;
int SIG_pin = 0;

int controlPin[] = {s0, s1, s2, s3};
int muxChannel[16][4]={
    {0,0,0,0}, //channel 0
    {1,0,0,0}, //channel 1
    {0,1,0,0}, //channel 2
    {1,1,0,0}, //channel 3
    {0,0,1,0}, //channel 4
    {1,0,1,0}, //channel 5
    {0,1,1,0}, //channel 6
    {1,1,1,0}, //channel 7
    {0,0,0,1}, //channel 8
    {1,0,0,1}, //channel 9
    {0,1,0,1}, //channel 10
    {1,1,0,1}, //channel 11
    {0,0,1,1}, //channel 12
    {1,0,1,1}, //channel 13
    {0,1,1,1}, //channel 14
    {1,1,1,1}  //channel 15
  };


void setup()
{
  Serial.begin(9600);
  pinMode(s0, OUTPUT); 
  pinMode(s1, OUTPUT); 
  pinMode(s2, OUTPUT); 
  pinMode(s3, OUTPUT); 
  digitalWrite(s0, LOW);
  digitalWrite(s1, LOW);
  digitalWrite(s2, LOW);
  digitalWrite(s3, LOW);

cli(); //stop interrupts

//set timer1 interrupt at 10Hz
  TCCR1A = 0; // set entire TCCR1A register to 0
  TCCR1B = 0; // same for TCCR1B
  TCNT1  = 0; //initialize counter value to 0
  // set compare match register for 10hz increments
  OCR1A = 780;//
  // turn on CTC mode
  TCCR1B |= (1 << WGM12);
  // Set CS12 and CS10 bits for 1024 prescaler
  TCCR1B |= (1 << CS12) | (1 << CS10);  
  // enable timer compare interrupt
  TIMSK1 |= (1 << OCIE1A);

sei();//allow interrupts

}


ISR(TIMER1_COMPA_vect)
{  
    // Loop through and read all 16 values
    // Reports back Value at channel 6 is: [value]
    for(int i = 0; i < 16; i++){
        for(int j = 0; j < 4; j ++){
            digitalWrite(controlPin[j], muxChannel[i][j]);
         }
    Serial.print("Value at channel ");
    Serial.print(i);
    Serial.print("is : ");
    Serial.println(analogRead(SIG_pin));
    }

}

void loop()
{
  }

Does anyone know what is going on?

Hello,

malwilley:
However, I need to go through all the values at a certain frequency, so I need to use timer1 and an interrupt verify the sampling frequency.

Why do you need to use an interrupt?

We have code that samples from multiple components. If we put all the code into the loop, we don't for sure how long the entire process will take, so we thought that using timers and interrupts would be the easiest way to do this.

malwilley:
We have code that samples from multiple components.

Uh huh. Nothing to do with interrupts.

If we put all the code into the loop, we don't for sure how long the entire process will take...

So?

...so we thought that using timers and interrupts would be the easiest way to do this.

"Easy" and "interrupts" are never appropriate in the same sentence.

A number of things:

  • You use 9600 baud, way to slow
  • You should not be doing serial inside a isr

This works

int x, y, z;
//Mux control pins
const int SIG_pin = 0;
const int s0 = 13;
const int s1 = 12;
const int s2 = 11;
const int s3 = 10;
volatile boolean signal;
int store[16];


void setup()
{
  Serial.begin(115200);
  pinMode(s0, OUTPUT); 
  pinMode(s1, OUTPUT); 
  pinMode(s2, OUTPUT); 
  pinMode(s3, OUTPUT); 
  digitalWrite(s0, LOW);
  digitalWrite(s1, LOW);
  digitalWrite(s2, LOW);
  digitalWrite(s3, LOW);

  cli(); //stop interrupts
  //set timer1 interrupt at 10Hz
  TCCR1A = 0; // set entire TCCR1A register to 0
  TCCR1B = 0; // same for TCCR1B
  TCNT1  = 0; //initialize counter value to 0
  // set compare match register for 10hz increments
  OCR1A = 780;//
  // turn on CTC mode
  TCCR1B |= (1 << WGM12);
  // Set CS12 and CS10 bits for 1024 prescaler
  TCCR1B |= (1 << CS12) | (1 << CS10);  
  // enable timer compare interrupt
  TIMSK1 |= (1 << OCIE1A);
  sei();//allow interrupts
}//setup()


ISR(TIMER1_COMPA_vect){  
  // Loop through and read all 16 values
  // Reports back Value at channel 6 is: [value]
  for(int i = 0; i < 16; i++){
    digitalWrite(s0, i&1);
    digitalWrite(s1, i&2);
    digitalWrite(s2, i&4);
    digitalWrite(s3, i&8);
    store[i] = analogRead(SIG_pin);
    signal = true;
  }
}//ISR(TIMER1_COMPA_vect)

void loop(){
  if(signal){
    for(int i = 0; i < 16; i++){
      Serial.print(store[i]);
      Serial.print('\t');
    }//for(i)
    signal = false;
    Serial.println();
  }
}//loop()

nilton61:
This works

But is not reliable. Your code has two race conditions.

ISR(TIMER1_COMPA_vect)
{  
    // Loop through and read all 16 values
    // Reports back Value at channel 6 is: [value]
    for(int i = 0; i < 16; i++){
        for(int j = 0; j < 4; j ++){
            digitalWrite(controlPin[j], muxChannel[i][j]);
         }
    Serial.print("Value at channel ");
    Serial.print(i);
    Serial.print("is : ");
    Serial.println(analogRead(SIG_pin));
    }
}

http://www.gammon.com.au/forum/?id=12153#trap4

    store[i] = analogRead(SIG_pin);

store should be declared volatile.