Aiuto a pulire il codice

Allora il programma che descrivi si può realizzare in questo modo:

void setup(){
 Serial.begin(9600);
 pinMode(13, OUTPUT);
 pinMode(12, OUTPUT);
 Serial.println("inserisci comando (a,b,c,o,...)");
}

void loop(){
  if(Serial.available()){
    char c = Serial.read();
    
    switch(c)
    {
      case 'a':
        funzione_a();
        break;
        
      case 'b':
        funzione_b();
        break;
        
      case 'c':
        funzione_c();
        break;
        
      case 'o':
        funzione_o();
        break;
        
      default:
        funzione_default();
      break;  
    }
  }
}


void funzione_a(){
  Serial.println("sei nella funzione a");
  while(1){
    if(Serial.available()){
      break;
    }
    digitalWrite(12, HIGH);
    delay(100);
    digitalWrite(12, LOW);
    delay(100);
  }
}

void funzione_b(){
   Serial.println("sei nella funzione b");
    while(1){
      if(Serial.available()){
        break;
      }
      digitalWrite(12, HIGH);
      delay(500);
      digitalWrite(12, LOW);
      delay(500);
    }
}

void funzione_c(){
   Serial.println("sei nella funzione c");
    while(1){
      if(Serial.available()){
        break;
      }
      digitalWrite(12, HIGH);
      delay(1000);
      digitalWrite(12, LOW);
      delay(1000);
    }
}
void funzione_o(){
  Serial.println("sei nella funzione o");
  digitalWrite(12, LOW);
  digitalWrite(13, LOW);
}

void funzione_default(){
  Serial.println("sei nella funzione default, valore non riconosciuto");
  digitalWrite(12, HIGH);
  digitalWrite(13, LOW);
}

Come vedi fa uso del costrutto switch, della comunicazione seriale e delle funzioni che chiedi di implementare.

Partiamo dal costrutto switch, questa struttura ti permette di prendere delle decisioni in base al valore di una variabile, è un pò come il costrutto if/else annidato ma meno complesso nella gestione, il suo funzionamento si basa sulla comparazione di una variabile con i diversi casi previsti nel costrutto, la struttura è:

switch(a) {  // 'a' è la variabile di controllo
  
   case '1':  // se la variabile a è uguale a '1' allora lo switch seleziona il caso 1 ed esegue il codice al suo interno
   //codice da eseguire
   break;

   case '2':  // se la variabile a è uguale a '2' allora lo switch seleziona il caso 2 ed esegue il codice al suo interno
   //codice da eseguire
   break;
   
   default:  // se la variabile a non è uguale a nessuno dei casi previsti allora lo switch esegue ciò che si trova nel blocco defaultì
   //codice da eseguire
   break;
}

L'istruzione break serve per uscire dal caso specifico dello switch dopo aver eseguito il codice ad esso associato.

La comunicazione seriale è più complessa da spiegare in due parole, però come puoi comprendere almeno per adesso noi la usiamo per comunicare con il pc e mandare messaggi ad arduino.
Per poterla usare occorre inizializzare la connessione con Serial.begin(9600); nella funzione setup e rispettare il baud rate, cioè quel numero 9600 come parametro della Serial.begin(), ciò significa che quando usi il serial monitor nell'ide di arduino in basso a destra della finestra del terminale dovrai settare il valore del baud rate a 9600.

Ora veniamo al programma, dopo aver inizializzato la connessione seriale nella funzione setup e impostato i pin di output per gestire i led, stampiamo via seriale il messaggio che avvisa l'utente che è tutto pronto per iniziare a ricevere comandi.
Passiamo alla funzione loop, qui la prima cosa da fare e capire se c'è qualche carattere scritto via seriale con la funzione Serial.available() che restituisce true come valore logico se abbiamo inviato qualche carattere ad arduino, a questo punto dobbiamo capire di che carattere si tratta e quindi leggerlo con la funzione Serial.read(); che restituisce appunto il carattere letto sulla seriale, lo salviamo in una variabile 'char c' e successivamente lo processiamo con lo switch per capire come comportarci.
Nei casi previsti dallo switch ci sono i caratteri a, b, c, o, se lo switch rileva uno di questi caratteri avviera la sua funzione associata presente nella parte finale del codice dopo il loop. Se lo switch riceve un qualsiasi carattere non presente tra i suoi casi avviera il blocco default e la sua relativa funzione associata.

Questo è quanto, ovviamente non commento le funzioni perchè elementari si tratta di far lampeggiare un led con frequenze diverse gestite con la funzione delay, però l'unica cosa che voglio farti notare è che se non digiti altri caratteri rimani fermo all'interno dell'ultima funzione chiamata, questo perchè ho usato un cilco while(1) che è infinito come la funzione loop, ne esci solo quando sulla seriale arduino trova un altro carattere da processare è questo comportamento lo implementi con l'istruzione:

if(Serial.available()){
      break; //se si invia un carattere alla seriale il break viene eseguito ed esci dal cilco while(1)
    }

Spero di essere stato chiaro, guardati un pò il codice e cerca di capire come funziona, se hai altri dubbi chiedi pure.
Ciao