Go Down

Topic: Problème Canbus (Read 1 time) previous topic - next topic

Roysone

Bonjour,

Je rencontre un soucis dont je n'arrive pas à m'extirper.

Je souhaite faire communiquer deux modules (dans un premier temps) via le bus CAN.

Chaque module est composé d'un Arduino, d'un MCP2515 et d'un MCP2551. Chaque module a bien son quartz de 16Mhz et sa résistance de terminaison de 120 Ohm (voir schéma).

Sur le 1er module, j'ai 4 boutons poussoirs et un 74LS14(pour la gestion des rebonds des BPs). Sur l'autre module, j'ai 3 LEDs.

J'essaie de faire ceci:

BP1 allume LED1
BP2 allume LED2
BP3 allume LED3
BP4 les éteint toutes

Côté émetteur, je crée un message d'un octet dans lequel je place l'identifiant du BP (de 1 à 4) que j'envoie au récepteur.

Code: [Select]

#include <mcp_can.h>
#include <SPI.h>

// Définition des pins
#define BP1 2
#define BP2 3
#define BP3 4
#define BP4 5
#define CS_PIN 10

// Définition des paramètres du CAN
#define DATA_LENGHT 1
#define ADDR_MODULE_CAN 0x30

// Initialitation de l'objet CAN
MCP_CAN CAN(CS_PIN);

/*
 * ***********************************************************************************************************************
 * Fonction : Setup                                                                                                      *
 * Args: -                                                                                                               *
 * Return: -                                                                                                             *
 * ***********************************************************************************************************************
 */
void setup()
{
  // Configuration des pins
  pinMode(BP1 , INPUT);
  pinMode(BP2 , INPUT);
  pinMode(BP3 , INPUT);
  pinMode(BP4 , INPUT);

  Serial.begin(115200);

  // Initialisation du bus CAN
  while (CAN_OK != CAN.begin(CAN_500KBPS))
    {
        Serial.println("Echec de l'initialisation du contrôleur CAN");
        Serial.println("Reessayez!");
        delay(100);
    }
    Serial.println("Contrôleur CAN ok!");
}

/*
 * ***********************************************************************************************************************
 * Fonction : Loop                                                                                                       *
 * Args: -                                                                                                               *
 * Return: -                                                                                                             *
 * ***********************************************************************************************************************
 */
void loop()
{
  // Création du tableau de variables à envoyer
  unsigned char donnees_BP[DATA_LENGHT] = {};
 
  if(digitalRead(BP1) == HIGH)
    {
      Serial.println("BP1 pressé!");

      // MAJ et envoi de la donnée
      donnees_BP[0] = 1;
      CAN.sendMsgBuf(ADDR_MODULE_CAN, 0, DATA_LENGHT, donnees_BP);
     
      delay(200);
    }
   
    if(digitalRead(BP2) == HIGH)
    {
      Serial.println("BP2 pressé!");

      // MAJ et envoi de la donnée
      donnees_BP[0] = 2;
      CAN.sendMsgBuf(ADDR_MODULE_CAN, 0, DATA_LENGHT, donnees_BP);
     
      delay(200);
    }
   
   if(digitalRead(BP3) == HIGH)
    {
      Serial.println("BP3 pressé!");

      // MAJ et envoi de la donnée
      donnees_BP[0] = 3;
      CAN.sendMsgBuf(ADDR_MODULE_CAN, 0, DATA_LENGHT, donnees_BP);
     
      delay(200);
    }
   
   if(digitalRead(BP4) == HIGH)
    {
      Serial.println("BP4 pressé!");

      // MAJ et envoi de la donnée
      donnees_BP[0] = 4;
      CAN.sendMsgBuf(ADDR_MODULE_CAN, 0, DATA_LENGHT, donnees_BP);
     
      delay(200);
    }

}


Côté récepteur, je lis le message reçu, vérifie si l'ID est le bon et en fonction de la valeur envoyée, j'effectue le  traitement correspondant.

