The byte lag?

Hey, i have a problem about converting byte to char. I tried to send 8 character and decode it using interrupt. The byte i decode works just fine, but when i convert it, it always receive the char only after i resend it :confused:

For example, i send <0 2 e>! but there's nothing on the Serial monitor. After i try to resend <0 2 e>! there is a <0 2 e>! But when i send another data, like <1 2 a>! the printed data is the <0 2 e>! that i've sent before.

This is the code:

byte lock=0;
int ya=1;
void baca(int sementara){
if (ya<9){
if ((sementara < 4700)&&(sementara > 4400)){
 ya=1;
 tambah=1;
 lock=0;
 //"header";

} else if ((sementara < 1800)&&(sementara > 1500)){
 lock=tambah+lock;
 tambah=tambah*2;
 ya++;
 //"byte 1"

  } else if ((sementara < 700)&&(sementara > 400)){
    tambah=tambah*2;
    ya++;
    //"byte 0"

    }else{
      //Serial.print("x");
      }
      

}else if (ya==9){
 if (l<8){
 isipesan[l]=char(lock);
 //Serial.print(isipesan[l]);
 l++;
 
if(l==8){
 String terima;
 for(int p=0;p<8;p++){
 terima=terima+isipesan[p];
 }
 Serial.print(terima);
 l=0;
 }
 ya=1;
 tambah=1;
 lock=0;
 }else{
  Serial.println("Error bit");
  }
}
}

You have to post all you code or at least a smaller but compilable version of it with the same problem. We are not Snippets R Us.

As of now, what you tell does not make sense.

From where do you send?
Why do you use an interrupt?
What conversion?
What are you actually trying to do? (See XY-problem)

post your full code...

I tried to decode IR Signal by reading the pulse length and convert the bit to char then to string before send it to the serial, and i'm try to convert the bit to the char from LSB to MSB

If i receive signal between 1500 and 1800 it means 1 and if between 400 and 700 it means 0.

The Tx code works fine since i checked using the oscilloscope.

Here's my full code on the Rx:

volatile int durasi;
volatile int prev_time;
volatile int data_simpan[255];
int l=0;
unsigned int lol;
int x=0;
byte tambah;
char isipesan[50];
void setup() {
Serial.begin(250000);
attachInterrupt(digitalPinToInterrupt(3), jatuh, RISING);
}

void loop() {
}

void jatuh() {
detachInterrupt(digitalPinToInterrupt(3));
prev_time=micros();
attachInterrupt(digitalPinToInterrupt(3),naik,FALLING);
}

void naik(){
detachInterrupt(digitalPinToInterrupt(3));
durasi=micros()-prev_time;
data_simpan[x]=durasi;
baca(data_simpan[x]);
x++;
attachInterrupt(digitalPinToInterrupt(3), jatuh, RISING);
}

byte lock=0;
int ya=1;
void baca(int sementara){
if (ya<9){
if ((sementara < 4700)&&(sementara > 4400)){
 ya=1;
 tambah=1;
 lock=0;
 //"header";

} else if ((sementara < 1800)&&(sementara > 1500)){
 lock=tambah+lock;
 tambah=tambah*2;
 ya++;
 //"Logic 1"
  } else if ((sementara < 700)&&(sementara > 400)){
    tambah=tambah*2;
    ya++;
    //"Logic 0"
    }else{
      Serial.print("x");
      }
      
}else if (ya==9){
 if (l<8){
 isipesan[l]=char(lock);
 l++;

 if(l==8){
 String terima;
 for(int p=0;p<8;p++){
 terima=terima+isipesan[p];
 }
 Serial.print(terima);
  l=0;
 }
 ya=1;
 tambah=1;
 lock=0;
 
 }else{
  Serial.println("Error bit");
  }
}
}

x probably would be better as a volatile

you should not call Serial.print in an interrupt

x probably would be better as a volatile

Yes and at some point, it should be reset to zero.

Press Ctrl+T in the IDE for fun, looks better doesn't it?

And why attach and detach the interrupt? Why not set it to CHANGE and just read the pin? Only if the signal is VERY fast that changes it.

micros() returns an unsigned long, so using a singed int is asking for trouble :wink:

volatile int data_simpan[255];

255 int's, hole crap, why do you need so much memory?

And worst, nothing is limiting x to a max of 254 so it will overflow data_simpan

And you should keep the interrupt SHORT and don't call Serial. So don't call Chewbacca baca in it. Set a flag you want to do that and do it in loop().

But what should the char contain? Just the value from the byte?

byte myByte = 0x12;
char mychar = myByte;

septillion:
And why attach and detach the interrupt? Why not set it to CHANGE and just read the pin? Only if the signal is VERY fast that changes it.

