Arduino and Processing. How to control a microcontroller via a COM port. Two way communication

Hello! There is a misconception on the Internet that to control a computer using home-made electronics, only special boards are needed that can be recognized as USB HID devices. And with regards to Arduino, everyone just talks about Arduino Leanardo . Such popular libraries as Keyboard and Mouse , which allow you to create emulation of the mouse or keyboard using the microcontroller, are intended only for a pair of Arduino, Leonardo boards, among them.

I’ll talk about how to connect any Arduino microcontroller (for example, taken Arduino Uno) and its Processing program. Having added to everything else the knowledge of Java, on which Processing is based, it will be possible to add a project under the control of the entire computer, and not just its own application. The topic of controlling a computer program in Java is not something secret, google and you will find everything, I assure you.

Download Development Environment (IDE)


There are many integrated development environments for programming microcontrollers in pure C. Of these, the most convenient can be noted: Atollic, Eclipse, Keil.

However, for the simplicity and accessibility of this guide, I will use the Arduino IDE editor and write in Arduino C. You can download such an editor from the Arduino official website .

The development environment for programming on Procrssing can also be downloaded from the official website .

It is worth noting, for the sake of decency, that the IDE data are very similar, because they are written on the same engine. And when Arduino was created, the founders tried to simplify their code editor as much as possible, as was done in the Processing editor.

Arduino We assemble the circuit and write the code


In this example, I will use Arduino Uno. A button, a potentiometer and an LED will be connected to it. Accordingly, I can output a logical 0 or 1. Read a logical 0 or 1. And perform an Analog-Digital conversion (ADC or ADC), getting numbers from 0 to 1023 (in the Arduino Uno a 10-bit ADC) depending on the position of the potentiometer. You don’t need much more for an example, since these are the main functions that a microcontroller can do.

Wiring diagram:



In the diagram, the anode LED is connected to 5V via a limiting resistor (minimum 220 Ohms, preferably 500 Ohms), by the cathode to pin D11. The button closes the ground and pin D2. Potentiometer changes potential on pin A1.

The task of the microcontroller is as follows: If the message “LED - H” arrives on the serial interface (Serial COM port) - light up the LED. If the message “LED - L” arrives, extinguish the LED. Every 250ms send a message to the serial port (in this case, to the computer screen) the message “Pot -” and the number received by analog reading of pin A1. When a button is pressed, send a message “Button is pressed!” Once.

Here is my suggestion for solving this problem (not an example to follow):

Firmware for Arduino Uno
#define pinPot A1
#define pinLed 11
#define pinBtn 2
void setup() {
  pinMode(pinPot, INPUT);
  pinMode(pinLed, OUTPUT);
  pinMode(pinBtn, INPUT_PULLUP);
  Serial.begin(9600);
  Serial.println("The program starts.\n\n");
}
void loop() {
  /* INITIAL VARIABLES. Segment 1 */
  static char potMes[]  = "Pot - ";
  static char btnMes[] = "Button is pressed!";
  static char passLight[] = "Led - ";
  static int passLength = sizeof(passLight) - 1;
  static int sizepm = sizeof(potMes) - 1;
  static int sizebtn = sizeof(btnMes) - 1;
  static bool flagLedState = LOW;
  static bool flagBtnPress = false;
  static long int curTime = 0;
  static const int period = 200; 
  static bool flagEnableRead = false;
  /* INITIAL VARIABLES. Segment 1 */
  /* FUNCTIONS CALL. Segment 2 */
  /*
   * Led is attached to HIGH voltage from one side
   * And to pin on the other side
   * By that the inverting logic
   */
  ReadSerialForLed(passLight, passLength, &flagLedState);
  digitalWrite(pinLed, !flagLedState);
  /*
   * Button pin always is pulled to the HIGH voltage
   * And only when button is pressed - Voltage on pin goes to GROUND
   * So it is need to invert logic when read pins 
  */
  if(!Bounce(pinBtn) && flagBtnPress == false){
    for(int i = 0; i < sizebtn; i++){
       Serial.write(btnMes[i]);
    }
    Serial.print("\n");
    flagBtnPress = true;
    if(!flagEnableRead){
      curTime = millis();
      flagEnableRead = true;
    }
  }else if(Bounce(pinBtn)){
    flagBtnPress = false;
  }
  /*
   * Read and send Info "Pot - " + var Only after first press on button
   * Every 'period'ms
   */
  if(millis() - curTime > period && flagEnableRead){
    SendData(pinPot, potMes, sizepm);
    curTime = millis();
  }
  /* FUNCTIONS CALL. Segment 2 */
}
/*
 * Pot - pin with potentiometer
 * pMes - Array with message before Pot value
 * sp - size of potentiometer message
 */
