Pages: [1]   Go Down
Author Topic: Serial Data Interference  (Read 723 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 15
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
Hello there,

I'm having trouble receiving data from Max/MSP via serial.

I am sending various commands from Max/MSP that control various components. These are working fine using a custom key system I have coded (such as MLM 255 7 9 5;), but when try to send commands to an LCD, the strings the LCD print have interference, picking up (sometimes only some of) the other data I have sent, such as the key above, and potentiometer values I am sending to Max/MSP (MVAL 1 8 1052). I had a feeling it was something to do with buffers overflowing, but cant figure out where it leaking. Can anyone see a major problem with the way I am sending strings to the LCD?

Many thanks in advance,


[b]Main loop[/b]
[code]void loop() {
  
  
 if(Serial.available())   // If serial data is waiting to be read
  {
      serialInString[serialInStringPos] = Serial.read();  // Store data in string
      serialInStringPos++;
      
      if (serialInString[serialInStringPos - 1] == 59){   // If read Semi-Colon
        serialInString[serialInStringPos - 1] = '\0';     // Null terminate
        actionSerialString();                             // Perform action on data
      }
  }  
 
elapsedTime = millis(); // Store elapsed time
readMixerValues(); // Uses internal timer
//sendMixerValues();

}  


Function that processes serial data
Code:
// actionSerialString
// Parses the serial string and excecutes relevant function
// - MLM Mixer Level Meter
// - LCD LCD display
// - MLD Mixer LED latch direction indicators
////////////////////////////////////////////////////////////////////////
void actionSerialString(){

  char *ch;   // Pointer
  
  ch = strchr(serialInString, ' ');    // Find 'space' and store posistion in ch
  if(ch) {                             // If space found
    *ch = '\0';                        // Convert to null character

    if(strcmp(serialInString, "MLM") == 0)    // If string matches "MLM"
      MLMFunctionCall(ch+1);                  // Call level meter function
else if(strcmp(serialInString, "LCD") == 0)    // If string matches "LCD"
      LCDFunctionCall(ch+1);                  // Call LCD function
    else if(strcmp(serialInString, "MLD") == 0)    // If string matches "MLD"
      MLDFunctionCall(ch+1);                  // Call Mixer LED function
  }
 
 
LCD Function call
Code:
// LCDFunctionCall
// Prints to the LCD in format "(lineNumber) (textToBeWritten)"
////////////////////////////////////////////////////////////////////////
void LCDFunctionCall(char *data){
 

 char *ch;   // Pointer
  
 ch = strchr(data, ' ');        // Find 'space' and store posistion in ch
 if(ch) {                       // If space found
   *ch = '\0';                  // Convert to null character
   LCDClearLine(data[0] - 49);  // Clear line based on first char
   lcd.print(ch+1);             // Print rest of string

  }
              
}


An example of a working call
Code:
// MLMFunctionCall
// Takes 4 values (0-8) as space-seperated symbol and updates level meters
////////////////////////////////////////////////////////////////////////
void MLMFunctionCall(char *data){
digitalWrite(LM_latchPin, LOW);
shiftOut(LM_dataPin, LM_clockPin, MSBFIRST, seq[ int( data[6]-48) ] );
shiftOut(LM_dataPin, LM_clockPin, MSBFIRST, seq[ int( data[4]-48) ] );
shiftOut(LM_dataPin, LM_clockPin, MSBFIRST, seq[ int( data[2]-48) ] );
shiftOut(LM_dataPin, LM_clockPin, MSBFIRST, seq[ int( data[0]-48) ] );
digitalWrite(LM_latchPin, HIGH);
}
[/code]
« Last Edit: January 10, 2013, 06:14:26 pm by mibix » Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 601
Posts: 48543
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
      if (serialInString[serialInStringPos - 1] == ';') {   // No silly comment needed
Some people recommend that the { be on a new line. Some recommend that it be on the line with the statement. NO one recommends that it be jammed up tight against the statement.

Perhaps you meant to post this at http://snippets-r-us.com. Here, we expect to see ALL of your code.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 15
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Sorry didn't want to post 300 lines of code if it wasn't needed. Here it is...

Why is that a silly comment? Because I have used the ASCII value instead of a character?
 
I didn't think the { had any relevance with regard position?

Code:
/** Ableton Controller v0.1

Ableton Controller.ino
Main code file */

// include the library code:
#include <LiquidCrystal.h>




// Initialisations
////////////////////////////////////////////////////////////////////////

// Level Meters
const int LM_latchPin = 25;
const int LM_clockPin = 23;
const int LM_dataPin = 27;
const int seq[9] = {0, 128, 192, 224, 240, 248, 252, 254, 255}; // Display Sequence

// Mixer
const int MIX_latchPin = 45;
const int MIX_clockPin = 47;
const int MIX_dataPin = 43;

const int MIX_muxBit1 = 49;
const int MIX_muxBit2 = 51;
const int MIX_muxBit3 = 53;

int potValues[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

// LCD
LiquidCrystal lcd(39, 255, 37, 41, 35, 33, 31, 29);
//LiquidCrystal lcd(RS, RW, Enable1, Enable2, data3, data2, data1, data0)

// Serial
char serialInString[250];   // Serial data string
int serialInStringPos = 0;  // Serial string position for writing
char inputString[2];


// Variables
unsigned long elapsedTime = 0; // Current Arduino up time in milliseconds
const int mixerUpdateTime = 50; // Pot value read refresh rate in milliseconds
const int mixerUpdateWriteTime = 100; // Serial send of values
const int numberOfMixerBoards = 2; // Number of mixer circuit boards
int mixerUpdateCounter = 0; // Counter used in mixer refresh
int mixerWriteUpdateCounter = 0; // Counter for mixer value write
int mixerBoardWriteNumber = 0; // Board which is currently printing to serial




void setup() {
  //Serial.begin(9600);
  Serial.begin(115200);
  pinMode(LM_latchPin, OUTPUT);
  pinMode(LM_clockPin, OUTPUT);
  pinMode(LM_dataPin, OUTPUT);

  pinMode(MIX_latchPin, OUTPUT);
  pinMode(MIX_clockPin, OUTPUT);
  pinMode(MIX_dataPin, OUTPUT);

  pinMode(MIX_muxBit1, OUTPUT);
  pinMode(MIX_muxBit2, OUTPUT);
  pinMode(MIX_muxBit3, OUTPUT);

  lcd.begin(40, 4);     // Start LCD
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("TURNED ON");
}


// Functions
////////////////////////////////////////////////////////////////////////



// readMixerValues
// Reads analog values from mixer multiplexer
// Update time controlled by variable mixerUpdateTime
////////////////////////////////////////////////////////////////////////
void readMixerValues()
{
if (int(elapsedTime) - mixerUpdateCounter > mixerUpdateTime)
{

//Serial.println(elapsedTime);
//Serial.println(mixerUpdateCounter);
mixerUpdateCounter = elapsedTime;


for (int count=0; count<=7; count++) { // For each pot (on 1 board)

// select the bits  
int r0 = bitRead(count,0);    
int r1 = bitRead(count,1);    
int r2 = bitRead(count,2);      
digitalWrite(MIX_muxBit1, r0);
digitalWrite(MIX_muxBit2, r1);
digitalWrite(MIX_muxBit3, r2);

int value=0;

// For each board
for (int boardCount = 0; boardCount < numberOfMixerBoards; boardCount++)
{

if (boardCount == 0) value = analogRead(A0); // Read board 1
if (boardCount == 1) value = analogRead(A1); // Read board 2


int potID = count + (8 * boardCount); // Get Pot ID number
//Serial.print("ID:   ");
//Serial.println(potID);

if (value != potValues[potID]) // If value has changed
{
potValues[potID] = value; // Save Value
Serial.print("Value: ");
Serial.println(value);
sendMixerValues(boardCount, count, value);
Serial.println("CHANGE");
//delay(200);
}

/* if (count != 6 || count != 7)
value = ((value * -1) + 1023);
else
potValues[count + (8 * boardCount)] = ((value * -1) + 1023); // Fix 5v-Gnd board pots*/

/*if (count == 6 || count == 7)
potValues[count + (8 * boardCount)] = value;
else
potValues[count + (8 * boardCount)] = ((value * -1) + 1023); // Fix 5v-Gnd board pots*/
}


 }  
}
}
  

// sendMixerValues
// Prints to serial in format "MVAL (boardNumber) (controllerNumber) (controllerValue)"
////////////////////////////////////////////////////////////////////////

void sendMixerValues(int boardNumberToSend, int potToSend, int value)
{


Serial.print("MVAL");
Serial.print(" ");
Serial.print(boardNumberToSend);
Serial.print(" ");
Serial.print(potToSend);
Serial.print(" ");
Serial.println(value);


}



// actionSerialString
// Parses the serial string and excecutes relevant function
// - MLM Mixer Level Meter
// - LCD LCD display
// - MLD Mixer LED latch direction indicators
////////////////////////////////////////////////////////////////////////
void actionSerialString(){

  char *ch;   // Pointer
  
  ch = strchr(serialInString, ' ');    // Find 'space' and store posistion in ch
  if(ch) {                             // If space found
    *ch = '\0';                        // Convert to null character

    if(strcmp(serialInString, "MLM") == 0)    // If string matches "MLM"
      MLMFunctionCall(ch+1);                  // Call level meter function
else if(strcmp(serialInString, "LCD") == 0)    // If string matches "LCD"
      LCDFunctionCall(ch+1);                  // Call LCD function
    else if(strcmp(serialInString, "MLD") == 0)    // If string matches "MLD"
      MLDFunctionCall(ch+1);                  // Call Mixer LED function
  }
  
  serialInStringPos = 0;                // Reset serial string data position
 // memset( serialInString, 0, sizeof(serialInString)); // Clear syting buffer
}






// MLDFunctionCall
// Takes spaces seperated list of binary chars and outputs to SR
// (eg. (00110011 10101010) - each 'bit' represents an LED)
////////////////////////////////////////////////////////////////////////
void MLDFunctionCall(char *data){



char *ch; // Pointer
int valuesToShift[numberOfMixerBoards*2]; // Array of values for shift register
int valueCounter = 0; // Counter for counting incoming values
char* valuesToSend; // Split string

ch = strtok (data," "); // Cut string at space
while (ch != NULL) // While it's got something
{
valuesToSend = ch; // Store char values
valuesToShift[valueCounter] = atoi(valuesToSend); // Convert to integer
valueCounter++; // Increase counter (next shift register)
ch = strtok (NULL, " "); // Try again to cut string at space
}

// Write to shift registers
digitalWrite(MIX_latchPin, LOW);
shiftOut(MIX_dataPin, MIX_clockPin, MSBFIRST, valuesToShift[0] );
shiftOut(MIX_dataPin, MIX_clockPin, MSBFIRST, valuesToShift[1] );
shiftOut(MIX_dataPin, MIX_clockPin, MSBFIRST, valuesToShift[2] );
shiftOut(MIX_dataPin, MIX_clockPin, MSBFIRST, valuesToShift[3] );
digitalWrite(MIX_latchPin, HIGH);
}



// binaryCharsToInt
// Convert binary chars to int (eg. 10110111 to 183)
// http://www.wikihow.com/Convert-from-Binary-to-Decimal (Doubling Method)
////////////////////////////////////////////////////////////////////////
int binaryCharsToInt(char *data){

}



// MLMFunctionCall
// Takes 4 values (0-8) as space-seperated symbol and updates level meters
////////////////////////////////////////////////////////////////////////
void MLMFunctionCall(char *data){
digitalWrite(LM_latchPin, LOW);
shiftOut(LM_dataPin, LM_clockPin, MSBFIRST, seq[ int( data[6]-48) ] );
shiftOut(LM_dataPin, LM_clockPin, MSBFIRST, seq[ int( data[4]-48) ] );
shiftOut(LM_dataPin, LM_clockPin, MSBFIRST, seq[ int( data[2]-48) ] );
shiftOut(LM_dataPin, LM_clockPin, MSBFIRST, seq[ int( data[0]-48) ] );
digitalWrite(LM_latchPin, HIGH);
}



// LCDFunctionCall
// Prints to the LCD in format "(lineNumber) (textToBeWritten)"
////////////////////////////////////////////////////////////////////////
void LCDFunctionCall(char *data){
 

 char *ch;   // Pointer
  
 ch = strchr(data, ' ');        // Find 'space' and store posistion in ch
 if(ch) {                       // If space found
   *ch = '\0';                  // Convert to null character
   LCDClearLine(data[0] - 49);  // Clear line based on first char
   lcd.print(ch+1);             // Print rest of string

  }
              
}

// LCDClearLine
// Clears line and sets cursor to beginning of line
////////////////////////////////////////////////////////////////////////
void LCDClearLine(int lineToClear){
    lcd.setCursor(0, lineToClear);    
    lcd.print("                                        ");  
    lcd.setCursor(0, lineToClear);    
}


void loop() {
  
  
 if(Serial.available())   // If serial data is waiting to be read
  {
      serialInString[serialInStringPos] = Serial.read();  // Store data in string
      serialInStringPos++;
      
      if (serialInString[serialInStringPos - 1] == 59){   // If read Semi-Colon
        serialInString[serialInStringPos - 1] = '\0';     // Null terminate
        actionSerialString();                             // Perform action on data
      }
  }  
 
elapsedTime = millis(); // Store elapsed time
readMixerValues(); // Uses internal timer
//sendMixerValues();

}

« Last Edit: January 10, 2013, 06:37:18 pm by mibix » Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 601
Posts: 48543
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
char serialInString[250];   // Serial data string
Are you really expecting 250 character messages? That's using 1/8th of the memory on a 328-based Arduino.

Quote
Why is that a silly comment? Because I could have used the ASCII value instead of a character?
Because you used the ASCII value instead of the character. Why force people reading your code to check an ASCII table to make sure the code does what the comment says? Make the code clear so the comment is not needed.

Quote
Sorry didn't want to post 300 lines of code if it wasn't needed. Here it is...
The commented out code is clearly not related to the problem. Delete it.

The code in MLMFunctionCall posted here does not match the code in the snippet in the initial post. Why?
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 15
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
char serialInString[250];   // Serial data string
Are you really expecting 250 character messages? That's using 1/8th of the memory on a 328-based Arduino.
I hadn't changed it from first testing when string could have been very long.

Quote
Why is that a silly comment? Because I could have used the ASCII value instead of a character?
Because you used the ASCII value instead of the character. Why force people reading your code to check an ASCII table to make sure the code does what the comment says? Make the code clear so the comment is not needed.
Meant to say should not could. Yeah fair play, will update.

The code in MLMFunctionCall posted here does not match the code in the snippet in the initial post. Why?

That's because of bad snippets. My bad.  smiley-roll-sweat
Logged

Pages: [1]   Go Up
Jump to: