// https://www.plcforum.it/f/topic/317579-programma-per-realizzare-4-uscite-random-con-arduino


// Definizioni ingressi/uscite/livelli
#define PIN_PULS     A0
#define PRESS_LEVEL  HIGH  // livello letto a pulsante premuto

#define PIN_R1       5
#define PIN_R2       4
#define PIN_R3       3
#define PIN_R4       2
#define ON_LEVEL     HIGH  // livello accensione elemento esterno

#define PIN_ANALOG   A1    // In analogico da lasciare scollegato


// Variabili usate nel programma
int8_t  xin = 0;   // shift register per debounce
bool    xq  = 0;   // ingresso pulsante filtrato
bool    xqp = 0;   // flag per P-edge detect
uint8_t n;         // numero random estratto
uint8_t np  = ~n;  // numero random precedente

//----------------------------------------

void randomize(uint8_t pin) {
    uint32_t seed;

    // Crea un seed non deterministico
    // da rumore su ingresso analogico
    for (uint8_t n=0; n<7; n++) {
        for (uint8_t m=0; m<50; m++)
            seed += analogRead(pin);
        seed <<= 4;
    }

    // Imposta punto di partenza casuale nella
    // sequenza di valori pseudo casuali
    randomSeed(seed); 
}

//----------------------------------------

void setup() {
    pinMode(PIN_PULS, INPUT);

    pinMode(PIN_R1, OUTPUT);
    digitalWrite(PIN_R1, !ON_LEVEL);    

    pinMode(PIN_R2, OUTPUT);
    digitalWrite(PIN_R2, !ON_LEVEL);    

    pinMode(PIN_R3, OUTPUT);
    digitalWrite(PIN_R3, !ON_LEVEL);    

    pinMode(PIN_R4, OUTPUT);
    digitalWrite(PIN_R4, !ON_LEVEL);   

    randomize(PIN_ANALOG);
}

//----------------------------------------

void loop() {
    // debounce 50 ms
    xin = ((xin << 1) & B111111) | (digitalRead(PIN_PULS) == PRESS_LEVEL);
    xq = (B111111 == xin) ? 1 : (0 == xin) ? 0 : xq;

    // P-edge detect
    if (xq && !xqp) {

        // Estrae nuova combinaz. diversa da precedente
        for (n = random(4);  n == np;  n = random(4));
        np = n;

        // Aggiorna uscite
        digitalWrite(PIN_R1, 0==n ? ON_LEVEL : !ON_LEVEL);     
        digitalWrite(PIN_R2, 1==n ? ON_LEVEL : !ON_LEVEL);     
        digitalWrite(PIN_R3, 2==n ? ON_LEVEL : !ON_LEVEL);     
        digitalWrite(PIN_R4, 3==n ? ON_LEVEL : !ON_LEVEL);     
    }
    xqp = xq;

    // rallenta elaborazione a 100 cicli al secondo
    delay(10);
}

//----------------------------------------