void SendData(int Pot, char* pMes, int sp){
  static int varP[2];
  varP[0] = analogRead(Pot);
  varP[1] = varP[0]/256; // 0 - 3 (256 - 1024)
  varP[0] = varP[0]%256; // 0 - 255
  //Send Message
  for(int i = 0; i < sp; i++){
    Serial.write(char(pMes[i]));
  }
  //Send 2 bits of data
  //Serial.write(varP[0]);
  //Serial.write(varP[1]);
  Serial.print(analogRead(Pot));
  Serial.print("\n");
}
/*
 * Function, which is reads button pin with the bounce
 */
bool Bounce(int btn){
  if(digitalRead(btn) == true){
    delay(15);
    if(digitalRead(btn) == true){
      return true;
    }else{
      return false;
    }
  }else{
    return false;
  }
}
/*
 * If Message from Serial port, which you read will be the same to passLight
 * So look at the next symbol after Pass Message. If it is symbol 'H' - make LED to light
 * If it is 'L' - make LED off.
 */
void ReadSerialForLed(char *passLight_f, int passLength_f, bool* flagLedState_f){
  static char sym;
  static int cntPass = 0;
  static bool readyGetLed = LOW;
  while (Serial.available() > 0) {
    sym = Serial.read();
    if(sym == passLight_f[cntPass] && !readyGetLed){
      cntPass++;
    }else if (!readyGetLed){
      cntPass = 0;
    }else if(readyGetLed){
      if(sym == 'H'){
        *flagLedState_f = HIGH;
      }else if(sym == 'L'){
        *flagLedState_f = LOW;
      }
    }
    if(cntPass == passLength_f){
      readyGetLed = HIGH;
    }
  }
}

Comment: The LED is connected to the power supply by the anode. This inverts the logic of the state of the LED and no longer benefits. The button is not tied up with a pull-up resistor for reasons of economy, since Arduino Uno has built-in pull-up resistors that are included in the circuit when the pin is initialized to INPUT_PULLUP mode.
Also in the firmware, messages about the value taken from the potentiometer are sent only after the first press of a button!


To fill the firmware in the board, do not forget to select the port and the board.



If you don’t know which COM port is allocated for the Arduino board, then on Windows go to
Control Panel -> Device Manager and click on the “COM Ports” tab



If your COM port is not signed as mine, you can always disconnect the Arduino and see which port is gone. But if no one has disappeared and Arduin is not recognized by the computer at all, then it's time to look for a solution on the Internet. But start by updating the drivers or changing the board.

When everything works out, try opening the port monitor and entering “Led-H”, “Led-L”, press the button, turn the potentiometer and look at the screen to see if everything is displayed correctly.

Have played enough - slightly change the code.

Replace the last line with the code from the comment.

  //Send 2 bits of data
  //Serial.write(varP[0]);
  //Serial.write(varP[1]);
  Serial.print(analogRead(Pot));

Now the values ​​from the potentiometer will not look readable, but such a maneuver is required for the Processing program.

Processing. We are writing a program that interacts with a microcontroller


The essence of communication between the Processing program and the microcontroller is very simple. For this programming language, there is a Serial library that allows you to receive messages sent as Serial.write();, and also allows you to send messages as Serial.print();. It is important to note that with such a message sent, it will be written to the port buffer, which means it will be read by the microcontroller. So we just have to connect to the desired Serial port and receive / send messages to it.

The following program will connect the Serial library and write in the editor console a list of all COM ports that you can connect to.

import processing.serial.*;
void setup()
{
  String[] port = Serial.list();
  for(int i = 0; i < port.length; i++){
    print("Port number #" + i + "  ");
    println(Serial.list()[0]);
  }
}
void draw() {}

When you write the code to the editor and click on the “Start” button (arrow 1 in the picture), the application window will appear (2) and the list of COM ports will be displayed in the console (3).



I have only one such COM port and in the sheet, as in the array, it will be at number 0. For these reasons, the object of the Serial class: Serial port;when it is created, it will be specified the first element of the list of ports. port = new Serial(this, Serial.list()[0], 9600);

Pour in Arduina our latest firmware with the change. Then write this program and run it. In it Every 500 milliseconds a message is sent to the COM port to put out or light up the LED. And if everything is done correctly, then after starting the application the LED should blink.

import processing.serial.*; 
Serial port;  // Create object from Serial class
void setup(){
  port = new Serial(this, Serial.list()[0], 9600); 
}
void draw(){
  delay(500);
  port.write("Led - H");
  delay(500);
  port.write("Led - L");
}

Or here is another example. The LED will change its state after any click on the application window (whose dimensions are 800x800px) with the mouse button.

import processing.serial.*; 
Serial port;  // Create object from Serial class
int cnt = 0;
void setup(){
  size(800, 800);
  port = new Serial(this, Serial.list()[0], 9600); 
}
void draw(){}
void mousePressed() {
  cnt++;
  if(cnt % 2 == 1){
    port.write("Led - H");
  }else{
    port.write("Led - L");
  }
}

Processing. Feature rich application example


This elementary application simulates a "flight in space", if you can call it that. The value from the potentiometer changes the flight speed, pressing the button changes the direction of flight. And any click of the mouse button on the application window changes the state of the LED (yes, I didn’t come up with anything more original).

My code is far from perfect, do not take it as a good example. This is just an example that works. Here he is.

Example multifunctional program
import processing.serial.*; 
Serial port;  // Create object from Serial class
int val;      // Data received from the serial port (symbol)
int pot;      // Data from potentiometer
String potMes  = "Pot - "; 
String btnMes = "Button is pressed!";
int cntPM = 0; // Counter Potentiometer Message. 
               // When it equals to length of Pot Mess - get value.
int cntBM = 0;
int cntBtnPress = 0;
int cntMousePress = 0;
Star[] stars = new Star[1000];
float speed;
int dir = 1;
void setup(){
  size(800, 800);
  for(int i = 0; i < stars.length; i++){
    stars[i] = new Star();
  }
  frameRate(60); // 60 Frames per second
  port = new Serial(this, Serial.list()[0], 9600); 
  // Wait for first message from Arduino
  delay(2000);
  while (port.available() > 0) {   
    val = port.read();            
    print(char(val));
  } 
}
void draw(){
   if (port.available() > 0) {     
    val = port.read();            
    cntPM = CheckSymbol(potMes, cntPM, char(val), cntPM);
    cntBM = CheckSymbol(btnMes, cntBM, char(val), cntBM);
  } 
  DrawRain(pot, 0, 1023);
}
void DrawRain(int speed_f, int min, int max){
  background(0);
  translate(width/2,height/2);
  speed = dir*map(speed_f, min, max, 0, 50);
  for(int i = 0; i < stars.length; i++){
    stars[i].go();
    stars[i].update();
    stars[i].show();
  }
}
int CheckSymbol(String mes, int index, char sym, int ret_val){
  if(mes.charAt(index) == sym && ret_val < (mes.length() - 1)){
    return (ret_val + 1);
  }else if( ret_val == (mes.length() - 1) && mes.equals(potMes) ){
    if(port.available() > 0){
      pot = port.read();            // First 0-255 value
    }
    if(port.available() > 0){
      pot += 256*port.read();       // Last 2 bits 256 - 1024
    }
  }else if( ret_val == (mes.length() - 1) && mes.equals(btnMes) ){
    cntBtnPress++;
    dir = -dir;
  }
  return 0;
}
void mousePressed() {
  cntMousePress++;
  if(cntMousePress % 2 == 1){
    port.write("Led - H");
  }else{
    port.write("Led - L");
  }
}

Conclusion


I think I need to write that I picked up the idea of ​​the last program from one programmer - Daniel Shiffman , who shoots videos that are understandable even to children about programming on Processing ( more than 140 visual tasks have been solved ).

When I tried to figure out what and how to do the Processing and Arduino communications myself, these sites really helped me:

  1. developer.alexanderklimov.ru/arduino/processing.php
  2. arduino-diy.com/arduino-processing-osnovi

Also popular now: