Pilotage relais MCP23017

Bonjour à tous/toutes, mon topic semble similaire à d'autres mais je n'ai pas retrouvé l'anomalie que je rencontre.

Problématique : Les entrées du PORTA d'un MCP me donnent toujours le mauvais résultat à la première lecture de celles-ci. Après changement de MCP, le problème est toujours présent, donc la piste d'un MCP défectueux est écartée.

Mon architecture est la suivante :

  • 1x pcb routé sur 2 couches
  • 32x relais bistables
  • 10x ULN2003 drivers de relais
  • 4x MCP23017 dont les ports A et B sont configurés en sorties pour piloter les relais au travers des ULN.
  • 2x MCP23017 dont les ports A et B sont configurés en entrées / pull-up interne, pour vérifier la bonne commutation des relais.

Un balais de ces relais est utilisé uniquement pour confirmer la bonne commutation de celui-ci (0/5VDC).

Je viens discuter avec ces MCP via un ATmega1284p, et je pense que le problème peut être d'origine logicielle plutôt que matériel, voici donc mes bouts de code :

Adafruit_MCP23X17 mcp2; // Première entité INPUT : etat relais 0-15  @010                          
Adafruit_MCP23X17 mcp3; //                                           @011                          
Adafruit_MCP23X17 mcp4; // Première entité OUTPUT : relais 0 - 7     @100                          
Adafruit_MCP23X17 mcp5; //                          relais 8 - 15    @101                          
Adafruit_MCP23X17 mcp6; //                          relais 16 - 23   @110                            
Adafruit_MCP23X17 mcp7; //                          relais 24 - 31   @110

Dans la phase setup() ces mcp sont initialisés aux bonnes @ via begin_I2C()
Je configure ensuite les GPIOs

for(unsigned int i = 0; i<16; i++){
    mcp2.pinMode(i, INPUT_PULLUP);
    mcp3.pinMode(i, INPUT_PULLUP);
    mcp4.pinMode(i, OUTPUT);
    mcp5.pinMode(i, OUTPUT);
    mcp6.pinMode(i, OUTPUT);
    mcp7.pinMode(i, OUTPUT);
  }

La commutation d'un relais se fait par simple impulsion, via utilisation de delay() temporairement...

Logique des fonctions :

void setRelaisHigh(unsigned int i) {
  if (i < 8) {
    mcp4.digitalWrite(i, HIGH);
    delay(10);
    mcp4.digitalWrite(i, LOW);
  } else if (i < 16) {
    mcp5.digitalWrite(i - 8, HIGH);
    delay(10);
    mcp5.digitalWrite(i - 8, LOW);
  } else if (i < 24) {
    mcp6.digitalWrite(i - 16, HIGH);
    delay(10);
    mcp6.digitalWrite(i - 16, LOW);
  } else if (i < 32) {
    mcp7.digitalWrite(i - 24, HIGH);
    delay(10);
    mcp7.digitalWrite(i - 24, LOW);
  }
}

Et pour lire l'état :

void getSingleRelais(int i){
  bool result;
  
  if (i < 16){
    result = mcp2.digitalRead(i);
  } else {
    result = mcp3.digitalRead(i);
  }

  if (result){
    Serial.print(1);
  } else {
    Serial.print(0);
  }
}

De cette manière je loop une commutation random :

void loop() {
  relaisCible = random(32);
  commande = random(2);
  
  if (commande){  //  IMPAIR
    setRelaisHigh(relaisCible);
  } else {                 //  PAIR
    setRelaisLow(relaisCible);
  }

  getSingleRelais(relaisCible);
  delay(1000);
}

Pour les lectures des relais 16 à 23 (inclus) qui correspondent au PORTA, le MCP ne retourne JAMAIS le bon état de sa broche.

Ce qui me fait dire que le problème est logiciel, c'est que dans un code différent, je lis les bons états :

void setAllRelaisHigh(){
  for (int i = 0; i < 32; i++){
    setRelaisHigh(i);
    quickDelay();
  }
}

void setAllRelaisLow(){
  for (int i = 0; i < 32; i++){
    setRelaisLow(i);
    quickDelay();
  }
}

void getAllRelais(){
  for(unsigned int i = 0; i<16; i++){
    bool result = mcp2.digitalRead(i);
    if (result)
      Serial.print(1);
    else
      Serial.print(0);
  }
  Serial.print(" ");
  for(unsigned int i = 0; i<16; i++){
    bool result = mcp3.digitalRead(i);
    if (result)
      Serial.print(1);
    else
      Serial.print(0);
  }
  Serial.println();
}

Si je boucle comme ça :

Pour toujours :
setAllRelaisHigh()
getAllRelais()
setAllRelaisLow()

je ne rencontre aucun soucis, ce sont les bonnes valeurs qui sont lues.

Avez vous des suggestions ? Je sens que le soucis est tout bête mais pas moyen de le définir vraiment...

Bonjour patopesto

Ce serai mieux avec le programme complet :wink:

