Void() parametri e variabili per MCP23017

Saluti!

Porgo una domanda, non so se è di identità semplice o fattibile, ma non bastonatemi...

Allego, per lo scopo, un sketch grezzo e banale di esempio.



const byte BUTTON_1 = 2;
const byte BUTTON_2 = 3;
const byte LED_1 = 10;
const byte LED_2 = 8;


//-----------------
void setup() {
  pinMode(LED_1, OUTPUT);
  pinMode(LED_2, OUTPUT);
  pinMode(BUTTON_1, INPUT_PULLUP);
  pinMode(BUTTON_2, INPUT_PULLUP);
}


//-----------------
void loop() {
  blink(LED_1, BUTTON_1);
}


//-----------------
void blink(byte AA, byte BB) {

  if (digitalRead(BB) == LOW) {
    digitalWrite(AA, HIGH);
    delay(200);
    digitalWrite(AA, LOW);
    delay(200);
    digitalWrite(AA, HIGH);
    delay(200);
    digitalWrite(AA, LOW);
    delay(200);
    digitalWrite(AA, HIGH);
    delay(200);
    digitalWrite(AA, LOW);
    delay(200);
    digitalWrite(AA, HIGH);
    delay(200);
    digitalWrite(AA, LOW);  // OFF
                            // un altro sacco e mezzo di righe come queste....
  }
}

Il void Blink(byte AA, byte BB) (nome a caso) nel mio esempio mi consente di poterlo definire una sola volta ed ad ogni utilizzo, cambiando i nomi delle variabili, posso richiamarlo per scopi diversi con LED e Pulsanti diversi: ma questo pare che valga solo per i Pin di Arduino.

Il mio problema è il seguente:
sto utilizzando quattro port Expander MCP23017 (I2C)
avvalendomi della libreria DFRobot_MCP23017
https://github.com/DFRobot/DFRobot_MCP23017

Le libreie per MCP23017, dalle più perverse alle più user-friendly, più o meno, sono tutte simili nella sintassi ...a meno che non ce ne sia una che non conosco che mi permette di associare subito al numero del pin, anche l'ID del MCP.

Per l'MCP23017, dovrei fare i seguenti passaggi
(li scrivo tutti così evitiamo giri ridondanti di messaggi):

#include "Wire.h"
#include "DFRobot_MCP23017.h"
DFRobot_MCP23017 mcp_1(Wire, 0x20);
DFRobot_MCP23017 mcp_2(Wire, 0x21);
DFRobot_MCP23017 mcp_3(Wire, 0x22);
DFRobot_MCP23017 mcp_4(Wire, 0x23);

const byte LED1 = 10;
const byte LED2 = 8;
const byte BUTTON1 = 2;
const byte BUTTON2 = 3;

void setup() {
  Wire.begin();
  mcp_3.pinMode(LED1, OUTPUT);
  mcp_3.pinMode(LED2, OUTPUT);
  mcp_3.pinMode(BUTTON1, INPUT_PULLUP);
  mcp_3.pinMode(BUTTON2, INPUT_PULLUP);
}

void loop() {
}

In breve, per l'MCP23017, un digitalWrite o un digitalRead deve essere così definito:
mcp.digitalWrite(LED, HIGH)
mcp.digitalRead(BUTTON)

oppure, come nel mio caso che ne utilizzo più di uno, (ad esempio per il terzo):
mcp3.digitalWrite(LED, HIGH)
mcp3.digitalRead(BUTTON)

Come posso (ammesso che sia possibile) inserire nelle variabili del void Blink()
anche i "prefissi" mcp1, mcp2, ecc.
in modo da poterle richiamare, lo scrivo con schiettezza, giusto per rendere l'idea:
mcp3.LED oppure mcp3.BUTTON ?

Innanzitutto smettendo di chiamare la funzione blink() con l'orribile appellativo "void", è una funzione e basta :confounded::joy:
void è solo il tipo di dati restituito, ovvero nessun tipo di dati.

Poi per fare quello che chiedi, è sufficiente aggiungere un terzo parametro alla tua funzione passando il riferimento alle diverse istanze di

DFRobot_MCP23017

che hai usato nel tuo sketch.

E quindi quando ti serve...

blink(AA, BB, mcp_3);

Grazie davvero per la celere risposta che mi ha dato molta speranza.

