[RESOLU] Utiliser arduino comme un registre 16 bit

Bonjour,

Je débute depuis quelques mois et j'aimerais savoir si il était possible de transformer son Arduino (Uno) en registre 16 Bit.

Histoire:
J'ai bricolé un afficheur d'onduleur APC 2200 avec dessus 16 LED gérées par un registre 16 Bit. J'ai réussi à coder le programme Arduino et le soft PC en vb.
Ce test m'a permis de déterminer la valeur à envoyer sur mes 2 octets pour piloter mon afficheur en utilisant l'instruction ShiftOut. Tout fonctionne mais ......

Le projet final sera de faire l'inverse du test : l'onduleur envoi la trame et Arduino l'interprète comme le fait l'afficheur.
L'interprétation de la trame ne sera pas trop difficile mais je ne trouve pas le fonction pour faire l'inverse soit la lecture de la trame et non l'envoi. Le ShiftIn fait la même chose que le ShiftOut mais pour des entrées. Savez-vous comment je pourrais faire, avec quelle fonction? Si c'est possible ....... :slight_smile:

Merci de votre aide.

PS: j'ai une autre méthode mais bien moins propre : soudes des opto-coupleurs en // de chaque LED.

Cordialement,
Le réparateur de PC

Bonjour,

Ton registre 16 bits communique via un bus SPI je suppose vu que tu utilises shiftOut() ?
Si oui utilise le port SPI matériel en esclave :

Dans le tuto ci dessus l'interruption ISR(SPI_STC_vect) est appelée à chaque octet reçu.
A toi de traiter une fois sur deux pour avoir tes 16 bits :wink:

re,

Le problème c'est que je n'ai que 3 fils; le composent est un MBI5026.
Je replonge dans les doc du SPI alors :slight_smile:

Voici le code que j(utilise pour piloter la bête :

//-----EEPROM Lib-----
#include <EEPROM.h> // Inclusin librairie pour lire/écrire dans EEPROM.

#define SDI 10 
#define CLK 12 
#define LE 11

#define MAX_STRING_LEN 20

char *inputstring1 = ""; //this is the string that will be split. this can be changed!
char *p, *i;
int x;

int octetReception=0; // variable de stockage des valeurs reçues sur le port Série (ASCII)
char caractereRecu=0; // variable pour stockage caractère recu
String Data1Str;
String Data2Str;
byte Data1;
byte Data2;
String chaineReception=""; // déclare un objet String vide pour reception chaine
String stringOne;
char charBuf[50];

void setup(){ 
  pinMode(SDI, OUTPUT); 
  pinMode(CLK, OUTPUT); 
  pinMode(LE, OUTPUT); 
  Serial.begin(9600);
  Out(255, 255);
  delay(1000);
  Out(0, 0);
  delay(1000);
  Out(EEPROM.read(0), EEPROM.read(1));
} 

void loop() {    

  while (Serial.available()>0) { // tant qu'un octet en réception 
    octetReception=Serial.read(); // Lit le 1er octet reçu et le met dans la variable
    if (octetReception==13) { // si Octet reçu est le saut de ligne
      stringOne = chaineReception; 
      stringOne.toCharArray(charBuf, 50) ;
      for (int i = 0; i < 9; i++) {
        charBuf[50] = charBuf[50] & charBuf[i];
      }
      inputstring1 = charBuf;
      Data1Str = subStr(inputstring1, "|", 1);
      Data2Str = subStr(inputstring1, "|", 2);
      Data1 = Data1Str.toInt();
      Data2 = Data2Str.toInt();
      EEPROM.write(0, Data1);
      EEPROM.write(1, Data2);
      Out(Data1, Data2); 
      chaineReception=""; //RAZ le String de réception
      Serial.println(charBuf);
      delay(100); // pause
      break; // sort de la boucle while
    }
    else { // si le caractère reçu n'est pas un saut de ligne
      caractereRecu=char(octetReception); // convertit l'octet reçu en caractère
      chaineReception=chaineReception+caractereRecu; // ajoute le caratère au String
    }

  } // fin tant que  octet réception
} 

void Out(byte data1, byte data2)  {    
  shiftOut(SDI, CLK, LSBFIRST, data2);   
  shiftOut(SDI, CLK, LSBFIRST, data1);   
  digitalWrite(LE, HIGH); 
  delayMicroseconds(1); 
  digitalWrite(LE, LOW);  
} 

char* subStr (char* input_string, char *separator, int segment_number) {
  char *act, *sub, *ptr;
  static char copy[MAX_STRING_LEN];
  int i;
  strcpy(copy, input_string);
  for (i = 1, act = copy; i <= segment_number; i++, act = NULL) {
    sub = strtok_r(act, separator, &ptr);
    if (sub == NULL) break;
  }
  return sub;
}

Une partie du code est consacré au découpage de la trame venant du soft PC.

Merci :slight_smile:

Cordialement,
Le réparateur de PC

C'est du SPI mais sans ligne esclave -> maitre (MISO).

Sinon il vient d'où cet afficheur ? C'est fourni avec l'onduleur ?

re,

Pour l'histoire, je récupère de tout et comme passé les 5 ans, les UPS sont remplacée et parte à la poubelle, bah j'en ai récupéré 5.
L'afficheur est une partie de l'onduleur :


L'UPS du ma chambre.


Une découpe de l'afficheur.


La carte Arduino pour le pilotage.

Pouvez-vous me donner la correspondance entre mes nom de broches :
#define SDI 10
#define CLK 12
#define LE 11

et les nom de l'interface SPI ?

Avec tout ça, ça devrais aller.

EDIT 09/12/13 :

Dans le tuto ci dessus l'interruption ISR(SPI_STC_vect) est appelée à chaque octet reçu.
A toi de traiter une fois sur deux pour avoir tes 16 bits smiley-wink

Je ne comprend pas trop le "une fois sur deux". Si vous pouvez m'eclairer ..... Merci

Cordialement,
Le réparateur de PC

lereparateurdepc:
Pouvez-vous me donner la correspondance entre mes nom de broches :
#define SDI 10
#define CLK 12
#define LE 11

SDI -> MOSI
CLK -> SCK
LE -> CS, SS ou CE (ça dépend de la convention de nommage).

lereparateurdepc:
Je ne comprend pas trop le "une fois sur deux". Si vous pouvez m'eclairer ..... Merci

16 bits = 2 x 8 bits
1 octet = 8 bits.
L'interruption s’exécute à la réception d'UN octet, pas deux.
A toi de faire ton traitement uniquement quand tu reçois le deuxième octets.
Un simple booléen pourrait suffire par exemple, vrai c'est le 1er octet, faux c'est le 2nd octet et là tu fait ton traitement, ou l'inverse comme tu veut.

re,

Merci à vous tous. J'ai avancé avec différents code et j'ai finalement trouvé :).
Pour la correspondance des broches bah il m'a fallu réfléchir un peut :slight_smile:

Voici le code utilisé dans l'Arduino qui pilote l'afficheur :

//-----EEPROM Lib-----
#include <EEPROM.h> // Inclusin librairie pour lire/écrire dans EEPROM.

#define SDI 10 
#define CLK 12 
#define LE 11

#define MAX_STRING_LEN 20

char *inputstring1 = ""; //this is the string that will be split. this can be changed!
char *p, *i;
int x;

int octetReception=0; // variable de stockage des valeurs reçues sur le port Série (ASCII)
char caractereRecu=0; // variable pour stockage caractère recu
String Data1Str;
String Data2Str;
byte Data1;
byte Data2;
String chaineReception=""; // déclare un objet String vide pour reception chaine
String stringOne;
char charBuf[50];

void setup(){ 
  pinMode(SDI, OUTPUT); 
  pinMode(CLK, OUTPUT); 
  pinMode(LE, OUTPUT); 
  Serial.begin(9600);
  Out(255, 255);
  delay(1000);
  Out(0, 0);
  delay(1000);
  Out(EEPROM.read(0), EEPROM.read(1));
} 

void loop() {    

  while (Serial.available()>0) { // tant qu'un octet en réception 
    octetReception=Serial.read(); // Lit le 1er octet reçu et le met dans la variable
    if (octetReception==13) { // si Octet reçu est le saut de ligne
      stringOne = chaineReception; 
      stringOne.toCharArray(charBuf, 50) ;
      for (int i = 0; i < 9; i++) {
        charBuf[50] = charBuf[50] & charBuf[i];
      }
      inputstring1 = charBuf;
      Data1Str = subStr(inputstring1, "|", 1);
      Data2Str = subStr(inputstring1, "|", 2);
      Data1 = Data1Str.toInt();
      Data2 = Data2Str.toInt();
      EEPROM.write(0, Data1);
      EEPROM.write(1, Data2);
      Out(Data1, Data2); 
      chaineReception=""; //RAZ le String de réception
      Serial.println(charBuf);
      delay(100); // pause
      break; // sort de la boucle while
    }
    else { // si le caractère reçu n'est pas un saut de ligne
      caractereRecu=char(octetReception); // convertit l'octet reçu en caractère
      chaineReception=chaineReception+caractereRecu; // ajoute le caratère au String
    }

  } // fin tant que  octet réception
} 

void Out(byte data1, byte data2)  {    
  shiftOut(SDI, CLK, LSBFIRST, data2);   
  shiftOut(SDI, CLK, LSBFIRST, data1);   
  digitalWrite(LE, HIGH); 
  delayMicroseconds(1); 
  digitalWrite(LE, LOW);  
} 

char* subStr (char* input_string, char *separator, int segment_number) {
  char *act, *sub, *ptr;
  static char copy[MAX_STRING_LEN];
  int i;
  strcpy(copy, input_string);
  for (i = 1, act = copy; i <= segment_number; i++, act = NULL) {
    sub = strtok_r(act, separator, &ptr);
    if (sub == NULL) break;
  }
  return sub;
}

Ce code traite la trame lu sur le port série envoyée par mon soft PC pour piloter l'afficheur.

Le code de lecture de la trame envoyé à l'afficheur contenu dans la seconde Arduino :

//-------------------------Déclaration des librairies-------------------------
//-----LCD Lib-----
#include <LiquidCrystal.h> // Inclusion de la librairie pour afficheur LCD.
//-----SPI Lib-----
#include <SPI.h>


//-------------------------Déclarations pour le LCD-------------------------
//-----Déclaration du LCD-----
LiquidCrystal lcd(2, 3, 4, 5, 6, 7); // Initialisation du LCD en mode 4 bits.

//-------------Définition des caracteres spéciaux pour le LCD-------------
//-----Définition du caractère è-----
byte actegve[8] = { // caractère è
  B01000,
  B00100,
  B01110,
  B10001,
  B11111,
  B10000,
  B01110,
  B00000,
};

//-----Définition du caractère é-----
byte acteaig[8] = { // caractère é
  B00010,
  B00100,
  B01110,
  B10001,
  B11111,
  B10000,
  B01110,
  B00000,
};

//-----Définition du caractère ê-----
byte actecrq[8] = { // caractère ê
  B00100,
  B01010,
  B01110,
  B10001,
  B11111,
  B10000,
  B01110,
  B00000,
};

//-----Définition du caractère /-----
byte slh1[8] = { // caractère /
  B00000,
  B00001,
  B00010,
  B00100,
  B01000,
  B10000,
  B00000,
  B00000,
};

//-----Définition du caractère \-----
byte slh2[8] = { // caractère \
  B00000,
  B00000,
  B10000,
  B01000,
  B00100,
  B00010,
  B00001,
  B00000,
};


char buf [100];
volatile byte pos;
volatile boolean First;

int Data1 = 0;
int Data2 = 0;

//int BData1;
//int BData2;

void setup (void)
{

  //----------LCD----------
  //-----Initialisation du LCD-----
  lcd.begin(16,2); // Initialise le LCD avec 16 colonnes * 2 lignes.
  lcd.noCursor();
  delay(10); // Pause pour prise en compte.
  //-----Initialisation des caractères spéciaux-----
  lcd.createChar(9998, actegve ); // Initialisation du caractère è dans le LCD.
  lcd.createChar(9997, acteaig ); // Initialisation du caractère é dans le LCD.
  lcd.createChar(9996, actecrq ); // Initialisation du caractère ê dans le LCD.
  lcd.createChar(9995, slh1 ); // Initialisation du caractère / dans le LCD.
  lcd.createChar(9994, slh2 ); // Initialisation du caractère \ dans le LCD.
  delay(10);


  Serial.begin (9600);

  // have to send on master in, *slave out*
  pinMode(MISO, OUTPUT);
  SPI.setBitOrder(LSBFIRST);

  // turn on SPI in slave mode
  SPCR |= _BV(SPE);

  // now turn on interrupts
  SPI.attachInterrupt();

  lcd.setCursor(0, 0);
  lcd.print("   APC pannel   ");
  lcd.setCursor(0, 1);
  lcd.print(" Trame d");
  lcd.write(9997); // é
  lcd.print("codeur ");
  delay(2000);
  lcd.clear();

}

// SPI interrupt routine
ISR (SPI_STC_vect)
{
  byte c = SPDR;  // grab byte from SPI Data Register
  if (First == true){
    Data1 = c;
    lcd.setCursor(0, 0);
    lcd.print("  Data 1 = ");
    if (Data1 < 100 && Data1 > 10) lcd.print("0");
    else if (Data1 < 10) lcd.print("00");
    lcd.print(Data1);
    lcd.print("  ");


//    Serial.print("O1 : ");
 //   Serial.println(BData1);
    First = false;
  }
  else{
    Data2 = c;
    lcd.setCursor(0, 1);
    lcd.print("  Data 2 = ");
    if (Data2 < 100 && Data2 > 10) lcd.print("0");
    else if (Data2 < 10) lcd.print("00");
    lcd.print(Data2);
    lcd.print("  ");


  //  Serial.print("O2 : ");
  //  Serial.println(BData2);
    First = true;
  }
}

void loop (void)
{
  //RIEN
}

Prochaine étape, le test en réel depuis l'UPS. Je vous informerais de l'avancée.
Merci

Cordialement,
Le réparateur de PC

re,

Bon bah, ne fonctionne pas en réel. L'afficheur de test n'est pas de la même version.
Je pense que c'est pour ça que le test sur l'onduleur ne fonctionne pas : l'onduleur plante un peut ainsi que l'afficheur.
L'afficheur sur l'onduleur a deux 74H... (je ne me souviens plus de la ref exacte) qui ne doit ( sûrement même ) pas fonctionner de la même façon que le MBI5026 (qui est dédié au pilotage de LED).

Je me retourne donc vers une solution plus simple avec Arduino du simple TOR avec des opto-coupleurs.

Merci à vous pour l'aide

Cordialement,
Le réparateur de PC