MCP23S17 per comandare dei relay

Facci sapere,ciao.

mmm... Niente da fare...

Ho provato a fare le correzioni consigliate e cioè: - tolto la gestione del pin per lo slave select, ma eliminandola non funziona proprio nulla. Però credo che sia perchè sto usando arduino mega che ha il CS sul pin 53. Quindi per ora ho gestito manualmente la cosa, cosa che dovrò fare comunque avendo più periferiche su SPI. - cambiato l'istruzione pinMode come consigliato con: switcher.pinMode(LOW); Anche qui nulla di differente.

Comunque ho analizzato un po' meglio cosa succede "ad orecchio": in pratica come ho già detto funziona solo metà expander, quindi si sentono le commutazioni di metà dei relay collegati. Quando dovrebbero commutare gli altri invece si sente sempre un rumore di bobina più debole, come se tentasse di nuovo di commutare, ma sempre proveniente dai relay funzionanti (se non ho sbagliato a sentire, poichè i relay sono molto vicini. E' come se prima commutasse i primi 7 relay, dopodichè invece di commutare gli altri 7 sembra che tenti di commutare ancora i primi... E' possibile?

Devo ancora provare a misurare le tensioni sulle uscite dell'expander e vedere se succede qualcosa di strano sui pin non funzionanti rispetto a quelli funzionanti

Finalmente sono riuscito a fare ancora qualche prova, ma purtroppo il circuito non ne vuole sapere di mettersi a funzionare.

La cosa perggiore è che quel poco che adesso funziona magari fra un'ora non funziona più. Vi spiego: ho collegato il tutto questa mattina per misurare le varie tensione di LOW e HIGH su ciascun pin dell'expander e ciascun relay. Ho iniziato dai pin che sapevo essere funzionanti e ho rilevato: - sulle uscite dell'expander LOW a 1,4V e HIGH a 4,8V - Sul relay (uscita dell'ULN2003) LOW a 0,8V e HIGH variabile da 5,7 a 6,2V

Dopodichè ho spento. Dopo un'ora torno, accendo e nemmeno quei pin commutano più: ottengo sull'expander LOW a 0V e HIGH a 0,1V !!!!! Il tutto semplicemente avendo scollegato l'alimentazione e ricollegato un'ora dopo!!! Come può essere?!?!? Escludo problemi di alimentazione perchè misurando i vari chip sono tutti alimentati correttamente.

In questo modo non riesco nemmeno a fare dei test, poichè i risultati sono del tutto inconcludenti! Ma non so nemmeno dove andare a parare per tentare di risolvere il problema.

Sessione di test 348593bis... :~

Ho giocato un po' con le alimentazioni, eliminando l'alimentazione da USB dell'arduino e alimentando il tutto con un'unica fonte: alimentatore da 12V che va ad arduino e ad un regolatore da 5V che alimenta i relay... Anche quì nulla da fare.

Al che mi sono messo a giocare con il solo MCP23S17 scollegato da ULN2003 e relay, e in questo modo in effetti le uscite sono corrette, 0V pe LOW e 4,9V per HIGH. Conclusione: le uscite dell'expander non vanno d'accordo con l'ingresso dell'ULN2003... Ma perchè??? Da datasheet l'ingresso sembrerebbe semplicemente un transistor con la sua resistenza di base da 2K7, mentre l'unico dato che ho trovato sulle uscite dell'expander è che possono erogare max. 25mA.

miiiiiiii, ancora impantanato con sto problema sei? :astonished:

Però sembra di capire che ne sei venuto a capo o quasi. Sei sicuro che l'ULN è adatto a segnali TTL, no perchè c'è anche la versione CMOS con tensione variabile che parte almeno da 6 volts a salire.

Nel dubbio prova a pilotare un ingresso del ULN con una tensione di 3.5 volts e vedi se commuta il relè correttamente, dovrebbe anche communtare con tensione di 3 volts secondo le specifiche TTL. Oppure posta la sigla completa del tuo ULN.

Ciao.