micros() returns an unsigned long, so using a singed int is asking for trouble :wink:

Thanks, i thought i detach the interrupt will protect the duration in this micros();?

durasi = micros() - prev_time;

septillion:
255 int's, hole crap, why do you need so much memory?

And worst, nothing is limiting x to a max of 254 so it will overflow data_simpan

And you should keep the interrupt SHORT and don't call Serial. So don't call Chewbacca baca in it. Set a flag you want to do that and do it in loop().

But what should the char contain? Just the value from the byte?

So it's better if i changed it to unsigned long?
I'm sorry but i don't get it what do you mean by set a flag, how can i put it in loop()? Can you give an example?

And yes just the value, like if the binary is 00001100 i'll save the '0' char to isipesan[p] and wait until 8 characters before convert it to string and send it to serial.

J-M-L:
x probably would be better as a volatile

you should not call Serial.print in an interrupt

As a volatile int? And when i need to change it to zero?

As a volatile int?

or byte given the size of your array

And when i need to change it to zero?

when you reach the end of the array (and if you use a byte (unsigned on 8 bits) then adding 1 to 255 automatically goes back to zero so you won't overflow your array

Thank you. But after i change it, it still print only the data that i sent before :confused:

Am i wrong at converting byte to char array? I tried this code too. But it still doesn't work.

//6 6 2017
//Data yang dikirim jadi batas id, diteruskan lewat serial
volatile unsigned long durasi;
volatile unsigned long prev_time;
volatile int data_simpan[25];
int l = 0;
int x, charke = 0;
//byte tambah;
byte bitArray[8];
byte byteArray[16];
byte chrmsk;
//int bitke;
int jum;
String terima;
void setup() {
  Serial.begin(250000);
  attachInterrupt(digitalPinToInterrupt(3), jatuh, RISING);
}

void loop() {
}

void jatuh() {
  detachInterrupt(digitalPinToInterrupt(3));
  prev_time = micros();
  attachInterrupt(digitalPinToInterrupt(3), naik, FALLING);
}

void naik() {
  detachInterrupt(digitalPinToInterrupt(3));
  durasi = micros() - prev_time;
  data_simpan[x] = durasi;
  baca(data_simpan[x]);
  if ( x < 25 ) {
    x++;
  } else {
    x = 0;
  }
  attachInterrupt(digitalPinToInterrupt(3), jatuh, RISING);
}

void baca(int sementara) {
  if ((sementara < 4700) && (sementara > 4400)) {
    jum = 0;
  } else if ((sementara < 1800) && (sementara > 1500)) {
    bitArray[jum] = 1;
    jum++;
    if (jum == 8) {
      terjemah();
      jum = 0;
    }
  } else if ((sementara < 700) && (sementara > 400)) {
    bitArray[jum] = 0;
    jum++;
    if (jum == 8) {
      terjemah();
      jum = 0;
    }
  } else {
    //Serial.print("x");
  }
}

void terjemah() {
  binertochar();
  if (charke < 8) {
    byteArray[charke] = chrmsk;
    charke++;
    if (charke == 7) {
      terima = String((char*)byteArray);
      Serial.println(terima);
    }
    if (charke == 8) {
      byteArray[7]=0;
      charke = 0;
    }
  }
  jum = 0;
  return;
}

void binertochar() {
  int  tambah = 1;
  chrmsk = 0;
  for (int i = 8; i > 0; i--) {
    if (bitArray[i - 1] == 1) {
      chrmsk = chrmsk + tambah;
    }
    tambah = tambah * 2;
  }
}

I tried this code because it put the convert outside the byte reading. But, this one just print the whole wrong character :confused:

No interrupt is called during an interrupt.

Just do it on the fly! If you see the end of a bit (aka, after a falling) just check the time. A simple if is quick. And based on that add a 0 or a 1 to a variable.

I can't really help you with that because I have no clue what ya, tambah and lock do... That just sounds ipsum lorum to me...

don't trust what you see when you print because during an interrupt you can't print..

septillion:
I can't really help you with that because I have no clue what ya, tambah and lock do... That just sounds ipsum lorum to me...

Ya is a counter, so i'll know when i get 8 bit. Lock is a zero for odd accumulator (bit 1) and tambah is for multiplying/even accumulator.

For example if i receive 00001100 the 0 will be multiplied by two, stored in tambah for 4 times so tambah will be 8, and the one will be multiplied by two and added by one. Then it found 1 so it will be 17, and then it found another 1 so it will be 35 and so on..

J-M-L:
don't trust what you see when you print because during an interrupt you can't print..

So, what should i do?

Don't call Serial in the interrupt....

Like I said, you're making it wayyyyy more complex. Just decide if it's a 0 or a 1 the moment you see the falling edge and you know how long it took :slight_smile: