0

I don't know why but since yesterday, my Arduino sketch returns weird data. I've check eaches inputs and the returns values are ok.

But that line:

sprintf(read, "%d;%d;%d;%d;%d;%d;%d;%d\r", x, analogRead(HD), analogRead(HG), analogRead(CD), analogRead(CG), 0, 0, analogRead(ECG));

returns something like this:

3000;0;110;291;263;230;0;0 (It's like the analog reads are shift from 1 position to the right)

It's suppose to return something like this:

3000;110;291;263;230;0;0;245

Here is my sketch:

int HD = A0;
int HG = A1;
int CD = A2;
int CG = A3;
int ECG = A5;

volatile boolean interruptFlag = 0;
char read[45];
char signal[2048];
volatile int count = 0;
volatile long x = 0;

void setup() {
  Serial.begin(9600);   

  noInterrupts(); // Stop interrupts.

  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 50Hz increments.
  OCR1A = 39999; // = 16000000 / (8 * 50) - 1 (must be <65536)

  // Turn on CTC mode.
  TCCR1B |= (1 << WGM12);
  // Set CS12, CS11 and CS10 bits for 64 prescaler.
  TCCR1B |= (0 << CS12) | (1 << CS11) | (1 << CS10);
  // Enable timer compare interrupt.
  TIMSK1 |= (1 << OCIE1A);

  interrupts(); // Allow interrupts.  
}

ISR(TIMER1_COMPA_vect){    
  if (!interruptFlag){  
    interruptFlag = 1;    
  }  
}

void loop() {
  if (interruptFlag){    
    writeAnalogSignals();
    count++; 
    interruptFlag = 0;     
  }     
}

void writeAnalogSignals() { 
  if (strlen(read) == 0) {
    sprintf(read, "%d;%d;%d;%d;%d;%d;%d;%d\r", x, analogRead(HD), analogRead(HG), analogRead(CD), analogRead(CG), 0, 0, analogRead(ECG));
  } else {
    sprintf(read, "|%d;%d;%d;%d;%d;%d;%d;%d\r", x, analogRead(HD), analogRead(HG), analogRead(CD), analogRead(CG), 0, 0, analogRead(ECG));
  }
  strcat(signal, read);

  x += 2;  

  if (count >= 50) {
    Serial.print(signal);
    signal[0] = 0;
    count = 0;    
  }  
}
8
  • Why are you even using sprintf? What's wrong with just printing the values direct to serial?
    – Majenko
    Jan 24, 2017 at 14:52
  • I was just using sprintf to format data instead of using concat or «+», it seems more efficient to me. But hey, I'm open to improvement. My C is far far beyond me! Is this a best practice to do multiple acquisitions before sending it on the Serial or I can send it on each iteration? Jan 24, 2017 at 14:59
  • Serial is way slower than your acquisition. It depends if you want a block of data followed by a delay while it sends, or a smooth sending of values over time. Either way using strings to store the data isn't good - it's a huge waste.
    – Majenko
    Jan 24, 2017 at 15:01
  • 1
    An array of ints if you really must store it. However, unless you have a requirement to do a block of high speed sampling followed by sending then don't bother storing - just write the values out as you sample them. You're not making the sending any faster by storing them, and that is by far the slowest operation.
    – Majenko
    Jan 24, 2017 at 15:08
  • 1
    As mentioned by @jot your x is 4 bytes but sprintf expects it to be 2 bytes because you used %d in the format string. If you want to keep x as a long, then replace the first %d with %ld and that should fix it; otherwise declar x as int. Please accept @jot answer if that fixes your problem.
    – jfpoilpret
    Jan 28, 2017 at 13:37

1 Answer 1

2

Sometimes the sprintf can be used instead of 20 lines of code. In this case an array with integers and a loop with Serial.print would be better as Majenko already wrote.

When you do use the sprintf, a shift in the data means that one of the parameters has too many or too little bytes. The sprintf does not know the size of the parameter and the parameter will not be converted to a different type. When you use "%d", you have to put two bytes on the stack. Since your 'x' is 4 bytes, all those 4 bytes will be put onto the stack. The first "%d" reads two bytes of 'x' and the second "%d" read the other two bytes of 'x'. That is why it is shifted.

For a data rate of 50Hz, I suggest to raise the baudrate to 115200.

Using millis() for the 50Hz will result into the same timing accuracy as you have now. You don't need the timer and you don't need the interrupt. See the BlinkWithouDelay example and use 20ms as an interval.

2
  • Thanks @Jot. In my first implementations, I used delay().The use of interrupt came off along the way while I tried to optimize my code. I will try another baud rate. Jan 24, 2017 at 18:39
  • Ok, performance is much better at 115200 bauds! Jan 24, 2017 at 18:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.