Hehe si... ancora impantanato... =( Per la verità non ci ho perso poi così tanto tempo, ci sto lavorando a sessioni di mezz'ora nel fine settimana! :blush:

Per lo meno sono arrivato a capire il punto in cui si presenta il problema, concludendo che il software funziona e l'MCP risponde correttamente (almeno a vuoto).

La sigla completa è ULN2003AN. Il datasheet indica: - ULN2001 general purpose DTL-TTL-PMOS-CMOS - ULN2002 14-25V PMOS - ULN2003 5V TTL, CMOS - ULN2004 6-15V CMOS La lettera A indica la versione DIP, mentre non so a cosa si riferisca la N.

Non appena riesco a fare qualche prova in più con gli ULN riferirò i risultati!

L'ultima lettera indica l'impedenza termica del package e altre caratteristiche. Vedi pag. 4 --> http://www.ti.com/lit/ds/symlink/uln2003a.pdf

Ah perfetto grazie, sul datasheet che ho in mano non è indicato.

Tornando al discorso… Ho dedicato ancora un’oretta ai test ma purtroppo nemmeno oggi ho concluso qualcosa, anzi…
Ho provato a ricaricare il primissimo sketch che ho scritto per iniziare i test, e che riporto:

#include <SPI.h> 
#include <MCP23S17.h>

MCP switcher(0);

void setup() {
  pinMode(53, OUTPUT);
  digitalWrite(53,LOW);
  switcher.pinMode(0B0000000000000000);
  switcher.digitalWrite(0B1111111111111111);
}

void loop() {
  int i;
  for (i=1;i<=16;i++) {
    switcher.digitalWrite(i, LOW);
    delay(100);
  }
  delay(200);
  for (i = 1; i <=16; i++) {
    switcher.digitalWrite(i, HIGH);
    delay(100);
  }
  delay(200);
}

Con questo codice come dicevo in passato funzionano solo metà dei relay, cioè quelli appartenenti al primo “ottetto” di uscite dell’expander. In realtà il circuito è piuttosto instabile: spesso appena tocco qualcosa con i puntali del tester il ciclo si ferma. Ma questo secondo me potrebbe essere causato dai fili di collegamento dell’SPI volanti. Più tardi tempo permettendo rifaccio tutti i collegamenti con dei cavetti schermati.

Comunque… In questa situazione ho provato a smontare gli ULN2003 e fare qualche misura: come previsto solo le prime 8 uscite commutano passando da circa 0 a circa 5V.

Poi, in questa situazione ho provato diverse modifiche al programma: interferenze e instabilità a parte ho sempre il secondo ottetto di uscite fermo immobile, non si schioda dai 0V… E quì ho veramente il dubbio che sia un problema software o di librerie. Non saprei quale altra prova effettuare su questo circuito.
L’unica cosa che potrei fare è costruire un altro ciruito su breadboard eventualmente con un atmega328 invece dell’arduino mega. Così potrei innanzitutto escludere problemi software o incompatibilità con la mega.

Come al solito porterò notizie al più presto.

Appena ho un attimo di tempo, rileggo da capo la discussione, perché mi sono un po' perso. :|

Hehe, anch'io mi sono perso... Tra un tentativo e l'altro, uno più inconcludente dell'altro, non ci sto capendo più una mazza... :fearful:

Faccio un riassunto della situazione. Innanzitutto il progetto è costituito da una catena di relay comandati attraverso un expander MCP23S17 su bus SPI. Fanno da tramite due ULN2003. La scheda è alimentata a 5V ottenuti da un regolatore switching, e il cervello è una scheda Arduino Mega.

Ho già testato il bus SPI su un circuito che controlla dei display a 7 segmenti con un MAX7221, quindi sono sicuro che il bus SPI funziona, mentre non sono per nulla sicuro che funzioni altrettanto bene la libreria MCP23S17.h

Dai test fatti sembrerebbe che la prima metà dell'expander sia funzionante(prime 8 uscite), mentre la seconda metà non si schioda dallo zero logico (uscite 9-16). Il tutto è un po' instabile ma credo che ci sia da lavorare sulla schermatura dei collegamenti SPI. Le ultime conclusioni mi avevano portato a dire che l'uscita dell'expander non andasse d'accordo con l'ingresso dell'ULN2003, ma a quanto pare non è quello il problema perchè metà delle uscite commuta correttamente.

Ora vorrei provare a costruire un circuito più semplice possibile con ATMEGA328, MCP23S17 e qualche led per testare in modo sicuro il funzionamento della libreria e dello sketch.

Scrivo solo questo e poi vado a nanna, ci ho gli occhi a pampinedda. :P

Il 23017 dovrebbe essere idendico al quello che usi tu, con la differenza che il tuo dialoga tramite ISP, mentre il "017" tramite I2C. Leggendo il manuale del 23017 ho notato che è possibile farlo funzionare in due modalità, 8 bit o 16 bit, ora non ho la lucidità per indagare e i risultati sarebbero pessimi, ma vado per intuito, cioè se è impostato per 16 bit ed invii 16 bit di cui riempi solo i meno significativi, gli altri non si accenderanno, se invece è in modo 8 bit devi inviare due byte distinti, ma qui c'è di mezzo la libreria, io al tuo posto avrei estrapolato il codice sensibile da quella lib e scritto uno sketch con le istruzioni indispensabili per eccitare tutti i 16 relè così da vedere cosa cambia tra modo 8 bit e 16 bit.

Ciao.

Grazie dei suggerimenti.

La libreria funziona in diverse modalità: - Impostando un pin per volta, ed i pin sono numerati da 1 a 16 - Impostando tutti i pin in un solo colpo con una stringa di 16 bit (esempio 0B1111111111111111 per impostare tutti i pin a HIGH) oppure con una word esadecimale (0xFF se non ricordo male per tutti HIGH). Non ho ancora ben chiaro se ci siano anche altri modi di funzionamento. Sono partito da questi perchè sono i più semplici e proprio per questo non vedo perchè non dovrebbero funzionare. Ho già fatto anche un po' di prove per eccitare tutto insieme, o un pin singolo, o una sequenza. Ieri sera ho anche provato senza relay, solo con led e resistenze collegati ad un singolo pin. Il risultato è sempre lo stesso... Alcuni pin vanno, altri no, il tutto sempre in modo molto instabile.

L'unica prova che devo ancora fare è sostituire i cavetti del bus SPI con qualcosa di schermato, ma ho i miei dubbi che sia una cosa risolutiva perchè a quanto pare il bus trasmette correttamente... Comunque potrebbe essere un passo avanti per rendere il tutto più stabile.

Altra prova rapida…

Con questo codice funzionano i famosi 8 ingressi, mentre gli altri restano fissi alcuni LOW e alcuni HIGH senza una logica apparente:

#include <SPI.h> 
#include <MCP23S17.h>

MCP switcher(0);

void setup() {
  pinMode(53, OUTPUT);
  digitalWrite (53, LOW);
  switcher.pinMode(0B0000000000000000);
}

void loop() {
  int i;
  for (i=1;i<=16;i++) {
    switcher.digitalWrite(i, LOW);
    delay(100);
  }
  delay(200);
  for (i = 1; i <=16; i++) {
    switcher.digitalWrite(i, HIGH);
    delay(100);
  }
  delay(200);
}

Con quest’altra sento delle commutazioni che non hanno niente a che vedere con ciò che c’è scritto nel programma: ho delle commutazioni sull’uscita 9 con tempi diversi da quelli scritti nello sketch e un’altra commutazione sull’uscita 7 che non so da dove arriva!!!

#include <SPI.h> 
#include <MCP23S17.h>

MCP switcher(0);

void setup() {
  pinMode(53, OUTPUT);
  digitalWrite (53, LOW);
  switcher.pinMode(0B0000000000000000);
}

void loop() {

    switcher.digitalWrite(9, HIGH);
    delay(200);
    switcher.digitalWrite(9, LOW);
    delay(500);
}

Qui addirittura ho commutazioni su 4 relè diversi:

#include <SPI.h> 
#include <MCP23S17.h>

MCP switcher(0);

void setup() {
  pinMode(53, OUTPUT);
  digitalWrite (53, LOW);
  switcher.pinMode(0B0000000000000000);
}

void loop() {

    switcher.digitalWrite(1, HIGH);
    delay(200);
    switcher.digitalWrite(1, LOW);
    delay(500);
}

Adesso ho anche sostituito i cavetti con un cavo a 4 poli schermato, ed in effetti sembra un po’ meno sensibile ai disturbi del tester, delle mani, ecc.
Però non cambia il funzionamento.

gamby:
Grazie dei suggerimenti.

La libreria funziona in diverse modalità:

  • Impostando un pin per volta, ed i pin sono numerati da 1 a 16
  • Impostando tutti i pin in un solo colpo con una stringa di 16 bit (esempio 0B1111111111111111 per impostare tutti i pin a HIGH) oppure con una word esadecimale (0xFF se non ricordo male per tutti HIGH).
    Non ho ancora ben chiaro se ci siano anche altri modi di funzionamento. Sono partito da questi perchè sono i più semplici e proprio per questo non vedo perchè non dovrebbero funzionare.
    Ho già fatto anche un po’ di prove per eccitare tutto insieme, o un pin singolo, o una sequenza. Ieri sera ho anche provato senza relay, solo con led e resistenze collegati ad un singolo pin. Il risultato è sempre lo stesso… Alcuni pin vanno, altri no, il tutto sempre in modo molto instabile.

L’unica prova che devo ancora fare è sostituire i cavetti del bus SPI con qualcosa di schermato, ma ho i miei dubbi che sia una cosa risolutiva perchè a quanto pare il bus trasmette correttamente… Comunque potrebbe essere un passo avanti per rendere il tutto più stabile.

Si ok la libreria ti da l’impressione di poter gestire il 23S17 in modo diverso, ma è una impressione o è la realtà?

Nel datasheet c’è anche scritto che è possibile impostare la polarità per ogni pin di GPIO, quindi se metti alto un pin in uscita avrai 1 negato cioè zero. Queste cose la lib non le gestisce.

Comunque, la lib che ho guardato io usa l’include:

#include <SPI.h>                 // Arduino IDE SPI library - uses AVR hardware SPI features
#include "MCP23S17.h"            // Header files for this class

Nel codice di esempio non c’è necessità di includere nuovamente SPI.
Per ultimo una cosa molto importante:

#define    SS            (10)          // SPI bus slave select output to pin 10 - READ ARDUINO SPI DOCS BEFORE CHANGING!!!

SS è definito ma non usato nella lib, in sua vece c’è una costante numerica espressa in binario, questo è il codice:

// GENERIC BYTE WRITE - will write a byte to a register, arguments are register address and the value to write

void MCP::byteWrite(uint8_t reg, uint8_t value) {      // Accept the register and byte
  PORTB &= 0b11111011;                                 // Direct port manipulation speeds taking Slave Select LOW before SPI action
  SPI.transfer(OPCODEW | (_address << 1));             // Send the MCP23S17 opcode, chip address, and write bit
  SPI.transfer(reg);                                   // Send the register we want to write
  SPI.transfer(value);                                 // Send the byte
  PORTB |= 0b00000100;                                 // Direct port manipulation speeds taking Slave Select HIGH after SPI action
}

Guarda caso PORTB |= 0b00000100 è il digital pin 10 di arduino 2009/UNO, che corrisponde al pin SS (16) del 328.

Ora tu devi cambiare sia porta che valore fino a selezionare il pin 53 della MEGA e questi cambiamenti li devi fare su tutta la lib.

Poi c’è ancora una cosa che non ho capito, il 23S17 ha dei pin chiamati A0, A1, A2 che possono essere disabilitati o abilitati, sono abilitati di default nella versione I2C perchè manca il bit HAEN e disabilitati per la versione ISP ma abilitabili grazie ad HAEN.

Il documento che ho consultato e questo che è valido per entrambe le versioni ISP e I2C, alla pagina 18 c’è la descrizine di importati bit.
DS21952B-page 18

Ciao.

Sto facendo riferimento a questa pagina: http://playground.arduino.cc/Main/MCP23S17

A un certo punto è scritto:

The class does include several more methods that can be used to simplify configuration in the same "Arduino-ish" way, methods for writing/reading 8-bit registers (configuration and I/O ports) at once, as well as writing/reading consecutive registers (allowing all 16 bits to be read or written with one method call)

Quindi se non ho capito male sarebbe possibile impostare i pin da 1 a 16 senza preoccuparsi dei due registri. Cosa che io ho prontamente evitato ]:D Non avevo invece controllato la presenza del pin SS nella libreria. Avevo cambiato da 10 a 53 nella #define ma non avevo notato che non era presente nel codice.

Però ho anche provato ad assegnare manualmente il segnale al pin 53 con un semplice digitalWrite(53,LOW). Non ricordo se lo avevo letto o se è una mia convinzione, ma non è la stessa cosa? Anche perchè se così non fosse come si fa a controllare più slaves? Occorre modificare la libreria di ogni periferica per assegnare un pin di slave select diverso?

A questo punto devo provare a modificare quel "PORTB |= 0b00000100" per puntare al pin 53.

Rieccomi... Ho dato un'occhiata al datasheet e alle librerie di questo benedetto MCP23S17, ma ho le idee ancora più confuse di prima.

Si parlava di Slave select e di quel valore "PORTB |= 0b00000100" che corrisponderebbe al pin slave select sul ATMEGA328. Ma come faccio a modificarlo per dare la corrispondenza al relativo pin sul ATMEGA2560? A quanto vedo non è sufficiente ricavare il valore binario corrispondente al pin SS.

Quei pin A0,A1,A2 identificano l'indirizzo del 23S17. Vanno settati HIGH o LOW in base all'indirizzo che si vuole dare al chip. In questo modo è possibile collegare fino a 8 dispositivi in parallelo con un solo pin SS, e attivare quello corretto attraverso l'indirizzo che lo identifica. Nel codice l'indirizzo va inizializzato assieme al nome del chip. Nel mio circuito ho messo i tre pin a massa, quindi ho inizializzato il componente con l'indirizzo zero in questo modo:

MCP switcher(0);

Così che in seguito nel codice farò riferimento a quel chip con il nome switcher che identifica il dispositivo con indirizzo zero.

Il pin SS vedo che si trova nella porta B ma nella prima posizione della porta, cioè in PB0 (pin19).

Nel codice mi pare che c'è una constante "#define SS" che non viene usata, beh usala più o meno così:

define SPI_SS 0b00000001

Nel codice sostituisci :

PORTB |= 0b00000100 con PORTB |= SPI_SS

Anche quando rimette il bit a zero usando "&=" al posto di "|=" devi fare la sostituzione. PS: non mi ricordo il codice.

Sempre che tu non abbia già provato senza risolvere.

Ciao.

YESSSSSSSSSS… PERFETTO!!!

:smiley: :smiley: :smiley: :smiley:

Inizio a capire la logica… Non avevo capito che quel “PORTB” era riferito al registro dell’ATMEGA, pensavo fosse ancora del 23S17!
Praticamente ho sostituito il valore binario di PORTB in tutta la libreria in questo modo:

PORTB |= 0b00000001
PORTB &= 0b11111110

Ora funziona correttamente. Non ho fatto dei test intensivi ma a quanto pare il ciclo for del mio programmino di test funziona correttamente!
Grazie a tutti per il supporto, specialmente a MauroTec per essere andato a studiare datasheet e libreria…

