Ceci est la traduction d’un article publié sur https://www.instructables.com/Serial-Communication-UART-Between-an-Arduino-Board/

Ce tutoriel montre comment utiliser une carte Narrow équipée d’un écran OLED (mais vous pouvez utiliser n’importe quelle carte compatible Arduino) pour envoyer des commandes au Générateur d’Horloge à travers la liaison série (UART). Nous allons envoyer une commande pour changer la fréquence puis une commande pour balayer les fréquences entre 10 et 20 MHz par pas de 0.1 MHz. L’écran OLED servira à afficher toutes les commandes passées et les données reçues.

Contrôle par liaison série du Générateur d'Horloge

Contrôle par liaison série du Générateur d’Horloge

Ce projet relativement simple couvre de nombreux aspects: l’envoi des données par UART, la réception des données en utilisant un tampon, la validation des commandes, l’appel des fonctions de la librairie du Générateur d’Horloge. Donc, même si vous n’avez ni carte Narrow ni Générateur d’Horloge vous y trouverez sans doute des éléments de code intéressants pour vos projets.

C’est aussi l’occasion de montrer la communication entre une carte basée sur Atmega et une carte basée sur STM32, en utilisant uniquement du code Arduino.

Fournitures:

  • Une alimentation de 6 à 12 volts
  • Une carte Narrow ou une autre carte de type Arduino (UNO, NANO etc)
  • Un écran OLED 0.49″ (que vous pouvez commander avec la carte Narrow)
  • 2 * 2 câbles male/femelle Dupont avec une “planche à pain” ou 2 * 2 câbles femelle/femelle Dupont.
  • Le Générateur d’Horloge
  • Un câble USB A vers Mini-B pour programmer les cartes.

Etape 1: Principe de fonctionnement lorsque vous contrôlez le Générateur d’Horloge depuis le Moniteur Série

Principe de fonctionnement - contrôle depuis le Moniteur Série

Principe de fonctionnement – contrôle depuis le Moniteur Série.

Le Générateur d’Horloge est une carte autonome qui fournit 3 horloges programmables. Etant compatible Arduino vous pouvez modifier le programme de base. Dans cet exemple nous allons charger une nouvelle version du programme qui permet de configurer la carte en lui envoyant des ordres. N’importe quelle carte ainsi que le Moniteur série peuvent envoyer des commandes si elles sont correctement formattées. Nous nous servirons d’abord du Moniteur Série pour envoyer des commandes et recevoir en retour l’état de la carte:

  1. Chargement du sketch ClockGen_serial_control.ino sur le Générateur d’Horloge en utilisant le port USB en DFU (il peut être nécessaire d’appuyer sur reset pour que la carte soit détectée comme un périphérique DFU).
  2. Un port COM est ensuite énuméré. Si vous lancer le Moniteur série vous pouvez taper des commandes qui seront envoyées au Générateur d’Horloge à travers l’USB/COM.
  3. Le sketch ClockGen_serial_control.ino comporte une fonction processIncomingBytes() qui stock les octets reçus jusqu’à recevoir un caractère de fin de ligne (\n).
  4. Chaque octet reçu est affiché sur l’écran TFT.
  5. Lorsqu’une ligne complète, correctement formatée avec une commande et d’éventuels paramètres, est reçue, une fonction de la librairie de ClockGen est invoquée pour modifier la configuration de la carte.
  6. Le nouvel état de la carte est obtenu depuis la librairie ClockGen.
  7. Cette information est envoyée à l’interface USB/Série.
  8. Et elle est transportée vers le Moniteur Série à travers l’USB/COM

Etape 2: Principe de fonctionnement lorsqu’une carte contrôle le Générateur d’Horloge

Principe de fonctionnement - en contrôlant le Générateur d'Horloge depuis une autre carte.

Principe de fonctionnement – en contrôlant le Générateur d’Horloge depuis une autre carte.