Le hic, c'est que ca plante! Dès que j'allume plus de deux LEDs, l'Arduino se bloque systématiquement. Si j'ouvre et je ferme la fenêtre série, l'Arduino reboote! Je peux par contre appuyer autant de fois sur le bouton 4 (celui qui met à off toutes les LEDs) sans que cela ne fasse bloquer l'Arduino. Plus étrange encore, si je mets les "digitalWrite" en commentaire, le système ne plante pas et j'ai bien la valeur du BP appuyé qui s'affiche dans la console.

On dirait que ce sont les "digitalWrite" mis à 1 qui font planter le système.

J'ai essayé avec une autre carte, cela ne change rien.

Voici le code côté récepteur:

Code: [Select]

#include <SPI.h>
#include "mcp_can.h"

// Définition des pins
#define LED1 5
#define LED2 6
#define LED3 7
#define CS_PIN 10

#define BUFF_SIZE 8

// Définition de l'objet CAN
MCP_CAN CAN(CS_PIN);

/*
 * ***********************************************************************************************************************
 * Fonction : Setup                                                                                                      *
 * Args: -                                                                                                               *
 * Return: -                                                                                                             *
 * ***********************************************************************************************************************
 */
void setup()
{
  // Configuration des pins
  pinMode(LED1 , OUTPUT);
  pinMode(LED2 , OUTPUT);
  pinMode(LED3 , OUTPUT);

  Serial.begin(115200);

  // Initialisation du bus CAN
  while (CAN_OK != CAN.begin(CAN_500KBPS))
    {
        Serial.println("Echec de l'initialisation du contrôleur CAN");
        Serial.println("Reessayez!");
        delay(100);
    }
    Serial.println("Contrôleur CAN ok!");
}

/*
 * ***********************************************************************************************************************
 * Fonction : Loop                                                                                                       *
 * Args: -                                                                                                               *
 * Return: -                                                                                                             *
 * ***********************************************************************************************************************
 */
void loop()
{
    unsigned char len = 0;
    unsigned char donnees_recues[BUFF_SIZE];

    // Attente de l'arrivée d'une donnée
    if(CAN_MSGAVAIL == CAN.checkReceive())
    {
        CAN.readMsgBuf(&len, donnees_recues);    // read data,  len: data length, buf: data buf

        unsigned int canId = CAN.getCanId();
       
        if(canId == 0x30)
          {
          Serial.println(donnees_recues[0]);
         
           if(donnees_recues[0]==1)
            {
              Serial.println ("LED1 allumee");
              if(digitalRead(LED1)==LOW)digitalWrite(LED1, HIGH);
            }
           
          if(donnees_recues[0]==2)
            {   
              Serial.println ("LED2 allumee");
              if(digitalRead(LED2)==LOW)digitalWrite(LED2, HIGH);
            }
           
          if(donnees_recues[0]==3)
            {
              Serial.println ("LED3 allumee");
              if(digitalRead(LED3)==LOW)digitalWrite(LED3, HIGH);
            }
           
          if(donnees_recues[0]==4)
            {
              Serial.println ("All off");
              digitalWrite(LED1, LOW);
              digitalWrite(LED2, LOW);
              digitalWrite(LED3, LOW);
            }
          }
 
    }
}



Ai-je commis une faute? Ma méthode est elle mauvaise?

Merci de votre aide!

Raph

trimarco232

Bonjour,
en résumant grossièrement ça marche quand tu éteins les led et ça plante quand tu les allumes : as-tu mis les résistances des leds ?

Roysone

#2
Mar 30, 2017, 11:18 pm Last Edit: Mar 30, 2017, 11:28 pm by Roysone
as-tu mis les résistances des leds ?
Bonjour,

Oui oui bien sur!

Je ne pense pas que le problème vient du matériel, mais plutôt du côté soft.

J'ai fait deux vidéos pour bien comprendre:

https://www.youtube.com/watch?v=fUYIjJALy6g

