Generic Sketch

Hi All,
I want share with you, this sketch that I made for one project. In my project, I had hundreds micro controllers, each micro controller control (use digital or analog outputs) or monitor (used digital inputs) different devices. Number of devices that attached to each micro controller was different too.

First approach was, I have to write and manage hundreds different sketches.
Second approach was, make generic code that I can reused in all micro controllers.

Like a lazy person, I choose second way.

Five arrays at the beginning of sketch is only place where you adjust setting for each micro controller.
Length of arrays represent number of GPIOs that you want use in the specific micro controller.
Predefined type (GIO_Types) is what you want to do with the GPIO. GIO_Pins is array PIN numbers.

You can add more predefined functionalities to this example or use it AS IS, also you can use it a black box, only change setting in 5 arrays.
You can find complete example with HMI here

/*
   NOTE:
   All five arrays ( GIO_Names[],GIO_Types[], GIO_Pins[],GIO_Status[], GIO_prev_Satus) MUST be with the same size

   GIO_Names[]array - contain Arduino pin names, or variable names that can be shared  between YCS (Yedi Com Server) and Arduino App
   GIO_Types[]array

            "I+" input - INPUT
            "I-" input - INPUT_PULLUP
            "A" analog input
            "O" - output
            "OR" - output with on timer Reset. See "outputResetTime"
            "S" - output switch type, one click one, next click off
            "T" - output trigger type. See "triggerTime"
            "B" - Arduino internal read-write wariable.
   GIO_Pins[]array - Arduino PIN number
   GIO_Status[] array - Internal variable associated with the PIN
   GIO_prev_Satus[] array - Internal variable associated with the PIN
*/

String         GIO_Names[]       = {"Door1DPS", "Door2DPS", "GIO_6", "Door1LOK", "Door2LOK", "GIO_11", "GIO_12"}; 
String         GIO_Types[]       = {"I+",       "I+",       "T",     "OR",       "OR",       "O",      "O"};
int            GIO_Pins[]        = {2,          3,          6,       9,          10,         11,       12};
unsigned long  GIO_Status[]      = {0,          0,          0,       0,          0,          0,        0}; 
boolean        GIO_prev_Satus[]  = {LOW,        HIGH,       LOW,     LOW,        LOW,        LOW,      LOW}; 

// number of items in an array
#define NUMITEMS(arg) ((unsigned int) (sizeof (arg) / sizeof (arg [0])))

//Calculate array size
int arraySize = NUMITEMS(GIO_Names);
String serial_read = "";
int delayTime = 0;
unsigned long timeNow;
int triggerTime = 1000; //1sec
int outputResetTime = 1000; //1sec //if output become HIGH then reset it to LOW in THIS 1 second

/*
   Arduino UNO PIN numbers
  int GIO_2 = 2;//External Interrupts: pins 2 and 3. These pins can be configured to trigger an interrupt on a low value, a rising or falling edge, or a change in value.
  int GIO_3 = 3;//PWM: 3, 5, 6, 9, 10, and 11
  int GIO_4 = 4;
  int GIO_5 = 5;//PWM:(Pulse Width Modulation)
  int GIO_6 = 6;//PWM:
  int GIO_7 = 7;
  int GIO_8 = 8;
  int GIO_9 = 9;//PWM:
  int GIO_10 = 10;//PWM:
  int GIO_11 = 11;//PWM:
  int GIO_12 = 12;
  int GIO_13 = 13;//LED
  
  int AI_1 = 1;
  int AI_2 = 2;
  int AI_3 = 3;
  int AI_4 = 4;
  int AI_5 = 5;
  int AI_6 = 6;
*/

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  Serial.setTimeout(5); //Keep this number smaller

  //initialize generic IO
  setupGIOs();
}

void loop() {

  /*(1) read the String */
  serial_read = Serial.readString() ;

  //(2) Handle Inputs
  getGIOsAndAnalogInputs();

  //(3) Handle Outputs (Rx format - Name=Value - Ex. GIO_12=1  or GIO_5=0, etc)
  for (int i = 0; i < serial_read.length(); i++) {
    if (serial_read.substring(i, i + 1) == "=") {
      String firstVal = serial_read.substring(0, i);
      String secondVal = serial_read.substring(i + 1);
      setGIOsOutput( firstVal,  secondVal);
      break;
    }
  }
  //(4)delay Time
  delay(delayTime);
}

