// This arduino code runs the pump and stirrer module // Communication is based on https://forum.arduino.cc/t/serial-input-basics-updated/382007 // Pin definitions #define DIRA_fill A3 #define DIRB_fill A2 #define ENABLE_fill 3 #define DIRA_drain 2 #define DIRB_drain 4 #define ENABLE_drain 5 #define DIRA_reactor A1 #define DIRB_reactor A0 #define ENABLE_reactor 6 #define DIRA_bath 7 #define DIRB_bath 8 #define ENABLE_bath 9 // Global variables int last_time = 0; //last time measurement data was sent by the arduino in s int time = 0; //actual time int timeinterval = 1; //time interval in which measurements should be made and their data sent const byte numChars = 32; // number of characters in the message received from the PC. Can be much bigger, because the buffer is cleared before it is full char receivedChars[numChars]; // Array for received characters char tempChars[numChars]; // temporary array for use when parsing to not change the original data receivedChars // variables to hold the parsed data // The received data has the format "" with the name of the arduino and the actor, whichs value should be changed to the actorvalue char Arduino[numChars] = {0}; // Variable for the name of the arduino, whichs actors should act char Actor[numChars] = {0}; // Variable for the name of the actor, whichs value should be changed int Actorvalue = 0; // Variable for the value the actor should be changed to boolean NewInstructions = false; // Indicates if message is completely received // Setup of pin's and communication void setup() { pinMode(DIRA_fill,OUTPUT); pinMode(DIRB_fill,OUTPUT); pinMode(ENABLE_fill,OUTPUT); pinMode(DIRA_drain,OUTPUT); pinMode(DIRB_drain,OUTPUT); pinMode(ENABLE_drain,OUTPUT); pinMode(DIRA_reactor,OUTPUT); pinMode(DIRB_reactor,OUTPUT); pinMode(ENABLE_reactor,OUTPUT); pinMode(DIRA_bath,OUTPUT); pinMode(DIRB_bath,OUTPUT); pinMode(ENABLE_bath,OUTPUT); Serial.begin(9600); } // Main loop running continuously void loop() { ReceiveInstructions(); // the ReceiveInstructions function is defined below and receives the instructions from the PC to the arduino using serial communication if (NewInstructions == true) { //if new instructions have been received ExecuteInstructions(); // execute the instructions by setting the values of the actors. The ExecuteInstructions function is defined below NewInstructions = false; //set the variable to show, that the instructions have been executed } //time = millis()/1000; // calculate actual time in s //if((time-last_time)>=timeinterval){ // check if it is time to send new measurement data // SendData(); // send the data using the SendData function defined below // last_time = time; // remember the last time data has been sent //} } void ReceiveInstructions() { //receives the instructions from the PC to the arduino using serial communication static boolean recvInProgress = false; //indicates if startMarker has been received and message is collected static byte ndx = 0; //index for the char array char startMarker = '<'; //startMarker for the array char endMarker = '>'; //endMarker for the array "New Line" in arduino IDE serial monitor puts a '\n' at the end of each message as endMarker char rc; // single received character which is put into the receivedChars array while (Serial.available() > 0 && NewInstructions == false) { //if new data is available and the message is not completed rc = Serial.read(); //read single character from buffer if (recvInProgress == true) { //if the start marker has been received and the message is now collected if (rc != endMarker) { //if the received character is not the endMarker receivedChars[ndx] = rc; //attach the character to the array ndx++; //increase index of the received character array if (ndx >= numChars) { //check that not too many characters have been received ndx = numChars - 1; } } else { //if the received character is the endMarker receivedChars[ndx] = '\0'; // terminate the string recvInProgress = false; //set the indicator that the message is completely received ndx = 0; //reset the array index NewInstructions = true; //set the indicator that the data can be displayed } } else if (rc == startMarker) { //if the received character is the startMarker recvInProgress = true; //set the indicator that the characters should be collected to the message } } } void ExecuteInstructions() { //process the received data and execute the instructions // Parse the received Data into it's components char * strtokIndx; // char * is a pointer (the memory adress for char data) this is used by strtok() as an index strcpy(tempChars, receivedChars); //copies the string in receivedChars into tempChars // this temporary copy is necessary to protect the original data // because strtok() used in parseData() replaces the commas with \0 strtokIndx = strtok(tempChars,","); // strtok splits a string (tempChars) into pieces (tokens) using a delimiter (,). it replaces the delimiter with \0 (NULL) and returns the pointer to the next token each time it is called strcpy(Arduino, strtokIndx); // copy it to messageFromPC strtokIndx = strtok(NULL, ","); // this continues where the previous call left off strcpy(Actor, strtokIndx); // copy it to messageFromPC strtokIndx = strtok(NULL, ","); // this continues where the previous call left off Actorvalue = atoi(strtokIndx); // convert this part to an integer // Execute the received instructions if (strcmp(Arduino,"Ard_Pump_Stirr")==0){ if (strcmp(Actor,"fill")==0){ if (Actorvalue == 0){ digitalWrite(DIRA_fill,LOW); digitalWrite(DIRB_fill,LOW); analogWrite(ENABLE_fill,0); } else if (Actorvalue > 0){ digitalWrite(DIRA_fill,HIGH); digitalWrite(DIRB_fill,LOW); Actorvalue = map(Actorvalue,0,100,230,255); // map the entry in % power to the value used to run the analog output Actorvalue = constrain(Actorvalue,0,255); // constrain the value to possible outputs analogWrite(ENABLE_fill,Actorvalue); } else if (Actorvalue < 0){ digitalWrite(DIRA_fill,LOW); digitalWrite(DIRB_fill,HIGH); Actorvalue = map(Actorvalue,0,-100,230,255); // map the entry in % power to the value used to run the analog output Actorvalue = constrain(Actorvalue,0,255); // constrain the value to possible outputs analogWrite(ENABLE_fill,Actorvalue); } } if (strcmp(Actor,"drain")==0){ if (Actorvalue == 0){ digitalWrite(DIRA_drain,LOW); digitalWrite(DIRB_drain,LOW); analogWrite(ENABLE_drain,0); } else if (Actorvalue > 0){ digitalWrite(DIRA_drain,LOW); digitalWrite(DIRB_drain,HIGH); Actorvalue = map(Actorvalue,0,100,217,255); // map the entry in % power to the value used to run the analog output Actorvalue = constrain(Actorvalue,0,255); // constrain the value to possible outputs analogWrite(ENABLE_drain,Actorvalue); } else if (Actorvalue < 0){ digitalWrite(DIRA_drain,HIGH); digitalWrite(DIRB_drain,LOW); Actorvalue = map(Actorvalue,0,-100,217,255); // map the entry in % power to the value used to run the analog output Actorvalue = constrain(Actorvalue,0,255); // constrain the value to possible outputs analogWrite(ENABLE_drain,Actorvalue); } } if (strcmp(Actor,"reactor")==0){ if (Actorvalue == 0){ digitalWrite(DIRA_reactor,LOW); digitalWrite(DIRB_reactor,LOW); analogWrite(ENABLE_reactor,0); } if (Actorvalue == 1){ digitalWrite(DIRA_reactor,HIGH); digitalWrite(DIRB_reactor,LOW); analogWrite(ENABLE_reactor,255); } } if (strcmp(Actor,"bath")==0){ if (Actorvalue == 0){ digitalWrite(DIRA_bath,LOW); digitalWrite(DIRB_bath,LOW); analogWrite(ENABLE_bath,0); } if (Actorvalue == 1){ digitalWrite(DIRA_bath,HIGH); digitalWrite(DIRB_bath,LOW); analogWrite(ENABLE_bath,255); } } } } void SendData() { //sent the acutal timestamp and the measurement values from the arduino to the pc Serial.print(time); Serial.print(','); Serial.println(analogRead(0)/1023.0); }