Serial Comm Ports for ever and ever… (Part 2)

Part 12345678

Now that we are more familiar with asynchronous serial communication, let’s complicate a little bit more the programming in order to achieve our ultimate goal: send and received bunches of bytes (at any rate, from 5 to 28800 baud).
Instead of transfering unique bytes, we will transfer vectors of bytes. In addition, we will pass the vector parameter “ByRef”; for this, we will use pointers!

This is how it works for initializing the vector of data sent and listing its content:

Here is the test script

  byte vDataOut[26]; // Create a vector containing the sent data
  initializeData(&vDataOut[0], 26); // Fill in this vector with some data (Alphabet)
  listData(&vDataOut[0], sentBytes); // List  n bytes from the vector with sent data

Here is the initialization function

/* 
Initialize the content of the vector of data 
The vecor is filled with capitalized alphabet
*/
void initializeData(byte *pdata, int nbrBytes){
  for (int i=0; i < nbrBytes; i++) {
    pdata[i] = (i + 65);
  }
}

Here is the list function

/*
List the content of the vector of data 
*/
void listData(byte *pdata, int nbrBytes){
  for (int i=0; i < nbrBytes; i++) {
    Serial.print(pdata[i], BYTE);
    Serial.print(" ");
  }
  Serial.println();
}

Some more explanations:

  • &vDataOut[0] means: address-of the first record of vector nammed vDataOut
  • byte *pdata means: define a pointer to a byte variable (the vector) which will be passed as a parameter to the function
  • pdata[i] means: de-reference the pointer value in order to access (in read or write) to the value of the variable it points to

And now the bytes writer function

/* 
Write bytes
Returns the number of written bytes
*/
int writeBytes( 
  byte *pdata, 
  int nbrBytes, // nbr expected bytes
  long baudRate, // 5 to 28800
  int nbrBits // 1 to 8
  )
  {
  long interval = long(1000000 / baudRate); // in µs
  for (int j; j < nbrBytes; j++) {
    //
    PORTB |=  (1 << ledPin); // turn status led on
    //
    byte byteValue = pdata[j];
    long startOfByteTime = micros(); // Set reference time to half first bit interval
    long endOfBitTime = startOfByteTime + interval;
    // Send start bit
    PORTB &= ~(1 << TxPin); // Set start bit (low level) on TxPin
    while (micros() < endOfBitTime);  // Wait until stop pulse is reached
    // Send data bits: LSB first, MSB last
    for (int i = 0; i < nbrBits; i++) {
      byte bitValue = ((byteValue >> i) & 0x01);
      if (bitValue) {
        PORTB |=  (1 << TxPin); 
      }
      else {
        PORTB &= ~(1 << TxPin); 
      }
      endOfBitTime = startOfByteTime + (interval * (i+2));
      while (micros() < endOfBitTime); // // Pulse width
    }
    // Send stop bit
    PORTB |=  (1 << TxPin); // Set stop bit (high level) on TxPin
    endOfBitTime = startOfByteTime + (interval * (nbrBits+2));
    while (micros() < endOfBitTime); // // Pulse width
    //
    PORTB &= ~(1 << ledPin); // turn status led off
    //
  }
}

And the bytes reader function

/* 
Read incoming byte
Returns the number of read received bytes
*/
int readBytes( 
  byte *pdata, // Pointer to destination vector
  int nbrBytes, // nbr expected bytes
  long baudRate, // 5 to 28800
  int nbrBits, // 1 to 8
  int timeOut // in ms
  )
  {
  // default error code
  errorCode = ERR_NONE;
  int nbrReceivedBytes = 0;
  long interval = long(1000000 / baudRate); // in µs
  for (int j=0; j < nbrBytes; j++) {
    boolean elapsedTimeOut = false;
    byte byteValue = 0; 
    long abortTime = (millis() + timeOut);
    // Wait for the start bit (low level)
    while (PINB & (1 << RxPin)) { // Loop until level is high
      if (millis() > abortTime){ // Monitor timeout
        elapsedTimeOut = true;
        break;
      } 
    }
    long referenceTime = micros() + long(500000 / baudRate); // now + half interval
    if (elapsedTimeOut) { // 
      /*
      if (nbrBytes == 0 ) {
        errorCode = ERR_TIMEOUT;
      }
      */
      errorCode = ERR_TIMEOUT;
      break;
    }
    else {
      // Read the incoming byte
      //
      PORTB |=  (1 << ledPin); // turn status led on
      //
      long nextSensingTime = 0;
      // Read bits
      for (int i=0; i < nbrBits; i++) {  
        // Set next sensing time
        nextSensingTime = (referenceTime + (interval * (i + 1)));
        // Wait for data bits
        while (micros() < nextSensingTime);
        byte bitValue = ((PINB >> RxPin) & 0x01);
        byteValue |= (bitValue << i);
       }
      // Wait for the stop bit
      nextSensingTime = referenceTime + interval * (nbrBits + 1);
      while (micros() < nextSensingTime);
      byte bitValue = ((PINB >> RxPin) & 0x01);
      //
      PORTB &= ~(1 << ledPin); // turn status led off
      //
      if (bitValue){ // (High level)
        // Validate and record byte 
        nbrReceivedBytes++;
        pdata[nbrReceivedBytes - 1] = byteValue;
      } 
      else {// (Low level)
        errorCode = ERR_FRAME;
        return (0); // We could return the number of bytes
      }
    }
  } 
  return (nbrReceivedBytes);
}

Note that the errorCode variable is global to the application

Next post on same subject

Leave a Reply

You must be logged in to post a comment.