//Write to Serial Name=Value string
void getGIOsAndAnalogInputs() {
  //Read inputs
  boolean currentInputState = LOW;
  float floatAnalogInput;

  for (int i = 0; i < arraySize; i++) {
    //DIGITAL INPUT 
    //or 
    //DIGITAL  INPUT_PULLOUT
    if (GIO_Types[i] == "I-" || GIO_Types[i] == "I+") {
      currentInputState = digitalRead(GIO_Pins[i]);
      //if (currentInputState == true )
      if (digitalRead(GIO_Pins[i]) == HIGH )
      {
        Serial.println(GIO_Names[i] + "=1");
      }
      else if (digitalRead(GIO_Pins[i]) == LOW )
      {
        Serial.println(GIO_Names[i] + "=0");
      }
    
    //SWITCH INPUT
    } else if (GIO_Types[i] == "S") {

      if (  digitalRead(GIO_Pins[i]) == HIGH  )
      {
        GIO_Status[i] = 3;
      }

      // Activate switch logic when button pressed and GIO_Status[i] == 3
      if (digitalRead(GIO_Pins[i]) == LOW && GIO_Status[i] == 3) //On LOW Press, Button pressed
      {
        if (GIO_prev_Satus[i] == LOW) { //OFF
          Serial.println(GIO_Names[i] + "=1"); //Write 1st time
          GIO_prev_Satus[i] = HIGH;// Save previouse status
          delay(30); //delay between 1st and second writes
          Serial.println(GIO_Names[i] + "=1"); //Write 2nd time
          //digitalWrite(8, HIGH);
          GIO_Status[i] = 0; //increase counter
        }
        else if (GIO_prev_Satus[i] == HIGH &&  GIO_Status[i] == 3)//ON
        {
          Serial.println(GIO_Names[i] + "=0"); //Write 1st time
          GIO_prev_Satus[i] = LOW; // Save previouse status
          delay(30);  //delay between 1st and second writes
          Serial.println(GIO_Names[i] + "=0"); //Write 2nd time
          digitalWrite(8, LOW);
          GIO_Status[i] = 0;
        }
      }

    //ANALOG INPUT
    } else if (GIO_Types[i] == "A" ) {
      floatAnalogInput = analogRead(GIO_Pins[i]);
      //!!!! put your custom code here
      //(1)
      //LM35 TEMPERATURE SENSOR
      //T(°C)
      //floatAnalogInput =  floatAnalogInput * 0.48828125;
      //floatAnalogInput =  (floatAnalogInput*5.0*1000.0/1024.0)/10;
    
      //(2)
      //input mapping
      //floatAnalogInput = map(floatAnalogInput,0,1023,0,100);
      Serial.println(GIO_Names[i] + "=" + tempF);
    }
    
    //TRIGER
    else if (GIO_Types[i] == "T") {
      timeNow = millis();
      if (GIO_Status[i] == 0 || timeNow < GIO_Status[i] )
      {
        GIO_Status[i] = timeNow;
      }
      if (timeNow - GIO_Status[i] >= triggerTime  && digitalRead(GIO_Pins[i]) == HIGH )
      {
        digitalWrite(GIO_Pins[i], LOW);
        GIO_Status[i] = timeNow;
      }
      else if (timeNow - GIO_Status[i] >= triggerTime  && digitalRead(GIO_Pins[i]) == LOW )
      {
        digitalWrite(GIO_Pins[i], HIGH);
        GIO_Status[i] = timeNow;
      }
    }
    //RESET OUTPUT
    if (GIO_Types[i] == "OR" && GIO_prev_Satus[i] == HIGH)
    {
      if (millis() - GIO_Status[i] > outputResetTime ) {
        Serial.println(GIO_Names[i] + "=0"); //Reset
        GIO_prev_Satus[i] = LOW;
        //Serial.println("RESET OUTPUT");
      }
    }
  }
}
//Activate/Deactivate Output
void setGIOsOutput(String _name, String _value) {
  //initialize generic IO
  for (int i = 0; i < arraySize; i++) {
    if ( GIO_Types[i] == "O" || GIO_Types[i] == "OR")
    {
      if (_name == GIO_Names[i]) {
        if (_value == "0") {
          digitalWrite(GIO_Pins[i], LOW);
          //this setting used by "OR" only
          GIO_prev_Satus[i] = LOW;
          //  Serial.println("LOW");

        } else if (_value == "1") {
          digitalWrite(GIO_Pins[i], HIGH);
          //these two setting used by "OR" only
          GIO_prev_Satus[i] = HIGH;
          GIO_Status[i] = millis();
          // Serial.println("HIGH");
        }
        break;
      }
    }
  }
}

// Set GIO Type Input or Output
// This function asigned INPUT or OUTPUT GIO type based on internal Types "I", "O", "S", "T" (See GIO_Types[])
void setupGIOs() {
  //initialize generic IO
  for (int i = 0; i < arraySize; i++) {
    if (GIO_Types[i] == "O" || GIO_Types[i] == "OR" || GIO_Types[i] == "T") {
      pinMode(GIO_Pins[i], OUTPUT); //OUTPUT //digitalWrite()
    } else if (GIO_Types[i] == "I-" || GIO_Types[i] == "S") {
      pinMode(GIO_Pins[i], INPUT_PULLUP); //INPUT  //digitalRead()
    } else if (GIO_Types[i] == "I+") {
      pinMode(GIO_Pins[i], INPUT); //INPUT  //digitalRead()
    }
  }
}

What was your project?

Probably, my project deserves separate thread, but here, lets discus, how to build generic reusable code for Arduino. Big project, small project, doesn’t matter generic thinking can be implemented anywhere. I am sure; you have something in your pocket. Show it.

Let call this post – project "Generic Solution", of cause it is not 100% generic, but reusable for sure.