QUADLOGIC MODULE

 

Avant la description, le fonctionnement général est à voir ici :

Fonctionnement

Il existe des schémas basés sur des portes AND, OR etc, mais je voulais quelque chose de simple et de souple : 4 paires d'entrées sont associées à 4 sorties via 8 fonctions logiques indépendantes, et 2 sorties supplémentaires sont disponibles. Au prix des atmega328, c'est même moins cher qu'un montage à base de portes logiques. C'est moins rapide, mais largement suffisant pour mon usage (environ 80 ns) ! L'avantage est que je dispose de 2 sorties programmables selon mes besoins.

Les 9 fonctions sont accessibles indépendamment avec les potards : AND, NAND, OR, NOR, XOR, NXOR, NOT (voie 1), Set/Reset, ALEAS (sur front voie 1).

quad logic truthTable

Schéma :

Programme :

quad logic algo

Le code est divisé en trois sections :

main :
/*

  QuadLogic v0.4

  Laurent Chaté 2019-2020

  www.la-roue-tourne.fr

  4 paires d'entrée sont logiquement liées sur 4 sorties
  à l'aide de 7 opérations logiques + 1 aléas + S/R
  durée d'un cycle complet de scan/calcul/sortie < 80 ns

  -------------------------------------------------------
  D0 : out G1
  D1 : out G2
  D2 : in A1
  D3 : in A2
  D4 : in B1
  D5 : in B2
  D6 : in C1
  D7 : in C2
  D8 : in D1
  D9 : in D2

  D10: out A
  D11: out B
  D12: out C
  D13: out D

  A0 : potard MODE  0 (23)
  A1 : potard MODE  1
  A2 : potard MODE  2
  A3 : potard MODE  3
  A4 : N/A
  A5 : N/A
 
*/

// entrées
#define pinA1 2
#define pinA2 3
#define pinB1 4
#define pinB2 5
#define pinC1 6
#define pinC2 7
#define pinD1 8
#define pinD2 9

// sorties
#define pinGP1 0
#define pinGP2 1
#define pinA  10
#define pinB  11
#define pinC  12
#define pinD  13

byte pinIn[] = {pinA1, pinA2, pinB1, pinB2, pinC1, pinC2, pinD1, pinD2};
byte entree[8];

byte pinOut[] = {pinA, pinB, pinC, pinD, pinGP1, pinGP2};
byte sortie[4];

// --------------------------------------------------- lecture potentiometres
byte compteurPot;
unsigned long timePot;

// --------------------------------------------------- les modes des 4 voies
enum modes {
  MODE_AND,
  MODE_NAND,
  MODE_OR,
  MODE_NOR,
  MODE_XOR,
  MODE_NXOR,
  MODE_NOT,
  MODE_SR,
  MODE_ALEAS
};

modes mode[4];

// variables temporaires pour la gestion de l'aléas
byte oldX1[4], oldY[4];

// les seuils pour les aléas
int seuil[4] = {25, 50, 75, 90};

void setup() {
  int i;

  initPotard();
  randomSeed(mode[0] + mode[1] + mode[2] + mode[3]);

  for (i = 0; i < 8; i++) {
    pinMode(pinIn[i], INPUT);
  }
  for (i = 0; i < 6; i++) {
    pinMode(pinOut[i], OUTPUT);
  }
}

void loop() {
  gererPotard();
  lectureEntrees();
  calculSorties();
}
fonctions :
/*

    les fonctions

*/
void lectureEntrees() {
  byte pd = PIND,
       pb = PINB;
  entree[0] = (pd & B00000100) >> 2;   // D2
  entree[1] = (pd & B00001000) >> 3;   // D3
  entree[2] = (pd & B00010000) >> 4;   // D4
  entree[3] = (pd & B00100000) >> 5;   // D5
  entree[4] = (pd & B01000000) >> 6;   // D6
  entree[5] = (pd & B10000000) >> 7;   // D7
  entree[6] =  pb & B00000001      ;   // D8
  entree[7] = (pb & B00000010) >> 1;   // D9
}

/*
    les calculs logiques
    0   AND
    1  NAND
    2    OR
    3   NOR
    4   XOR
    5  NXOR
    6   NOT    : on inverse l'entrée n°1 indépendemment de la 2
    7    SR    : SET/RESET : 1 sur la voie 1 SET, puis 1 sur la voie 2 RESET
    8 ALEAS    : on déclanche 1 bit aléatoire sur apparition de 1 sur l'entrée 1
*/

void calculSorties() {
  byte  x1, x2, y;
  byte  g1 = 1,
        g2 = 0;

  for (int i = 0; i < 4; i++) {
    x1 = entree[ 2 * i ];
    x2 = entree[ 2 * i + 1];

    switch (mode[i]) {
      case MODE_AND:
        y = x1 & x2;
        break;
      case MODE_NAND:
        y = 1 - (x1 & x2);
        break;
      case MODE_OR:
        y = x1 | x2;
        break;
      case MODE_NOR:
        y = 1 - (x1 | x2);
        break;
      case MODE_XOR:
        y = x1 ^ x2;
        break;
      case MODE_NXOR:
        y = 1 - (x1 ^ x2);
        break;
      case MODE_NOT:
        y = 1 - x1;
        break;
      case MODE_ALEAS:
        if (x1 == 1) {
          if (oldX1[i] == 1) {
            y = oldY[i];
          } else {
            y = (random(100) > seuil[i]);
            oldY[i] = y;
            oldX1[i] = 1;
          }
        } else {
          y = oldY[i];
          oldX1[i] = 0;
        }
        break;
      case MODE_SR:
        y = 1 - sortie[i];
        if (x1 == 1) {
          y = 1;
        }
        if (x2 == 1) {
          y = 0;
        }
        break;
    }
    
    /*  inversion du signe pour l'électronique des portes de sortie
     *  à modifier pour une future version à base de suiveurs
     */    
    sortie[i] = 1 - y;
    g1 &= y;
    g2 |= y;
  }

  // Ecriture directe des ports
  // D0 et D1
  PORTD = (PORTD & 0b11111100) | (1 - g1) | ((1 - g2) << 1); 
  
  // D10 à D13
  PORTB = (PORTB & 0b11000011) | (sortie[0] << 2) | (sortie[1] << 3) | (sortie[2] << 4) | (sortie[3] << 5) ;

}

lectures des potentiomètres :
void gererPotard() {
  unsigned long tempo = millis();

  // un scan toutes les 100 ms : très suffisant
  if (tempo - timePot > 100) {
    timePot = tempo;
    compteurPot = (compteurPot + 1) & 0x03;
    // j'ai soudé mes potards à l'envers sur mon module, d'ou le calcul foireux
    // normalement, c'est :
    // mode[compteurPot] = analogRead(compteurPot) / 114;
    mode[compteurPot] = MODE_ALEAS - analogRead(compteurPot) / 114;
  }
}

void initPotard() {
  timePot = millis();
  mode[0] = MODE_ALEAS - analogRead(A0) / 114;
  mode[1] = MODE_ALEAS - analogRead(A1) / 114;
  mode[2] = MODE_ALEAS - analogRead(A2) / 114;
  mode[3] = MODE_ALEAS - analogRead(A3) / 114;
}

Cliquez pour le programme

PCB :

QUADLOGIC2 PCB

BOM :

quad logic bom

synthé modulaire

  • Clics : 1192

Related Articles