>> Arduino Communicator >> Microcontroller Setup


MICROCONTROLLER SETUP


Working Principle

To establish communication with the Arduino, it needs to be connected to the computer via a USB cable. Once the connection is established, the software maintains a list of commands that you provide. It sends the first command to the Arduino for execution and waits for a response sign from the Arduino before proceeding to the next command. This process continues until the entire list of commands is completed.

A command sent to the Arduino has the following format: d5000#. The first letter of the command (in this case, d) specifies the function to be called in the Arduino code. For example, it could be a delay function that instructs the Arduino to wait for a specific time span. The subsequent characters represent parameters that provide additional information to the Arduino function. In this example, 5000 represents 5000 milliseconds.
The last character, #, indicates the completion of the command transfer to the Arduino. It signals that the Arduino can now execute the function and process the provided parameter.

The command d5000# hence calls the delay function in the Arduino code, passing it the value 5000. The Arduino will then wait for 5000 milliseconds before proceeding with its next task. Once the Arduino completes its task, it sends the character * to the software as a notification. Upon receiving this character, the software proceeds to send the next command from the command list to the Arduino. This sequential process ensures that the commands are executed step by step.





The Arduino Sketch

Well, there is no working with an Arduino without a little programming. To facilitate it, you will find a basic template for the Arduino code here below. I suggest using the Arduino IDE for the Arduino setup. The sketch has a setup function that is called when the Arduino is started. At this stage, some configuration parameters are set. The constant BUFFER_SIZE defines the maximum size of the buffer used to store received characters, while BIT_RATE sets the baud rate for the serial communication.


The sketch utilizes various variables:

Buffer:   Array used to store received characters.
helpBuffer:   Temporary buffer for argument handling.
positionOfEndChar:   Length of the incoming command.
bufferIndex:   Current writing position in the Buffer array.
receivedChar:   Most recently received character.
EndChar:   Final character of an incoming string (set to #).
ReturnChar:   Final return character (set to *).
resetChar:   Character indicating to clean the current buffer immediately (set to %).

The Buffer serves as storage for the received characters, while helpBuffer acts as a temporary buffer for handling arguments. The remaining variables control the program flow and handle the received characters.

In the setup section of the program, the bufferIndex is set to 0 to reset the writing position in the buffer. The built-in LED is defined as an output for later toggling. Serial communication is started with the specified baud rate.

The main part of the program, the loop() function, runs continuously. It checks for new characters available from the computer. If new characters are available, the most recently received character is read and passed to the receiveAndStoreChar() function for processing.

The receiveAndStoreChar() function handles the received characters. It skips invalid characters such as newline and -1. If the received character matches the EndChar, it indicates that the full command has been received. The length of the command is stored in positionOfEndChar, and the Distributor() function is called. Otherwise, the character is added to the buffer, and the bufferIndex is incremented. If the command length exceeds the buffer size, an error message is sent, and the buffer is cleared.

The Distributor() function is responsible for executing the appropriate actions based on the received command. It checks the first character of the incoming command and calls the corresponding function.

After executing the action, the ReturnChar (*) is sent as the end character to indicate that the command has been processed. The buffer is then cleared to be ready for the next command.

In this sketch, there are three pre-defined functions I recommend not to delete:

• If the command starts with ?, the Identify() function is called to send back the Arduino identification string.
• If the received character matches the resetChar (%), the buffer is immediately cleared, even without the command end character (#). This ensures that the Arduino can be reset in case of trouble.
• The delay function sets the Arduino into delay state for a given time (parameters in milliseconds).

In addition, one exemplary function is added. If the command starts with e, the built-in LED will be turned on or off, depending on the parameter. I suggest adding own functions at the end of the sketch. Make sure to also add them to the Distributor() function.


Arduino sketch: (Download)

// DEFINITIONS
#define BUFFER_SIZE 128    // All these variable names will be replaced by these values
#define BIT_RATE 9600

// VARIABLES
char Buffer[BUFFER_SIZE];       // Buffer for storage of received chars
char helpBuffer[BUFFER_SIZE];   // Help buffer for argument handling
short positionOfEndChar;        // Length of incoming command
short bufferIndex;              // current writing position in Buffer
char receivedChar;              // Incoming char
char EndChar = '#';             // Final char of an incoming string
char ReturnChar = '*';          // Final return char
char resetChar = '%';           // Char telling to clean current buffer immediately




// SETUP
void setup()
{
  bufferIndex = 0;   // Set buffer reading position to 0
  pinMode(LED_BUILTIN, OUTPUT);
  Serial.begin(BIT_RATE);  // Start connection
}


// LOOP looking for new signs from computer
void loop()
{
  while (Serial.available() > 0)    // if there are new signs from computer
  {
	receivedChar = Serial.read();         // read it
	receiveAndStoreChar(receivedChar);
  }
}


// Received character handling
void receiveAndStoreChar(char _receivedChar)
{
  // Skip invalid chars
  if(_receivedChar == '\n') return;
  if(_receivedChar == -1) return;
  

  // Look at received char
  if(_receivedChar == EndChar)
  {
	// If EndChar, the full command has been received. Save Length of command and call Distributor function.
	positionOfEndChar = bufferIndex;
	Distributor();
  }
  else if(_receivedChar == resetChar)
  {
	// If reset char, reset buffer
	ClearBuffer();
  }
  else
  {
	// If any other valid char, add to buffer and increment buffer index variable
	Buffer[bufferIndex] = receivedChar;
	bufferIndex++;

	// If the command length exceeds the buffer size, send an error message and clear buffer.
	if (bufferIndex >= BUFFER_SIZE)    
	{
	  Serial.print("Cmd length error!");
	  ClearBuffer();
	}
  }
}


// Buffer clearage and buffer index reset
void ClearBuffer()
{
  memset(Buffer, 0, sizeof(Buffer));
  bufferIndex = 0;
}


// Command Function caller
void Distributor()    // Looks at the first char of the incoming command (i.e. the buffer) and calls the corresponding function
{
  bufferIndex = 0;
  switch(Buffer[0])   // Buffer[0] = first sign of the command
  {
	case '?':     // arduino self identification
	  Identify();
	  break;

	case 'd':     // delay
	  Delay();
	  break;

	case 'e':     // example function
	  Example();
	  break;
	  
	default:      // error message if unknown command type
	  Serial.print("undef: '");
	  Serial.print(Buffer[0]);
	  Serial.print("'");
	break;
  }

  ClearBuffer();  // Clears Buffer to be ready for next command

  Serial.print(ReturnChar);   // Return end char to tell that command has been worked off

}


/* APPLICATION FUNCTIONS */
/* --------------------- */

// Sends the arduino identification string as reply
void Identify()     
{
	Serial.print("arduino"); 
}


// Executes system delay
void Delay()
{
  for(int x = 1; x < positionOfEndChar; x++) helpBuffer[x-1] = Buffer[x];   // Shift Argument to new buffer
  helpBuffer[positionOfEndChar] = '\0';      // Add end character to new buffer
  delay(atoi(helpBuffer));                   // Transfer new buffer to int and delays (in ms)
}


// turns on built-in LED if second char is '0', else turns it off
void Example()
{
  if(Buffer[1] == '0')
  {
	digitalWrite(LED_BUILTIN, HIGH);
  }
  else
  {
	digitalWrite(LED_BUILTIN, LOW);
  }
}

René Riedel, 8th July 2023.