Capturing, storing, modifying and retransmission of a data stream.

Go To Last Post
68 posts / 0 new

Pages

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It’s Arduino! Has been documented to the nth degree!
The problem on an UNO is the uart is connected to the usb->serial chip.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I should still be able to read the RX pin or do I need to unplug it from the USB and power it externally?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The UNO only has one hardware USART, but you can use "softserial" to add a software serial on any pair of free pins.

Just #include softserial and tell it what pins to use.  Look here for how to use it: https://www.arduino.cc/en/Refere...

Jim

 

 

 

(Possum Lodge oath) Quando omni flunkus, moritati.

"I thought growing old would take longer"

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you. I will have a read.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think I have the softwareserial working ........ sort of. When I read the serial in it only places it in the first byte of "buf". Replacing byte 5 seems to work as required as does the checksum for byte 7. I am using a Leo to produce the serial bytes and doesn't seem to be doing as it is expected to do. (It used but I must have done something to it) It only output write_byteN. Please ignore the over use of prints, they are just there for testing.

 

      Serial test data installed on Leo board

//Serial_byte_txer R0.1

int write_byteN[8] = {0x12, 0x14, 0x16, 0x18, 0x16, 0x00, 0x20, 0x22};
int write_byte1[8] = {0x12, 0x14, 0x16, 0x18, 0x16, 0x20, 0x20, 0x22};
int write_byte2[8] = {0x12, 0x14, 0x16, 0x18, 0x16, 0x40, 0x20, 0x22};
int write_byte3[8] = {0x12, 0x14, 0x16, 0x18, 0x16, 0x60, 0x20, 0x22};
int write_byte4[8] = {0x12, 0x14, 0x16, 0x18, 0x16, 0x80, 0x20, 0x22};
int write_byte5[8] = {0x12, 0x14, 0x16, 0x18, 0x16, 0xA0, 0x20, 0x22};

void setup() {

  Serial.begin(9600);
  Serial1.begin(9600);
}

void loop() {

  for (int n = 0; n < 50; n = n++)
    for (int i = 0; i <= 7; i = i + 1) {
      Serial.println(write_byteN[i], HEX);
      Serial1.write(write_byteN[i]);
      delay(5);
    }
  delay(1000);

  for (int one = 0; one < 50; one = one++)
    for (int i = 0; i <= 7; i = i + 1) {
      Serial.println(write_byte1[i], HEX);
      Serial1.write(write_byte1[i]);
      delay(5);
    }
  delay(1000);

  for (int two = 0; two < 50; two = two++)
    for (int i = 0; i <= 7; i = i + 1) {
      Serial.println(write_byte2[i], HEX);
      Serial1.write(write_byte2[i]);
      delay(5);
    }
  delay(1000);

  for (int three = 0; three < 50; three = three++)
    for (int i = 0; i <= 7; i = i + 1) {
      Serial.println(write_byte3[i], HEX);
      Serial1.write(write_byte3[i]);
      delay(5);
    }
  delay(1000);

  for (int four = 0; four < 50; four = four++)
    for (int i = 0; i <= 7; i = i + 1) {
      Serial.println(write_byte4[i], HEX);
      Serial1.write(write_byte4[i]);
      delay(5);
    }
  delay(1000);

  for (int five = 0; five < 50; five = five++)
    for (int i = 0; i <= 7; i = i + 1) {
      Serial.println(write_byte5[i], HEX);
      Serial1.write(write_byte5[i]);
      delay(5);
    }
  delay(1000);
//  delay(2000);
}

 

      Main code on UNO (to be transferred to AtTiny3217 once working)

//Wondatre R1.0

#include "Wire.h"
#include <EEPROM.h>
#include <SoftwareSerial.h>

SoftwareSerial RXSerial(2, 3); // RX, TX

byte indx;
uint8_t buf[8];
uint8_t bufIdx;
uint8_t new_byte;
uint8_t x;

int gear_in;
int Gear;
int sensorVal;
int out1 = 5;
int out2 = 6;
int rxd = 13;
int txd = 14;
int gearN = 0x00;
int gear1 = 0x20;
int gear2 = 0x40;
int gear3 = 0x60;
int gear4 = 0x80;
int gear5 = 0xA0;

void setup()

//stolen from PIGPI