Per chi dovesse incappare nello stesso problema dopo di me allego la libreria corretta (non ho usato le #define perchè in realtà i valori sono due).

MCP23S17.zip (20.8 KB)

Stappa lo spumante che brindiamo :P

Puoi usare la define con questa modifica:

define SPI_SS 0b00000001

PORTB |= SPI_SS PORTB &= ~SPI_SS

oppure accendi e spegni bit con la macro _BV(bit)

PORTB |= _BV(PB0) PORTB &= ~_BV(PB0)

Nota che PB0 PB1 ecc sono i nomi dei pin che nella avrlibc sono stati definiti tramite #define, quindi la define SS diventa

define SPI_SS PB0

e al posto di _BV(PB0) scrivi _BV(SPI_SS)

Occhio al "~" che inverte tutti i bit.

Io pensavo tu avessi una discreta competenza con il software tanto da potertela cavare da solo, e invece mi sbagliavo ora per punizione ti tocca sbatterti un poco a studiare le porte del micro, macro ecc. :P

Ciao.

In effetti mi sto rendendo conto che un po' di pratica vale molto più di tante ore passate sui libri. Ho già fatto i corsi di base sul C all'università, ma vedo che la teoria è molto diversa dalla pratica... Cioè un conto è scrivere un programmino con qualche ciclo, usare la ricorsione, le funzioni delle librerie standard, ecc, e un conto è mettersi a scrivere software, seppur semplice, per far funzionare qualcosa di reale. Per non parlare di "trucchetti" (messo tra virgolette perchè mi rendo conto che per un programmatore sono cose basilari), vedi la tilde per invertire i bit di cui non ricordavo minimamente l'esistenza.

Per punizione mi ci metto volentieri a imparare un po' di cosette :grin: Sono ben accetti consigli su cosa iniziare a studiare.

Tornando alle cose importanti... Quasi quasi lo spumante lo stappo davvero!!! ]:)