Maintenant nous utilisons une carte Narrow pour envoyer les commandes au Générateur d’Horloge

  1. Chargrement du sketch ClockGen_serial_control.ino sur le Générateur d’Horloge en utilisant le port USB en DFU (il peut être nécessaire d’appuyer sur reset pour que la carte soit détectée comme un périphérique DFU).
  2. Chargement du sketch SendCommands.ino sur la carte Narrow à travers le port USB/COM (évidement il faut pour cela modifier le choix de la carte dans l’IDE Arduino). La carte Narrow est un bon choix car elle offre 2 ports série et la possibilité de monter un OLED dessus.
  3. Après chargement des programmes, il n’est plus nécessaire d’utiliser l’ordinateur. Le programme SendCommands.ino va envoyer les commandes au Générateur d’Horloge à travers un des ports série. Si vous n’avez qu’un port disponible, cela peut fonctionner à partir du moment ou vous déconnectez le port USB pour éviter toute interférence.
  4. Les commandes passées sont affichées sur l’écran OLED.
  5. L’interface série envoi les commandes depuis sa broche Tx vers la broche Rx du Générateur d’Horloge.
  6. Le sketch ClockGen_serial_control.ino comporte une fonction processIncomingBytes() qui stock les octets reçus jusqu’à recevoir un caractère de fin de ligne (\n).
  7. Chaque octet reçu est affiché sur l’écran TFT.
  8. Lorsqu’une ligne complète, correctement formatée avec une commande et d’éventuels paramètres, est reçue, une fonction de la librairie de ClockGen est invoquée pour modifier la configuration de la carte.
  9. Le nouvel état de la carte est obtenu depuis la librairie ClockGen.
  10. Les données en retour sont envoyées de la broche Tx du Générateur d’Horloge à la broche Rx de la carte de contrôle.
  11. La fonction processIncomingBytes() du programme SendCommands.ino stocke les données reçues.
  12. Lorsqu’une ligne complète est reçue, elle est affichée sur l’écran OLED. L’utilisateur peut donc immédiatement s’assurer de l’état du Générateur d’Horloge (les données sont brutes, non interprétées).

Les flèches en pointillés montrent un chemin de communication alternatif.

Etape 3: Le réseau UART et le formatage des paquets de données

Les cartes compatibles Arduino supportent le protocole de communication série UART. Dans sa forme la plus simple c’est un système de communication asynchrone à 2 fils.

Les 2 fils transportent des données. Un sert à envoyer les données de la broche Tx de l’appareil 1 à la broche Rx de l’appareil 2 et l’autre envoie les données de la broche Tx de l’appareil 2 à la broche Rx de l’appareil 1.

Etant asynchrone, il n’y a pas de ligne transportant un signal d’horloge. Donc les 2 appareils doivent envoyer chaque bit de donnée après une période fixe et identique qui dépend du nombre de bauds. Nous allons utiliser un nombre de 9600 bauds, ce qui est faible, parce que nous n’allons pas peaufiner la réalisation matérielle. Nous utilisons de simples fils Dupont sans trop nous soucier. Vous pouvez essayer d’utiliser des valeurs de bauds beaucoup plus élevées (jusqu’à 1000000 ?). Bien sûr si la valeur de bauds du récepteur est différente de celle de l’émetteur les données sembleront totalement erronées.

Les commandes sont formattées ainsi:

Commande param1;…param n \n

C’est à dire un mot de commande suivi éventuellement de un ou plusieurs paramètres séparés par des point virgules et un caractère de fin de ligne (\n).

Lorsque nous envoyons des commandes depuis le Moniteur Série, le caractère de fin de ligne est ajouté par le fait de taper la touche “Entrée”. Donc on n’aura pas à le taper dans la zone de saisie. Mais il faut l’ajouter lorsque l’on fait envoyer les commandes par un programme.

Voici les trames transmises:

Envoi d'une commande par UART

Envoi d’une commande par UART

  • Envoi de la commande “c0 sf 1000000 \n”: vous pouvez voir chaque bit qui a été envoyé (symbolisé par un point), plus les bits techniques. Tous sont espacés régulièrement avec une période qui dépend du nombre de bauds. L’analyseur logique montre en effet les données décodées en format ASCII “C0(sp)sf(sp)100000LF”
La réception de la fréquence de l'horloge 1 par UART

La réception de la fréquence de l’horloge 1 par UART

  • La réception des données en retour qui informent de la fréquence de l’horloge 0. L’analyseur logique montre : clock(sp)0(sp)frequency:(sp)1000000(sp)Hz(sp)CRLF