As tu essayé de tester sans les relais, en connectant directement la sortie commande avec l'entrée de contrôle ?

A+
Cordialement
jpbbricole

#include <Wire.h>              // Serial
#include "Adafruit_MCP23X17.h" // Multiplexeurs
                       
Adafruit_MCP23X17 mcp2;    
Adafruit_MCP23X17 mcp3;                   
Adafruit_MCP23X17 mcp4;                          
Adafruit_MCP23X17 mcp5;                  
Adafruit_MCP23X17 mcp6;                            
Adafruit_MCP23X17 mcp7; 

void setup() {
  Serial.begin(9600);                       
  while (!Serial) {;  }                             

  mcp2.begin_I2C(0x22);  // Retour relais 0-15   - IN
  mcp3.begin_I2C(0x23);  // Retour relais 16-31  - IN
  mcp4.begin_I2C(0x24);  // Relais 0-7           - OUT
  mcp5.begin_I2C(0x25);  // Relais 8-15          - OUT
  mcp6.begin_I2C(0x26);  // Relais 16-23         - OUT
  mcp7.begin_I2C(0x27);  // Relais 24-31         - OUT

  for(unsigned int i = 0; i<16; i++){
    mcp2.pinMode(i, INPUT_PULLUP);
    mcp3.pinMode(i, INPUT_PULLUP);
    mcp4.pinMode(i, OUTPUT);
    mcp5.pinMode(i, OUTPUT);
    mcp6.pinMode(i, OUTPUT);
    mcp7.pinMode(i, OUTPUT);
  }
  Serial.println("Setup done.");
}

void quickDelay() {         // Permet la lecture pour les entrées d.
  delayMicroseconds(3);
}

void setRelaisHigh(unsigned int i) {
  if (i < 8) {
    mcp4.digitalWrite(i, HIGH);
    delay(10);
    mcp4.digitalWrite(i, LOW);
  } else if (i < 16) {
    mcp5.digitalWrite(i - 8, HIGH);
    delay(10);
    mcp5.digitalWrite(i - 8, LOW);
  } else if (i < 24) {
    mcp6.digitalWrite(i - 16, HIGH);
    delay(10);
    mcp6.digitalWrite(i - 16, LOW);
  } else if (i < 32) {
    mcp7.digitalWrite(i - 24, HIGH);
    delay(10);
    mcp7.digitalWrite(i - 24, LOW);
  }
}

void setRelaisLow(unsigned int i) {
  if (i < 8) {
    mcp4.digitalWrite(i + 8, HIGH);
    delay(10);
    mcp4.digitalWrite(i + 8, LOW);
  } else if (i < 16) {
    mcp5.digitalWrite(i, HIGH);
    delay(10);
    mcp5.digitalWrite(i, LOW);
  } else if (i < 24) {
    mcp6.digitalWrite(i - 8, HIGH);
    delay(10);
    mcp6.digitalWrite(i - 8, LOW);
  } else if (i < 32) {
    mcp7.digitalWrite(i - 16, HIGH);
    delay(10);
    mcp7.digitalWrite(i - 16, LOW);
  }
}

void getSingleRelais(int i){
  bool result;
  
  if (i < 16){
    result = mcp2.digitalRead(i);
  } else {
    result = mcp3.digitalRead(i);
  }

  if (result){
    Serial.print(1);
  } else {
    Serial.print(0);
  }
}

void loop() {
  relaisCible = random(32);
  commande = random(2);
  
  if (commande){  //  IMPAIR
    setRelaisHigh(relaisCible);
  } else {                 //  PAIR
    setRelaisLow(relaisCible);
  }

  getSingleRelais(relaisCible);
  delay(1000);
}

Bonjour patopesto

Au vu de ton programme, je mettrai une temporisation, ~50 millisecondes, entre un setRelais et un get Single Relais. Cette temporisation est nécessaire du fait que tu fais tirer un relais et que tu lis l'état de son contact, ce qui prend "un certain temps".

Cordialement
jpbbricole

Si j’etais a ta place je mettrais au point avec un programme qui ne gère qu’un seul relai.
Le programme serait bien plus court et il serait plus facile de trouver ce qui ne va pas.

La découpe en petit pas est souvent la méthode qui se révèle être la plus rapide.

1 Like

Bonjour jpbbricole,

J'essai ça dans la journée, je vous fait un retour sur ce qu'il en est :slight_smile:
Merci pour l'attention apportée en tout cas!

Bonsoir patopesto

Par curiosité, as tu un lien sur tes relais?

Cordialement
jpbbricole

Bonjour patopesto

J'ai fait l'essai, sans temporisation, il y a des erreurs, avec une temporisation, j'ai mis 20 millisecondes, plus d'erreurs.

Je pense qu'il y a une erreur ici:

  if (i < 16){
    result = mcp2.digitalRead(i);
  } else {
    result = mcp3.digitalRead(i);
  }

dans else, ça doit être i -16

Cordialement
jpbbricole

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