{

  delay(500); //wait to settle
  pinMode(out1, OUTPUT);
  pinMode(out2, OUTPUT);
  pinMode(rxd, INPUT_PULLUP);
  pinMode(txd, OUTPUT);
  pinMode(A0, INPUT);

  // Read sensor value

  sensorVal = analogRead (A0);

  //Save Gear to EEPROM

  if (sensorVal < 666 )

  {
    // No Change
    Gear = EEPROM.read(0); //Load gear from EEPROM
  }
  else if  (sensorVal > 667 and sensorVal <= 800)
  {
    Gear = 1; //4th Gear
  }
  else if  (sensorVal > 801 and sensorVal <= 905)
  {
    Gear = 2; //5th Gear
  }

  EEPROM.update(0, Gear); // Only writes if different

  switch (Gear)
  {
    case 1:  digitalWrite(out1, HIGH); break;
    case 2:  digitalWrite(out2, HIGH); break;
  }

  Serial.begin(9600);
  RXSerial.begin(9600);

}

void loop()
{
  sensorVal = analogRead (A0);

  Gear = EEPROM.read(0); //Load gear from EEPROM

  if (sensorVal > 301)

    switch (Gear)
    {
      case 1:  digitalWrite(out1, HIGH); break;
      case 2:  digitalWrite(out2, HIGH); break;
    }

  gear_in = analogRead (A0);      // read gear
  /*  Serial.println(Gear);           // For testing
    Serial.println(gear_in);        // For testing
    delay(1000);                    // For testing
  */

  if (gear_in <= 300)
  {
    new_byte = gearN;
  }

  else if (gear_in > 301 and gear_in <= 420)
  {
    new_byte = gear1;
  }

  else if (gear_in > 421 and gear_in <= 540)
  {
    new_byte = gear2;
  }

  else if (gear_in > 541 and gear_in <= 665)
  {
    new_byte = gear3;
  }

  else if (gear_in > 666 and gear_in <= 800)
  {
    new_byte = gear4;
  }

  else if (gear_in > 801 and gear_in <= 905)
  {
    new_byte = gear5;
  }
  /*
    Serial.print ("New_Byte ");       // For testing
    Serial.println (new_byte, HEX);   // For testing
    delay(1000);                      // For testing
  */

  //EVERYTHING ABOVE THIS LINE WORKS

// This bit is to check every 100ms for the next 8 bytes. Will work this out later.
  /*    for (uint8_t i = 0; i < 100; i++, _delay_ms(1) ) {
        if (read_byte >= 0)it
        } i = 0                           //start over if rx data
    }
    int
  */

  //Read data from ECU and store in buf
  {
    if (RXSerial.available() > 0);
    byte ECU_byte = RXSerial.read();
    indx = 0;

    if (indx < sizeof buf);
    buf [indx++] = ECU_byte;

    Serial.print ("ECU_Byte = ");       // For testing
    Serial.println (ECU_byte, HEX);   // For testing
    Serial.print ("New_Byte = ");       // For testing
    Serial.println (new_byte, HEX);   // For testing

    if (indx = 5, buf[5] = new_byte);     //check for byte 5....working
    Serial.print ("indx =  ");         // For testing
    Serial.println (indx);            // For testing

    Serial.print ("buf 0 =  ");         // For testing
    Serial.println (buf[0], HEX);            // For testing
    Serial.print ("buf 1 =  ");         // For testing
    Serial.println (buf[1], HEX);            // For testing
    Serial.print ("buf 2 =  ");         // For testing
    Serial.println (buf[2], HEX);            // For testing
    Serial.print ("buf 3 =  ");         // For testing
    Serial.println (buf[3], HEX);            // For testing
    Serial.print ("buf 4 =  ");         // For testing
    Serial.println (buf[4], HEX);            // For testing
    Serial.print ("buf 5 =  ");         // For testing
    Serial.println (buf[5], HEX);            // For testing
    Serial.print ("buf 6 =  ");         // For testing
    Serial.println (buf[6], HEX);            // For testing

  }

  // Calculate checksum - Appears to be working
  {
    int checksum = 0;
    for (int x = 0; x <= 6; x++); {
      checksum = checksum + buf[x];
      Serial.print ("Checksum =  ");         // For testing
      Serial.println (checksum, HEX);            // For testing

      buf[7] = 0xff - checksum; // Replace byte 7 with new checksum
    }
    Serial.print ("buf 7 =  ");         // For testing
    Serial.println (buf[7], HEX);            // For testing
    delay(000);                      // For testing

  }
}
/*
  //write Data to display
  {
    byte write_byte;
    bufIdx = 0;
    while ( bufIdx < 8 ) write_byte;
    buf[bufIdx++];
    RXSerial.write(buf, 7);
    delay(5);      // pauses for 5 milliseconds before sending the next byte
  }
*/

 

Last Edited: Fri. Oct 9, 2020 - 11:46 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Divide you code into functions. One function does one thing, properly. Test each function.

I can’t make much sense of your code. The line rxserial.available() does nothing. You set indx to 0. How does your receive code synchronise itself to the incoming data?

Hint: filter any external input in software. Limit your writes to eeprom. I’d suggest you detect power fail and write to eeprom then.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kartman wrote:
Divide you code into functions. One function does one thing, properly. Test each function.

 

I was thinking of doing that

 

Quote:
I can’t make much sense of your code.

 

I will repost once I funcionise it.....wow new word.

 

Quote:
The line rxserial.available() does nothing.

 

This was done from this example so I assumed it would work.  https://www.arduino.cc/en/Tutori...

 

Quote:
Hint: filter any external input in software.
 

 

No idea what this means or how to do it.

 

Quote:
Limit your writes to eeprom. I’d suggest you detect power fail and write to eeprom then.

 

It only writes to EEPROM if it is the first time it is run or if you change the gear setting which in theory should be never or very rarely.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have put them in functions. Hope it makes more sense.

 

Also what should be inplace if indx=0?

 

//Wondatre R1.0

#include "Wire.h"
#include <EEPROM.h>
#include <SoftwareSerial.h>

SoftwareSerial RXSerial(2, 3); // RX, TX

byte indx;
uint8_t buf[8];
uint8_t bufIdx;
uint8_t new_byte;
uint8_t x;

int gear_in;
int Gear;
int sensorVal;
int out1 = 5;
int out2 = 6;
int rxd = 13;
int txd = 14;
int gearN = 0x00;
int gear1 = 0x20;
int gear2 = 0x40;
int gear3 = 0x60;
int gear4 = 0x80;
int gear5 = 0xA0;

void setup()

//stolen from PIGPI

{

  delay(500); //wait to settle
  pinMode(out1, OUTPUT);
  pinMode(out2, OUTPUT);
  pinMode(rxd, INPUT_PULLUP);
  pinMode(txd, OUTPUT);
  pinMode(A0, INPUT);

  // Read sensor value

  sensorVal = analogRead (A0);

  //Save Gear to EEPROM

  if (sensorVal < 666 )

  {
    // No Change
    Gear = EEPROM.read(0); //Load gear from EEPROM
  }
  else if  (sensorVal > 667 and sensorVal <= 800)
  {
    Gear = 1; //4th Gear
  }
  else if  (sensorVal > 801 and sensorVal <= 905)
  {
    Gear = 2; //5th Gear
  }

  EEPROM.update(0, Gear); // Only writes if different

  switch (Gear)
  {
    case 1:  digitalWrite(out1, HIGH); break;
    case 2:  digitalWrite(out2, HIGH); break;
  }

  Serial.begin(9600);
  RXSerial.begin(9600);

}

void loop()
{
  sensorVal = analogRead (A0);

  Gear = EEPROM.read(0); //Load gear from EEPROM

  if (sensorVal > 301)

    switch (Gear)
    {
      case 1:  digitalWrite(out1, HIGH); break;
      case 2:  digitalWrite(out2, HIGH); break;
    }

  gear_in = analogRead (A0);      // read gear
  /*  Serial.println(Gear);           // For testing
    Serial.println(gear_in);        // For testing
    delay(1000);                    // For testing
  */

  if (gear_in <= 300)
  {
    new_byte = gearN;
  }

  else if (gear_in > 301 and gear_in <= 420)
  {
    new_byte = gear1;

  }

  else if (gear_in > 421 and gear_in <= 540)
  {
    new_byte = gear2;
  }

  else if (gear_in > 541 and gear_in <= 665)
  {
    new_byte = gear3;
  }

  else if (gear_in > 666 and gear_in <= 800)
  {
    new_byte = gear4;
  }

  else if (gear_in > 801 and gear_in <= 905)
  {
    new_byte = gear5;
  }
  
  /*
    Serial.print ("New_Byte ");       // For testing
    Serial.println (new_byte, HEX);   // For testing
    delay(1000);                      // For testing
  */
  
  read_data_replace_byte5();
  calculate_checksum();
  write_bytes();
  
}
  //EVERYTHING ABOVE THIS LINE WORKS

// This bit is to check every 100ms for the next 8 bytes. Will work this out later.

  /*    for (uint8_t i = 0; i < 100; i++, _delay_ms(1) ) {
        if (read_byte >= 0)it
        } i = 0                           //start over if rx data
    }
    int
  */
  
void read_data_replace_byte5()

  //Read data from ECU and store in buf
  {
    if (RXSerial.available() > 0);
    byte ECU_byte = RXSerial.read();
    indx = 0;

    if (indx < sizeof buf);
    buf [indx++] = ECU_byte;

    Serial.print ("ECU_Byte = ");       // For testing
    Serial.println (ECU_byte, HEX);   // For testing
    Serial.print ("New_Byte = ");       // For testing
    Serial.println (new_byte, HEX);   // For testing
  
    if (indx = 5, buf[5] = new_byte);     //check for byte 5....working
    
    Serial.print ("indx =  ");         // For testing
    Serial.println (indx);            // For testing

    Serial.print ("buf 0 =  ");         // For testing
    Serial.println (buf[0], HEX);            // For testing
    Serial.print ("buf 1 =  ");         // For testing
    Serial.println (buf[1], HEX);            // For testing
    Serial.print ("buf 2 =  ");         // For testing
    Serial.println (buf[2], HEX);            // For testing
    Serial.print ("buf 3 =  ");         // For testing
    Serial.println (buf[3], HEX);            // For testing
    Serial.print ("buf 4 =  ");         // For testing
    Serial.println (buf[4], HEX);            // For testing
    Serial.print ("buf 5 =  ");         // For testing
    Serial.println (buf[5], HEX);            // For testing
    Serial.print ("buf 6 =  ");         // For testing
    Serial.println (buf[6], HEX);            // For testing

  }

void calculate_checksum()

  // Calculate checksum - Appears to be working
  {
    int checksum = 0;
    for (int x = 0; x <= 6; x++); {
      checksum = checksum + buf[x];
      Serial.print ("Checksum =  ");         // For testing
      Serial.println (checksum, HEX);            // For testing

      buf[7] = 0xff - checksum; // Replace byte 7 with new checksum
    }
    Serial.print ("buf 7 =  ");         // For testing
    Serial.println (buf[7], HEX);            // For testing
    delay(0);                      // For testing

  }
void write_bytes()
{
/*
  //write Data to display
  {
    byte write_byte;
    bufIdx = 0;
    while ( bufIdx < 8 ) write_byte;
    buf[bufIdx++];
    RXSerial.write(buf, 7);
    delay(5);      // pauses for 5 milliseconds before sending the next byte
  }
*/
}

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1
uint8_t calculate_checksum(const uint8_t *dat,int len)
  // Calculate checksum - Appears to be working
  {
    uint8_t checksum = 0;
    
    for (int x = 0; x < len; x++) 
    {
      checksum += dat[x];
    }

    return checksum;
  }

The above is a function. You give it a block of data and the length. It gives you back the checksum. Easily tested. You can run this code on your PC.

 

Note, code like this won't do much: 

for (int x = 0; x <= 6; x++);

I'd say your intent was that you didn't want the ; on the end. You've done this a number of times through your code.

 

if (indx < sizeof buf);
 if (RXSerial.available() > 0);
if (indx = 5, buf[5] = new_byte);

Again, this will not do much.

 

 

I mentioned earlier about filtering.

sensorVal = analogRead (A0);

You read ADC0 at least three times in your code. Surely there only needs to be one?

When you read a digital input or an analog input, it is only a snapshot of the value in a small instant of time.  Thus reading once cannot give you a reliable result - especially if there is noise and since this is an automotive application, you'll have noise in spades. Therefore you need to filter it.

 

 

A common filter is:

 

result = (coeff * input) + (1- coeff)* result;

 

where coeff is a value between 0 and 1. 0  gives no change and 1 gives no filtering. Values in between give you a variable degree of filtering. Commonly known as an exponential filter. Determine how fast you expect the input to change and adjust the filter to suit. Anything that changes faster than you expect is noise. Thus, how many gear changes per second do you expect? Sample the analog input at least 10 times that rate and adjust the filter coeff value. I'd sample the input at 100Hz or maybe faster. You can observe the effect of the filter by outputting the result to the serial terminal. It should change smoothly even with large changes on the input.

 

 

Also, what's the pre-occupation with int? If you want to conserve memory space then choose the correct size of variable. An int uses two bytes. uint8_t uses 1.

 

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks. I will have a play tomorrow.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You are also missing values at various places in these tests-

 

  if (gear_in <= 300)
  {
    new_byte = gearN;
  }

  else if (gear_in > 301 and gear_in <= 420)
  {

 

you skipped 301, and so on.

 

 

You are probably making this more work than needed. The ecu already does the timing of these bytes for you, and you can just echo everything except the gear byte and checksum and have no need to save anything. The bytes go out the same time they come in, so there is no timing to keep track of. You don't even need to calculate checksum, just adjust it (which will also prevent using/sending the wrong set of 8 bytes as you will then end up with an incorrect checksum).

 

https://godbolt.org/z/ja58Y8

 

When you move to something like the tiny3217 where you have a little more control, the rx isr can do the work and it won't even break a sweat.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Can I suggest that you don't simply take an amorphous great lump of code, group some lines and call it a function but actually forget about writing C code all together. Spend some time analysing what needs to be done, what functions will be needed to achieve that and then what's going to be going on inside each of those functions. Only when you have all this clear in your mind then get out your C editor and start to code it. Otherwise you'll just find yourself knitting an increasingly large ball of spaghetti. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for your inputs.

 

I will try to explain each of my parts of code when I get home to my code machine.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok. I will try and simplify my requirements here. 

 

In the Void setup() I am detecting the gear the ike is in. If the bike is in any gear other than 4th or 5th it will go to the loop. If it is in 4th or 5th it will safe this value to EEPROM.

 

Once into void loop() It reads the EEPROM and A0 again and and if sensorval is above 301 sets the output per case1 or case2, these active a transistor to enable an output. This works.

 

The next step is to determine the actual gearthat is selected whilst riding. The ranges are there because each bike maybe be slightly different but will be apporx in the middle of each range per gear.

 

Curt, you mentioned that I missed 301 but it doesn't need to be that accurate and if it was anywhere near 301 there would be a problem. I have just made it a nice and wide window for each gear.

 

Everything up to this point works.

 

Thanks to the link Curt provided I might do some changes but I will explain what the rest is trying to do.

 

1.   read the serial in. Store it or now possibly echo as suggested. Currently not working. It is only ever place data in the 1st byte.

 

2.   When it reads the 6th byte I need to relace it with the hex value of the current gear. Sort of works.

 

3.   Take the first 7 bytes and calculate the checksum. This works but will try the method in the link. 

 

I will have a try over the next few nights and see what I can do.

 

Thanks again for your suggestions

 

PS. Curt, not sure how this can work. It only gives specific values and not ranges.

 

const adcGear_t gearTable[] = {
    { 300, 0x00 }, //if <= adcVal, return gearVal
    { 420, 0x20 },
    { 540, 0x40 },
    { 665, 0x60 },
    { 800, 0x80 },
    { 905, 0xA0 },
    // >905 ? error value or ?
    { 0xffff, 0xA0 } //{ 0xffff, 0xff }

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

that's just the table - need to write code that steps through that table testing the range. When you get a match then the table index is the gear number.

 

How do you know which byte is the first byte of the 7 byte message?

Maybe its framed by time or there's a specific start sequence? Your code needs to cope with this. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

>Curt, not sure how this can work. It only gives specific values and not ranges.

 

It is still ranges of values, and is checking them until you are in the right range.

0-300 = 0

301-420 = 0x20

421-540 = 0x40

541-665 = 0x60

666-800 = 0x80

801-905 = 0xA0

906-65535 = ?

 

I would probably assume the 905 entry could be eliminated so you get 0xA0 for anything > 800 (so 801-0xffff = 0xA0).

 

 

//read analog, convert to gear value from  lookup table
uint8_t readGear(){
    uint16_t v = analogRead (A0);    //read sensor, adc value 0-1023 (for 10bit)
    const adcGear_t* gp = gearTable; //a pointer to the gear table (actually the first entry of the array)
    for( ; v > gp->adcVal; gp++ ){}  // if( adc value > adc value in table ) wrong range, try next table entry
    return gp->gearVal;              // found something, return the gear value
}

 

example-

 

analogRead( A0 ) = 456, so v = 456

gp = pointer to gearTable (&gearTable[0])

v > gp->adcVal ?, 456 > 300 ?, yes, so gp++ ( gp = &gearTable[1] )

v > gp->adcVal ?, 456 > 420 ?, yes, so gp++ ( gp = &gearTable[2] )

v > gp->adcVal ?, 456 > 540 ? no, done

return gp->gearVal ( return 0x40 )

 

so we ended up using-

if( v >420 and v <= 540 ) return 0x40

 

 

 

>you mentioned that I missed 301 but it doesn't need to be that accurate and if it was anywhere near 301 there would be a problem. I have just made it a nice and wide window for each gear.

 

That could be true, but it would be a bad habit to get into because you want as much certainty as you can can get, in as many places as you can. You read the sensor, you get a gear value. You don't skip 5 of the 1024 adc values because they 'should' never happen. It doesn't take any more effort to include them, and you never have to worry about it again. The function above does not allow for skipping any values.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

>How do you know which byte is the first byte of the 7 byte message?

>Maybe its framed by time or there's a specific start sequence? Your code needs to cope with this. 

 

See the original post.

 

The linked code in post #62 looks for 30ms of silence, where there should be 60ms.

Pages