Etape 4: Quelques explications concernant la librairie du Générateur d’Horloge

Classe du Générateur d'Horloge

Classe du Générateur d’Horloge

La librairie Pandauino_Clock_Generator.h définit une classe et une instance de cette classe nommée « ClockGenerator ».

Un ensemble de fonctions publiques peuvent être invoquées depuis n’importe quel programme C++ et particulièrement notre sketch Arduino. Par exemple:

void begin(); initialise le programme: configure la puce Si5351A, obtient les paramètres stockés en EEPROM etc…

void run(); à invoquer dans la boucle loop de votre sketch pour capter les actions de l’utilisateur sur le bouton menu, le sélecteur etc…

void setFrequency(int clockId, uint32_t frequency); pour définir la fréquence en Hertz d’une des 3 horloges (id= 0,1 ou 2).

uint32_t getFrequency(int clockId);  pour obtenir la fréquence courante d’une horloge.

Voir le manuel utilisateur du Générateur d’Horloge pour une description exhaustive.

Etape 5: L’environnement de programmation et les prérequis.

  • Il vous faut l’IDE Arduino 1.8.13
  • Pour pouvoir programmer le Générateur d’Horloge, qui est une carte basée sur STM32, il faut ajouter les définitions de cartes dans l’IDE Arduino et le paramétrer correctement. Voir le manuel utilisateur du Générateur d’Horloge.
  • Pour programmer la carte Narrow, qui est basée sur un Atmega644 ou un Atmega1284, il faut aussi ajouter la définition de carte à l’IDE Arduino et la paramétrer correctement. Voir le manuel utilisateur des cartes Narrow.
  • Vous pouvez utiliser une autre carte Arduino à partir du moment ou elle comporte assez de mémoire flash (>= 13 KB) et de RAM (>= 2 KB).

Afin de contrôler la carte depuis le moniteur série il vous faudra toutes les librairies qui sont référencées dans la librairie du Générateur d’Horloge pour pouvoir compiler le sketch:

Pour contrôler le Générateur d’Horloge depuis une autre carte il vous faut la librairie de l’écran OLED 64×32 pixels:https://github.com/mrguen/Adafruit_SSD1306-master-…

Pour finir il vous faut les sketchs ClockGen_serial_control.ino  https://github.com/mrguen/ClockGen/tree/main/examp… et sendCommands.ino https://github.com/mrguen/ClockGen/tree/main/examp…

Etape 6: Le programme “ClockGen_serial_control.ino”

ClockGen_serial_control.ino

ClockGen_serial_control.ino

Ce programme comporte:

  • La fonction setup() qui
    • lance la communication série.
    • invoque ClockGenerator.begin() pour initialiser le Générateur d’Horloge.
    • invoque info() pour imprimer la syntaxe des commandes.
void setup() { 
  mySerial.begin(9600); 
  while (!mySerial) {} 
  ClockGenerator.begin(DEBUG, 9600); 
  if (mySerial==Serial)  info(); 
}
  • La fonction loop() qui:
    • invoque une fonction processIncomingByte() pour concaténer les octets de donnée reçus à chaque fois qu’il y a quelque chose dans le tampon de l’interface série.
    • invoque une fonction testSweep() qui change la fréquence de l’horloge s’il est temps de le faire.
    • invoque la fonction run() qui capte les actions sur l’interface utilisateur du Générateur d’Horloge (Bouton menu, sélecteur…).
void loop()
{ 
  // if mySerial data available, process it 
  while (mySerial.available () > 0) { processIncomingByte (mySerial.read ());} 
  ClockGenerator.testSweep();     // If sweep is launched, changes the frequency after the programmed period of time 
  ClockGenerator.run();           // allows human interaction 
}
  • La fonction processIncomingByte() concatène les octets qui sont reçus jusqu’à recevoir le signe \n ou jusqu’à une longueur maximale. Puis elle invoque la fonction analyzeCommand() pour interpréter la ligne de commande reçue. Chaque octet de donnée est aussi affiché sur l’écran TFT afin que l’utilisateur puisse voir immédiatement si ce sont les commandes attendues et correctement formatées.
