A présent, la “bougie” ne sait que faire une chose : imiter la lumière aléatoire d’une bougie. C’est déjà pas mal, mais je voudrais pouvoir communiquer par liaison série avec le circuit. Et cela sans que le programme “bougie” s’arrête.

Dans le précédent programme, la grande partie du temps de calcul a été perdu à rien faire. La fonction “delay(x)” force le processeur à ne rien faire pendant un temps x.

Dans un nouveau programme, je vais remplir la même tâche qu’avant (faire clignoter la lampe), mais en utilisant moins de temps de calcul. Ceci peut être fait en comparant le temps absolu depuis démarrage du processeur avec un temps enregistré. Ce temps est accessible via la fonction “millis()” qui fournit un nombre du type “unsigned long”:

#define PIN_PWM_OUT 0

unsigned long last_timestamp;

void lamp_setup(){
  pinMode(PIN_PWM_OUT, OUTPUT);
  last_timestamp = millis();
}

/* lamp driver */
void lamp_loop(){
  unsigned long timestamp = millis();
  if (timestamp - last_timestamp > 100)
    {
       analogWrite(PIN_PWM_OUT,random(128,255));
       last_timestamp = timestamp;
    }
}
 
void setup() {
  lamp_setup();
}

void loop() {
   lamp_loop();
}

Voilà donc un programme bien plus extensible que le dernier. Maintenant on peut ajouter d’autres fonctionnalités dans la boucle principale.

La classe SoftwareSerial et ses limites

La série Attiny25, 45 et 85 est performante, mais ne dispose pas de périphérie pour la communication UART. Cela limite le champ d’application, mais pour des liaison lentes on peut envisager l’utilisation de la classe SoftwareSerial qui vient avec les librairies Arduino.

SoftSerial envoie les bits conforme à UART utilisant des délais crées avec des commandes “nop”. La réception se fait de la même manière, mais utilisant des interruptions sur l’entrée Rx. Ces interruptions arrêtent le fonctionnement normal du processeur (la boucle principale) pour exécuter du code différent. Ici la capture et lecture du message du port série.

Plus d’infos sur le fonctionnement d’une liaison série par software se trouvent ici :

http://thegaragelab.com/a-software-uart-for-the-attiny85/

Ils utilisent une autre librairie mais le fonctionnement est similaire.

Le fonctionnement en détail de la librairie SoftwareSerial se comprend le mieux en lisant les fichiers SoftwareSerial.c et .h qui se trouvent dans le dossier des librairies Arduino.

D’abord, je vais mettre en place un petit programme de test :

#define PIN_PWM_OUT 0

unsigned long last_timestamp;

void lamp_setup(){
  pinMode(PIN_PWM_OUT, OUTPUT);
  last_timestamp = millis();
}

/* lamp driver */
void lamp_loop(){
  unsigned long timestamp = millis();
  if (timestamp - last_timestamp > 100)
    {
       analogWrite(PIN_PWM_OUT,random(128,255));
       last_timestamp = timestamp;
    }
}

/* serial */
void serial_setup()
{
  mySerial.begin(1200);
  mySerial.listen();
}

if (mySerial.available()!=0)
{
  mySerial.write(mySerial.read());
}

/* main */
void setup() {
  lamp_setup();
  serial_setup();
}

void loop() {
   lamp_loop();
   serial_loop();
}

Ce programme ne fait rien d’autre qu’envoyer l’octet reçu par liaison série par cette même. C’est une sorte d’écho.

Via le logiciel HTERM et un Arduino USB Serial Light Adapter je communique avec le Attiny.

L’envoi et la réception d’un byte fonctionne très bien, mais deux bytes successifs ne veulent pas passer. Le deuxième (et troisième etc.) byte est toujours corrompu.

Je pense que le problème est que la succession de deux bytes est trop rapide. Il me faut un moyen pour rendre un peu plus long le temps d’attente entre deux bytes envoyés par le PC ou le contrôleur.

Pour mieux comprendre le phénomène, il faut un oscillographe. Le mien n’est pas terrible, mais pour comprendre ce problème il est suffisant. La capture d’écran ci-dessous montre bien que les trois caractères “AVR” (0x41 0x56 0x52) se suivent sans véritable pause :

'AVR' par liaison série

‘AVR’ par liaison série

C’est bien ce que je craignait. Et le logiciel HTERM ne permet pas de modifier le temps entre l’envoi de deux bytes.

Ce qu’il faut retenir pour le contrôleur (qui sera basé Arduino), c’est qu’il faut un délai entre deux bytes envoyés. La longueur du délai reste à déterminer.

Introduire un délai dans l’envoi des messages

Puisque mes logiciels PC pour le port série ne permettent pas confortablement d’introduire des délais, j’ai décidé d’utiliser un autre Arduino pour accomplir cette tâche.

Le code est très simple, il s’agit de recevoir des bytes via liaison série hardware et de les transférer via SoftwareSerial en ajoutant une pause :

#include <SoftwareSerial.h>

SoftwareSerial mySerial(10, 11); // RX, TX

void setup()  
{
  Serial.begin(1200);
  mySerial.begin(1200);
}

void loop()
{
  while (mySerial.available()){
    Serial.write(mySerial.read());
    //delayMicroseconds(100);
  }
  while (Serial.available()){
    mySerial.write(Serial.read());
    //delayMicroseconds(100);
  }
}

Finalement, je n’ai même pas eu besoin du délai artificiel, car l’exécution même ajoute suffisamment de délais :

AVR par liaison série

‘AVR’ par liaison série

Cette-fois ci l’Attiny répond bien à tous les messages. Il reste tout de même à déterminer le délai minimal entre deux bytes. Mais ça c’est une autre histoire.