Dans la 1ère, on voit que je peux appuyer sur le bouton 4 autant de fois que je veux mais dès que j'appuie plus de deux fois d'affilée sur un des boutons qui allume une des LED, l' Arduino se bloque complètement et je suis obligé de le reseter.

https://www.youtube.com/watch?v=YkZMCe3ko-8

Sur la seconde, j'ai simplement mis les lignes "digitalWrite(LED, HIGH); en commentaire et on voit bien que je peux appuyer autant de fois sur les boutons, signe que les données sont correctement reçues et traitée par le programme.

C'est à ne rien y comprendre!


trimarco232

Quote
On dirait que ce sont les "digitalWrite" mis à 1 qui font planter le système
et en mettant les {...} après le if(...) ?

Roysone

et en mettant les {...} après le if(...) ?
Hélas, même en plaçant la condition hors de la boucle de réception, cela ne fonctionne pas!

Je suis à court d'idée :(

trimarco232

ce que je voulais dire, c'est par exemple :
il y a :
if(digitalRead(LED1)==LOW)digitalWrite(LED1, HIGH);
il faut ou il faudrait, car je n'ai jamais vu ta syntaxe singulière et vraisemblablement risquée :
if(digitalRead(LED1)==LOW) {digitalWrite(LED1, HIGH)};

Roysone

#6
Apr 02, 2017, 11:42 am Last Edit: Apr 02, 2017, 12:33 pm by Roysone
Le C permet de se passer d'accolade pour une seule ligne à condition de tout mettre sur la même ligne ( bien qu'il soit possible de la mettre à la ligne.

C'est bien expliqué ici: https://www.ltam.lu/cours-c/accolade.htm

Mais j'ai bien conscience que cela puisse perturber  ;)

Ceci dit, cela ne change rien. A la base j'avais mis un switch/case et le problème reste le même. J'ai tenté de mettre des Serial.print un peu partout pour comprendre où ca bugge, sans succès!


Roysone

#7
Apr 02, 2017, 08:46 pm Last Edit: Apr 02, 2017, 08:51 pm by Roysone
J'ai choisit d'afficher la valeur de CAN.checkReceive() afin de savoir quelle valeur permet de remplir la condition.

Code: [Select]

        // Attente de l'arrivée d'une donnée
    Serial.print(" Disponibilite: ");
    Serial.println(CAN.checkReceive());
    if(CAN_MSGAVAIL == CAN.checkReceive())
    {
     // Le reste du code....
     }




Quand il n'y a pas de message, CAN.checkReceive() a la valeur 4.
Quand il n'y un message, CAN.checkReceive() a la valeur 3.

J'ai aussi branché mon oscilloscope sur le bus CAN.



Quand j'appuie les deux premières fois, la trame passe bien (ce sont les deux petites lignes à gauche sur la capture d'écran).

Mais dès que cela plante, la trame est renvoyée encore et encore tant qu'elle n'est pas reçue par le récepteur (on le voit clairement sur la photo).

A partir de ce moment là, la valeur renvoyée par CAN.CheckReceive() est 4 donc il ne rentre pas dans la condition et donc le message ainsi que ceux envoyés après ne sont jamais reçus.

J'ai regardé dans la librairie pour essayer de comprendre à quoi correspondent les chiffres renvoyés.

Code: [Select]
#define CAN_OK              (0)
#define CAN_FAILINIT        (1)
#define CAN_FAILTX          (2)
#define CAN_MSGAVAIL        (3)
#define CAN_NOMSG           (4)
#define CAN_CTRLERROR       (5)
#define CAN_GETTXBFTIMEOUT  (6)
#define CAN_SENDMSGTIMEOUT  (7)
#define CAN_FAIL            (0xff)


D'après les définitions, il me dit qu'il n'y a pas de messages (4).

Reste à  savoir pourquoi ca plante....

trimarco232

à ce stade je crains de ne pouvoir t'aider d'avantage car je n'ai pas d'expérience avec le can
en décortiquant la librairie (y compris profondément en ajoutant du "débogage") et en regardant ce qui se passe sur le cuivre doit te permettre de pointer le problème

il semble en effet que le récepteur se plante et de ce fait ne renvoie pas l'aknoledge : as tu fait un test en enlevant physiquement les leds (ou les résistances ?)

Roysone

#9
Apr 06, 2017, 10:07 am Last Edit: Apr 06, 2017, 10:34 am by Roysone
il semble en effet que le récepteur se plante et de ce fait ne renvoie pas l'aknoledge : as tu fait un test en enlevant physiquement les leds (ou les résistances ?)
Salut Trimarco,

Désolé pour la réponse tardive mais j'étais un peu occupé ces jours-ci.

Alors j'ai fait ce que tu m'as dit, j'ai déconnecté les LEDS et .... ca marche!

Je les ai rebranché: ca marche une fois, deux fois, paf ca plante. Et là au lieu de redémarrer, j'ai débranché et rebranché les leds et la Ô miracle, j'ai pu continuer. Ca replante à nouveau après deux fois mais si je les débranche, ca refonctionne.

Alors, d'où vient le mal? Cela semble être matériel du coup!

J'ai ajouté une capa de 100uF sur la ligne d'alim et là ca marche.....un peux mieux. J'ai placé une 1000uF et ca ne plante quasi plus!

Problème de découplage?

Roysone

Je me suis dit que le problème pouvait venir de l'alim. J'ai donc branché une pile 9V et la ca ne plante plus du tout, idem avec une alim à découpage de 12V. Le codo de 1000uF est un peu volumineux, j'ai donc tenté de remettre un 100uF mais les plantages reviennent.

Ca marche de manière empirique mais j'aimerais savoir s'il y a une méthode de calcul.

Merci ;)

trimarco232

Quote
Problème de découplage?
tu peux observer le comportement du +5v à l'oscillo

Quote
Ca marche de manière empirique mais j'aimerais savoir s'il y a une méthode de calcul
on dépasse la capacité en courant de la source : source trop faible ou consommation anormale
comment le montage est-il alimenté au début du post ?

Roysone

Le 5v est fournit par l'Arduino qui est lui-même alimenté par l'USB de l'Arduino. Je suis quand même surpris de voir que deux LEDs allumées suffisent à perturber le contrôleur CAN. Serait_il possible que l'appel de courant fasse reseter le controleur CAN?

Le simple fait de mettre la sonde de l'oscillo sans le codo sur le 5V via l'USB suffit à faire refoirer le système. :o


Roysone

Je pense avoir trouvé la source de mon problème.

En gros, je fabrique des modules pour une domotique dont certains vont se retrouver derrière des interrupteurs muraux, le gain de place est donc crucial.

Pour le moment, j'utilise des arduinos pour prototyper les modules mais à terme, il n'y aura que le microcontrôleur en standalone (soit juste l'atmega328p, le quartz et les condensateurs). La fréquence utilisée par le MCU et le contrôleur CAN est la même, soit 16Mhz. Je me suis dit qu'il y avait peut-être moyen d'en utiliser qu'un seul.

J'ai découvert que l'Atmega328 est capable de fournir un signal d'horloge identique à celui entré via la pin CKOUT (soit la pin 8 de l'Arduino), il me suffirait donc de l'activer et de la relier à la pin OSC1 du contrôleur CAN.

Pour l'activer, il faut modifier les fuses, un peu déroutant quand on ne connait pas.

J'ai donc modifié mes fuses , viré les quartz et les codos de compensation et relancé le tout et là, non seulement ca fonctionne mais en plus, ca ne bugge plus du tout. J'ai viré les capas que j'avais placé sur la ligne d'alimentation pour voir, pareil, ca ne plante plus. Le problème venait donc du quartz (ou des condensateurs céramique mais j'en doute fort).

Au final, mon système fonctionne et est en plus optimisé, que demande le peuple :)

En tout cas, je te remercie de ton aide Trimarco :-)

Go Up