void processIncomingByte (const byte inByte)
{

  // Blank screen when expecting a new commande
  if (input_pos == 0) {  
    tft.fillScreen(ST7735_BLACK);
    tft.setCursor(2,50);
    tft.setFont(&FreeSans9pt7b);
    tft.setTextSize(1);
    tft.setTextColor(ST7735_WHITE);
    tft.setTextWrap(true);
  }

  // Prints each byte received on the TFT
  tft.print(char(inByte));
  delay(100);

  if (DEBUG) {
    Serial.print("Byte: ");
    Serial.write(inByte);
    Serial.write("\n");
  }
    
  switch (inByte) {

    case '\n':   // end of text
      input_line [input_pos] = 0;  // terminating null byte

      delay(1000);
      ClockGenerator.displayAllClocks();
      
      // terminator reached! process input_line here ...
      analyzeCommand(input_line);

      // reset buffer for next time
      input_pos = 0;  
      memset(input_line, 0, sizeof(input_line));      
      break;

    case '\r':   // discard carriage return
      break;

    default:
      // keep adding if not full ... allow for terminating null byte
      if (input_pos < (MAX_INPUT - 1))
        input_line [input_pos++] = inByte;
      break;
      
  }  // end of switch

} // end of processIncomingByte  <br>
  • La fonction analyzeCommand() vérifie que la commande reçue est correctement formatée. Elle vérifie la première lettre puis les lettres suivantes etc… en attendant seulement certaines lettres à chaque niveau. Lorsque la ligne complète à du sens, elle:
    • invoque la fonction publique appropriée de l’instance ClockGenerator.
    • invoque une des méthode “print” utilisée pour retourner les informations concernant l’état mis à jour de la carte vers la carte de contrôle. Par exemple si la fréquence d’une horloge a été modifiée, la fonction printFreq() est invoquée. Celle-ci invoque la fonction getFrequency(clockId) et envoie le résultat à l’interface série. De cette manière l’utilisateur qui a passé une commande de changement de fréquence reçoit en retour la fréquence effective de l’horloge après modification.
void analyzeCommand(char* data) {
  char firstLetter;
  int clockId;
  char thirdLetter;
  char fourthLetter;

  char dataTreat[50];
  char command[3];
  char buff[50];
  int value;

  removeSpaces(dataTreat, data);
  strtolower(data, dataTreat);
  
  firstLetter = data[0];
  
  //mySerial.println(data);
  //mySerial.println(firstLetter);
  //return;

  // Single Clock settings
  if ((firstLetter == 'c'))
  {
    strncpy(buff, data+1, 1);
    clockId = atoi(buff);
  
    // mySerial.println(clockId);
    
    if (!( (clockId == 0) || (clockId == 1) || (clockId == 2) )) {
    mySerial.println("Unknown clock id");
    return;    
    }

    if (strlen(data) < 4) { //c0sf + frequency on 4 digits minimum
      mySerial.println("Ill-formated command");
      return;
    }

    strncpy(buff, data+2, 2);
        
    // **************** Set frequency
    if (strcmp(buff,"sf") == 0) {

      // mySerial.println("sf ");
      
      strncpy(buff, data+4, strlen(data) -4);
      value = atoi(buff);

      if (value < SI5351_CLKOUT_MIN_FREQ) {
        mySerial.println("Frequency too low");
        return;
      }

      if (value > SI5351_CLKOUT_MAX_FREQ) {
        mySerial.println("Frequency too high");
        return;
      }
      
      ClockGenerator.setFrequency(clockId, value);
      ClockGenerator.displayAllClocks(); // pb sans doute de editMode
      printFreq(clockId);
    
    // **************** Get frequency
    } else if (strcmp(buff,"gf") == 0) {
      printFreq(clockId);

    // **************** Get phase step
    } else if (strcmp(buff,"gt") == 0) {
      mySerial.print("Clock ");
      mySerial.print(clockId);
      mySerial.print(" phase Step: ");
      mySerial.print(ClockGenerator.getPhaseStep(clockId));
      mySerial.println(" Hz"); 
 
    // **************** Set phase indice
    } else if (strcmp(buff,"sp") == 0) {

      strncpy(buff, data+4, strlen(data) -4);
      value = atoi(buff);

      if (value > 127) {
        mySerial.println("Phase indice must be less than 128");
      }
      ClockGenerator.setPhase(clockId, value); 
      ClockGenerator.displayAllClocks();
      printPhase(clockId);
                   
    // **************** Get phase
    } else if (strcmp(buff,"gp") == 0) {
       printPhase(clockId);
    
    // **************** Set drive 
    } else if (strcmp(buff,"sd") == 0) {
      
      strncpy(buff, data+4, strlen(data) -4);
      value = atoi(buff);

      if (! ((value < 4) && (value >= 0)) ) {
        mySerial.println("Drive indice must be 0 (2 mA), 1 (4 mA), 2 (6 mA) or 3 (8 mA)");
        return;
      }
      ClockGenerator.setDrive(clockId, value);
      ClockGenerator.displayAllClocks();
      printDrive(clockId); 
      
    } else if (strcmp(buff,"gd") == 0) {
      printDrive(clockId);  

    // **************** Set sweep params
    } else if (strcmp(buff,"ss") == 0) {
      
      strncpy(buff, data+4, strlen(data)-4); 

      char* ptr = strtok(buff, delimiter);
      int startFreq = atoi(ptr);
      int stopFreq = atoi(strtok(NULL, delimiter));

      bool active = true; // (boolean)activeInt;
      if (strcmp(strtok(NULL, delimiter),"0") == 0) active = false; 
      
      ClockGenerator.setSweepParamCx(clockId, startFreq, stopFreq, active);
      printCxSweep(clockId);
      return;     
      
    // **************** Get sweep params
    } else if (strcmp(buff,"gs") == 0) {
      printCxSweep(clockId);
      return;  
    }  
  
  // Parameters not clock specific   
  } else { 
    strncpy(buff, data, 2);    

    // **************** Get phase tied clocks 
    if (strcmp(buff,"gp") == 0) {      
      printPhaseTied();
      return;
    }
        
    // **************** Set phase tied clocks
    if (strcmp(buff,"sp") == 0) {
      strncpy(buff, data+2, 1);
      value = atoi(buff);      
      ClockGenerator.setPhaseTiedClocks((byte)value); 
      ClockGenerator.displayAllClocks();
      printPhaseTied();   
      return; 
    }

    // **************** Set global sweep params
    strncpy(buff, data, 8); 
    buff[8] = '\0';       // !!! Pourquoi fonctionne dans les autres cas alors que nécessaire a priori d'ajouter \0
    
    if (strcmp(buff,"sweepset") == 0) {
      
      strncpy(buff, data+8, strlen(data)-8);    
//      mySerial.println(buff);
      
      // initialize first part (string, delimiter)
      char* ptr = strtok(buff, delimiter);
      int nbStep = atoi(ptr);
      float period = atof(strtok(NULL, delimiter));  
//      mySerial.println(period, DEC);
      
      ClockGenerator.setNbSweep(nbStep);
      ClockGenerator.setSweepPeriod(period);
      ClockGenerator.displayAllClocks();
      printSweep();
      return;        
    }

    // **************** Get global sweep params
    strncpy(buff, data, 8);    
    if (strcmp(buff,"sweepget") == 0) {
      printSweep();
      return; 
    }

    // **************** Sweep start 
    strncpy(buff, data, 10);    
    if (strcmp(buff,"sweepstart") == 0) {
      if(ClockGenerator.initSweep()) {
        mySerial.println("Sweep should start");      
      } else {
        mySerial.println("There isn't any clock with sweep activated");              
      }
      return;
    }
    
    // **************** Sweep stop 
    strncpy(buff, data, 9);    
    if (strcmp(buff,"sweepstop") == 0) {
      ClockGenerator.stopSweep();
      mySerial.println("Sweep should stop");        
      return;
    }

    strncpy(buff, data, 4);
    buff[4] = '\0';      
    // **************** Set calibration
    if (strcmp(buff,"scal") == 0) {
      strncpy(buff, data+4, strlen(data)-4); 
      float cal = atof(buff);            
      ClockGenerator.setCalibration(cal); 
      printCalibration();   
      return; 
    }

    // **************** Get calibration
    if (strcmp(buff,"gcal") == 0) {
      printCalibration();   
      return; 
    }
    
    mySerial.println("Unknown command");
    if (mySerial==Serial)  info(); 
  }
}
  • Quelques fonctions pour retourner l’état du Générateur d’Horloge à travers la liaison série. Par exemple la fonction printFreq():