Procedendo per linearità, ed andando off-topic, questa non l'ho capita:

o meglio, so che che il void non restituisce nulla, ma non mi è chiaro cosa intendi.
Ovviamente ho usato un esempio con comandi "popolari",
ma come si smette di chiamare una funzione senza usare l'orribile appellativo "void"?

Venendo a noi, ho usato:

void blink(byte AA, byte BB, DFRobot_MCP23017 & Wire)
{   blablabla }

e quindi nel loop:

blink(LED_1, BUTTON_1, mcp_3);

ma non funziona.

Qualche dettaglio mancante?

Ovviamente a scanso di equivoci, è tutto montato correttamente.
Ho provato lo sketch su una serie di breadboard sulle quali ho un hardware e sketch già funzionanti con gli MCP.

ciao cd4093,

quando si parla di passaggio parametri alla funzione per "valore", "riferimento", "puntatore" sai di cosa si tratta?
se la risposta è "No" cerca "passaggio per riferimento" e forse ti si chiarisce il tutto.

ciao

So di apparire uno scassa-maroni, ma è una cosa su cui sono abbastanza "sensibile".
E' una questione di semantica; quando si parla di argomenti tecnici io ritengo che oltre ai contenuti, sia altrettanto importante anche usare le terminologie giuste perché un vocabolario corretto e condiviso evita fraintendimenti, soprattutto in ambienti "a distanza" come questo.

Quindi quando scrivi
void blink(byte AA, byte BB, DFRobot_MCP23017 & dfrobot)

stai parlando di una funzione che sia chiama blink, non restituisce nulla ovvero restituisce un void ed accetta in ingresso 3 argomenti definiti dai parametri AA, BB e dfrobot.

I primi due parametri sono due interi senza segno da 8 bit (byte) passati per valore, mentre il terzo è un'istanza della classe DFRobot_MCP23017 passata per argomento ovvero passando il puntatore all'indirizzo di memoria dove "risiede".

Tornando alla sostanza, il tuo esempio non funziona perché hai usato un nome per il terzo parametro che è già usato dalla libreria Wire.h
(colpa mia, dovevo mettere qualcosa meno facile da confondere con quanto già presente nel core Arduino).

1 Like

Occhio che secondo me non stai usando l'integrato come credi.
Se definisci i tuoi GPIO in questo modo significa che BUTTON1 è connesso al pin GPA2 del MCP23017, BUTTON2 al GPA3, LED2 al GPB0 e LED1 al GPB10.

(se ne sei già al corrente, ignora il commento)

Certo, esatto
Per questo non ho nessun problema.
Gli integrati, qualsiasi integrato, li collego anche con le bende agli occhi :slight_smile:
E' il codice, che anche con gli occhiali, non mi riese :blush:

In ogni caso è un lavoro gia fatto con tutti i 64 pin + i pin di Arduino Every utilizzati come interrupt, gia connessi e funzionanti.
Volevo aggiungere una nuova funzione e per non riscrivere 15 volte un determinato blocco di codice adattato agni volta ai vari MCP ed ai vari Input/Output e stati logici, ho pensato di fare un "void" unico con parametri richiamabili a seconda dei pin coinvolti.

Perdonami la faccia tosta, come si fa a fare ciò che ho chiesto?

Partendo dal tuo esempio base e considerando la libreria che stai usando, una funzione blink() generica per usarla con il MCP23017 potrebbe diventare qualcosa del genere:

DFRobot_MCP23017 mcp_1(Wire, 0x20);

void blink(DFRobot_MCP23017 &mcp, const byte pin, uint32_t duration) {
  static uint32_t blinkTime;
  if (millis() - blinkTime >= duration) {
    blinkTime = millis();
    bool actualValue= mcp.digitalRead(pin);
    mcp.digitalWrite(pin, !actualValue);
  }
}

void loop() {
  blink(mcp_1, LED1, 500);
  blink(mcp_2, LED2, 1000);
}

Perdona, ma ... per evitare incomprensioni di linguaggio ti prego di osservare che quella che tu hai creato è una funzione che, non resistuendo un valore, è di tipo void.

La parolina void identifica il fatto che la funzione non ritorna un valore al chiamante. Se la funzione avesse ritornato un valore, al posto di void avresti dovuto mettere il tipo di valore tornato (byte, int, long, ecc.).

Quindi quelle che scrivi sono funzioni e se non ritornano nulla sono di tipo void, altrimenti si deve specificare il tipo del valore che ritornano. :slight_smile:

Grazie :slight_smile:

Guglielmo

Ciao andreaber,
Purtroppo la risposta è "NI", altrimenti non avrei chiesto lumi in questa sede.
Ma se chiedo aiuto è perchè dopo aver cercato da solo di capire, non ci arrivo, Non è il mio mestiere.

Potrei fermarmi qui, ma continuo, non rivolgendomi a te.
Mi occupo anche di alta e bassa frequenza da 40 anni, Se mi chiedono come installare un ponte, non mando nessuno a studiarsi la modulazione, le rotazioni dell'angolo Beta o le somme dei contributi o le densità di potenza.
Questo non è il mio mestiere come non lo è per gran parte di chi chiede auito in questo posto.

Lo dico senza polemica. Lo dico perchè è una occasione che colgo per esternare un mio pensiero.
Leggo spesso sul forum domande alle quali si potrebbero dare risposte immediate, come alla domanda che ho posto io, risposte che aiutano a capire tramite esempi.
Non ho chiesto lo sketch bello pronto e fatto.
E' una semplice domanda sulla sintassi, esattamente come se avessi chiesto come e quando usare il punto e virgola.
Su questo ha ragione chi consiglia di dare uno sguardo per schiarire le idee.
Ma se uno chiede qui, penso che lo faccia perchè, intanto, vuole un input pratico, una spiegazione come la si dovrebbe dare ad un bambino, altrimenti, detto senza cattiveria, questo forum non sarebbe nemmeno necessario.
In rete si trovano anche le tesi di laurea, che ragione ci sarebbe di chiedere qui?
Ed ecco che con un esempio pratico tra le mani, anche la tesi che si trova in giro per il web, diventerebbe più comprensibile.

Spero di non aver generato incomprensioni.

Ma quale esempio esempio Blink! :grin:
Ho detto subito che era un nome di fantasia
e che ho voluto usare "termini" popolari.
La funzione reale è tutt'altra, ma dentro ci sono i vari digitalRead e digitalWrite che purtroppo sono associati agli MCP.
Adirittura cè anche il Delay che non ho mai (MAI MAI MAI usato in vita mia)
Lo scopo unico è che quei digitalRead e digitalWrite dovevano essere visti come mcp_3.digitalRead ed mcp_3.digitalWrite.

Grazie di nuovo, contestatnt

Ed infatti io ho fatto altrettanto :smirk:

... purtroppo però, questa NON è neanche la sede per dei corso base di C/C++ ... sono cose fondamentali che uno deve andare a studiarsi e NON può pretendere che qui si tenga un corso su dette cose.

Mi spiace ... :roll_eyes:

Guglielmo

Ciao Guglielmo, per te nutro sempre gran rispetto,
Concordo con quanto dici, ma un input, almeno solo un input concreto bisognerebbe sempre darlo.
Ad esempio il suggerimento di cotestatnt mi ha aiutato molto per comprendere con più semplicità un ripasso dell'argomento.
anche se prima o poi dimenticherò di nuovo tutto.

Hai ragione,
il motivo lo conoscevo, anche il parametro non era quello giusto, ma senza pensarci, l'ho presa per buona.
Avrei dovuto essere più lucido...
Questo perchè non ho studiato il C++ :innocent:

grazie ancora,
Questa funziona:

void Prisencolinensinainciusol(byte AA, byte BB, DFRobot_MCP23017 &mcp)   {  }

ovviamente dentro il
void Prisencolinensinainciusol
diventano tutte
mcp.digitalWrite oppure mcp-digitalRead

Per abitudine nelle mie funzioni, ai nomi dei parametri antepongo sempre p_ , in questo modo nella funzione (sopratutto lunga) se leggo una variabile p_ qualcosa so che è un parametro.
es.

void blink(byte p_AA, byte p_BB) 
{ if (digitalRead(p_BB) == LOW) 

Si, è una ottima abitudine.
Ho sviluppato per circa dieci anni usando Filemaker,
ed ho sempre avuto anche io questo metodo.
Idem per le variabili locali e globali

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.