void printFreq(int clockId) {
  mySerial.print("Clock ");
  mySerial.print(clockId);
  mySerial.print(" frequency: ");
  mySerial.print(ClockGenerator.getFrequency(clockId));
  mySerial.println(" Hz");  
}
  • Des fonctions de mise en forme de données et la fonction info() qui aide l’utilisateur en affichant la syntaxe des commandes possibles.

Etape 7: Utilisation simple du sketch “ClockGen_serial_control.ino”

Envoi de commandes par le Moniteur Série

Envoi de commandes par le Moniteur Série

Vous pouvez charger le programme ClockGen_serial_control.ino sur le Générateur d’Horloge puis lancer le Moniteur Série et taper des commandes.

Par exemple, si vous tapez “c0 sf 1000000” et la touche “entrée”, vous allez modifier la fréquence de l’horloge 1 (id = 0) à 1000000 MHz et le Moniteur Série va ensuite afficher cette fréquence de manière à vous assurer que la commande a été exécutée correctement.

Toutes les commandes possibles sont affichées dans le Moniteur Série lorsque vous le lancez et ainsi que si vous tapez quelque chose d’incompréhensible.

Vous devrez modifier un peu le sketch pour pouvoir passer des commandes à partir du Moniteur Série. Il doit utiliser l’interface série Serial (c’est à dire en fait USBSerial) plutôt que Serial1 (qui sera utilisée pour communiquer avec une carte pour passer les commandes). Au début du programme, modifiez ceci

//#define mySerial Serial1    // Use Serial1 to communicate with a standalone device through the Rx and Tx pins
#define mySerial Serial       // Use Serial (=SerialUSB) to communicate with the Serial Monitor through the USB connector

Etape 8: Le programme « SendCommands.ino »

Le programme SendCommands.ino

Le programme SendCommands.ino

Ce programme doit être chargé sur la carte de contrôle pour:

  • Envoyer les commandes au Générateur d’Horloge.
  • Afficher sur l’écran OLED les commandes passées et les informations reçues.
  • Dans la fonction setup il envoi plusieurs commandes. Pour chaque commande il:
    • affiche la commande sur l’écran OLED.
    • envoi la commande au Générateur d’Horloge.
    • attend une ligne complète de réponse en retour.
display.clearDisplay();
  display.setCursor(0,0);
  display.println("c0 sf 1000000");
  display.display();

  mySerial.print("c0 sf 1000000\n"); // Need to add the \n that is recognized by the receiving software as end of data

  processed = false;
  while (!processed) {
    while (mySerial.available () > 0) { processIncomingByte (mySerial.read ());}
  }
  delay(pauseDelay);
  • Il comporte une fonction processIncomingByte() qui concatène les octets reçus. Elle est identique à celle contenue dans le programme ClockGen_serial_control.ino mais eu lieu d’appeler une fonction d’analyse de la ligne reçue, elle l’affiche sur l’écran OLED sans traitement.
void processIncomingByte (const byte inByte)
{
  switch (inByte) {

    case '\n':   // end of text
      input_line [input_pos] = 0;  // terminating null byte

      // terminator reached! process input_line here ...
      delay(pauseDelay);
      display.clearDisplay();
      display.setCursor(0,0);
      display.println(input_line);
      display.display();
      delay(pauseDelay);

      // reset buffer for next time
      input_pos = 0;  
      memset(input_line, 0, sizeof(input_line));     
      processed = true; 
      break;

    case '\r':   // discard carriage return
      break;

    default:
      // keep adding if not full ... allow for terminating null byte
      if (input_pos < (MAX_INPUT - 1))
        input_line [input_pos++] = inByte;
      break;
      
  }  // end of switch

} // end of processIncomingByte  <br>

Il faut aussi configurer l’OLED (dans le programme ClockGen_serial_control.ino nous n’avions pas configuré l’écran TFT car cela est fait dans la fonction begin() de la librairie ClockGen). Pour cela il faut inclure dans l’en-tête:

#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

Puis instancier l’objet de l’écran OLED

Adafruit_SSD1306 display(OLED_RESET);

Et le paramétrer dans la fonction setup()

void setup()   {                
  mySerial.begin(9600);
  
  // by default, we'll generate the high voltage from the 3.3v line internally! (neat!)
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 0x3C 
  // init done
  
  // Clear the buffer.
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(0,0);

  display.println("Sending");
  display.println("commands");
  display.println("to the");
  display.println("ClockGen");
  display.display();
  delay(pauseDelay);

...

Etape 9 : Réaliser la mini chaîne d’outils constitués d’une carte contrôleur et du Générateur d’Horloge

Contrôle par liaison série du Générateur d'Horloge

Contrôle par liaison série du Générateur d’Horloge

Le but étant de montrer une petite chaine d’outils, nous allons utiliser une carte 1284 Narrow pour envoyer les commandes au lieu de les taper dans le Moniteur Série. Toutes les commandes passées et les données reçues étant affichées sur l’écran OLED, nous allons pouvoir surveiller le fonctionnement sans recourir à un ordinateur.

Réalisation:

  • Alimentez la carte Narrow avec une source de tension par exemple de 12 volts.
  • Alimentez le Générateur d’Horloge grâce à la même alimentation.
  • Connectez une des broches Tx ou Tx1 de la carte Narrow à la broche Rx du Générateur d’horloge.
  • Connectez une des broches Rx ou Rx1 de la carte Narrow à la broche Tx du Générateur d’horloge.

Vous pouvez utiliser soit le port Serial (Rx, Tx) soit le port Serial1(Rx1, Tx1) de la carte Narrow. Il faut simplement choisir le port approprié dans le programme SendCommands.ino

#define mySerial Serial // If you want to user the first serial port. In this case disconnect the USB after programming to avoid interference with the USB
//#define mySerial Serial1 // If you want to user the second serial port (on the 1284 Narrow board for example Rx1 = 10, Tx1 = 11).

Etape 10: faire fonctionner la mini chaîne d’outils

Sending C0SF1000000

Envoi de la commande c0 sf 1000000

Voici ce qui doit se passer en ce qui concerne la carte Narrow lorsque vous appuyez sur le bouton Reset (de la carte Narrow):

  • Affichage d’un message d’accueil sur l’écran OLED: “Sending commands to the Clock Generator”.
  • Envoi de la commande “c0 sf 1000000”  pour fixer la fréquence de l’horloge 1 à 1 MHz et affichage de cette commande sur l’OLED.
  • Reception de “Clock 0 frequency: 1000000 Hz” et affichage sur l’OLED.
  • Envoi de la commande “sweepset 100;0.1”  pour définir 100 pas de 0.1 secondes pour balayer les fréquences et impression de cette commande sur l’OLED.
  • Réception de “Sweep steps: 100, sweep period: 0.10 s” et affichage de cette information sur l’OLED.
  • Envoi de la commande “c0 ss 10000000;20000000;1”  pour définir la fréquence de début (10 MHz), la fréquence de fin (20 MHz) du balayage sur l’horloge 1 et impression de cette commande sur l’OLED.
  • Réception de “Clock 0, start: 10000000, stop: 20000000, active: 1” et affichage de cette information sur l’OLED.
  • Envoi de la commande “sweepstart” et affichage de cette commande sur l’OLED.
  • Réception de “Sweep should start” et affichage de cette information sur l’OLED.
  • La fréquence change sur l’écran du Générateur d’Horloge toutes les 0.1 seconde et balaye la plage de 10 MHz à 20 MHz.

Voilà, j’espère que ce tutoriel vous a donné une compréhension à la fois globale et approfondie du fonctionnement de cette mini chaine d’outils qui montre un des aspects utiles du Générateur d’Horloge. Les mêmes principes peuvent s’appliquer à d’autres produits que je propose, par exemple le fréquencemètre compatible Arduino.

Leave a Reply

Your email address will not be published. Required fields are marked *