boule lumineuse avec attiny85
Article mis en ligne le 30 juillet 2021

par Rémi

Maintenant que mon attiny85 fonctionne, je peux revenir à mon projet initial :
faire une boule lumineuse. Mais celle-ci doit rouler, c’est le principe des boules en générale, et elle doit changer de couleurs (grâce à des leds à l’intérieur) en fonction des mouvements.

Matériel

- Un attiny en ordre de marche (pour un premier test, j’utilise un arduino nano) ;
adxl345
- Un accéléromètre afin de capter les mouvements de l’objet. Mais sur l’attiny, il y a peu de broches, il faut donc un accéléromètre qui peut parler en I2c : 2 broches de communications (et deux pour vcc/gnd bien sûr). L’Adxl345 (pas de pub pour gotronic, mais c’est là que je l’ai trouvé), le fait très bien
- Des diodes multicolores. J’ai choisi trois Module LED RGB Gravity DFR0605. Elles ont 1 fil de communication pour la couleur, et se connectent entre elles facilement. Acheté chez Gotronic (je ne suis toujours pas payé par eux).
module led
un module d’alimentation 5v
- Une batterie lipo 3,2v
- Une boule transparente qui puisse s’ouvrir (il faut pouvoir tout faire rentrer dedans !)
- Des bandes de caoutchouc pour amortir les chocs Un interrupteur ? C’est bien ça !!

Code de test

Il n’a rien de compliqué. Par contre, il y a quelques prémisses à respecter :
→ inclure la librairie NeoPixel dans l’IDE Arduino ;
→ accessoirement, faire de même avec celle de l’Adxl pour comprendre comment cela fonctionne, avec les exemples inclus.
Ensuite, j’ai fait simple : les diodes changent de couleur en fonction de la position de l’accéléromètre. C’est tout.
Pour le test, tout est monté sur Arduino Nano, et cela fonctionne avec le code fourni.
 

code adxl et led sur arduino nano

 
 
 

Tests sur Digispark

Tant que ce n’est pas dans la boule, avec ma batterie de récupération de vieux portable. je vais faire quelques tests par sécurité. Ce n’ai pas parce que j’ai validé le principe, que cela ça va marcher comme ça du premier coup.

Intégrons ceci dans le Digispark.

Avant, il faut modifier les connexions utilisées, car elles ne sont pas identiques entre l’attiny85 et le nano
digispak pinout

Regardez bien le schéma ci-dessus pour ne pas se méprendre sur les numéros des broches

→ La connexion de l’unique lien de communication des diodes se fera sur une broche (= PB4) (test fait avec uniquement les leds : cela fonctionne)
→ Pour communiquer avec l’ADXL345, ce sont les pins de l’I2C. La 5 (=PB0) pour SDA, la 7 (=PB2) pour SCL. La, par contre, Zéro. Pas de résultat. Les diodes ne réagissent pas. Il a donc fallu faire des tests pour comprendre si l’ADXL fonctionnait avec l’Attiny85. J’ai pas mal cherché. Une première solution est de faire une communication série avec entre attiny85 et l’ordinateur, via une prise FTDI, et minicom sur l’ordinateur (sous linux). La librairie à utiliser est SoftSerial.h. Un exemple de test :

#include <SoftSerial.h>
// Définitions
#define rxPin 1
#define txPin 3
SoftSerial mySerial(rxPin, txPin);

void setup(){
 mySerial.begin(9600);
 analogWrite(0,1); // la diode du ‘cœur qui bat, pour voir que l’attiny est "alive"
}

void loop(){
 mySerial.print("Input Val: ");
 mySerial.print("azerty");
 mySerial.println();
}

Sur la sortie de minicom, j’ai bien une sortie de texte "Input Val : azerty" qui s’affiche en boucle. Maintenant, reste à voir ce que me sort l’adxl....


→ Après plusieurs semaines de tests dans tous les sens, et un peu d’aide du forum arduino.cc, il apparaît qu’il y a un problème de compatibilité entre la librairie digispark installée, et la librairie Wire.h utilisée. Peut être que mon alimentation via l’USB, n’est pas optimale… Utiliser l’i2c, avec une alimentation en USB, semble causer des problèmes de synchronisation d’horloge (on gagne de la praticabilité d’un côté, mais on perd des fonctionnalités de l’autre). On commence par changer de librairie : utilisation de AttinyCore. Pour l’installer dans l’IDE Arduino, ajouter la ligne https://github.com/SpenceKonde/ATTinyCore dans la configuration. Ensuite, c’est comme toute utilisation de nouveau matériel. Je suppose que vous connaissez si vous lisez ce que j’écris. Retour au code de test :

#include <SoftwareSerial.h>
#include <Wire.h>

// Definitions pour le serial-debug
#define rxPin 1
#define txPin 3
SoftwareSerial mySerial(rxPin, txPin);

#define ADXL345 (0x53) //address of Accelerometer
#define ADXL345_X (0x32) //register for X value from Accelerometer
#define ADXL345_Y (0x34) //register for Y value from Accelerometer
#define ADXL345_Z (0x36) //register for Z value from Accelerometer

byte _buff[6];

char POWER_CTL = 0x2D;  //Power Control Register
char DATA_FORMAT = 0x31;

void setup()
{
 mySerial.begin(9600);
 Wire.begin();
 initAccelerometer();
 delay (500);
}

/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
void loop()
{
 readAccelerometer(ADXL345_X, _buff);
 mySerial.print("X= ");
 mySerial.println((((int)_buff[1]) << 8) | _buff[0]);
 mySerial.print("Y= ");
 mySerial.println((((int)_buff[3]) << 8) | _buff[2]);
 mySerial.print("Z= ");
 mySerial.println((((int)_buff[5]) << 8) | _buff[4]);
 delay(500);
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

void initAccelerometer(){
 // writeRegister(ADXL345, POWER_CTL, 0x08);
 writeRegister(ADXL345, DATA_FORMAT, 0x01);//set range to +/-4G
 writeRegister(ADXL345, POWER_CTL, 0x08); //power up and enable measurements
 mySerial.println("init ok");
}

void writeRegister(uint8_t address, uint8_t reg, uint8_t val){
 Wire.beginTransmission(address);
 Wire.write(reg);
 Wire.write(val);
 Wire.endTransmission();
}

void readAccelerometer(byte address, byte _buff[]){
 Wire.beginTransmission(ADXL345); // start transmission to device
 Wire.write(address);    
 Wire.endTransmission();         // end transmission
 Wire.beginTransmission(ADXL345); // start transmission to device
 Wire.requestFrom(ADXL345, 6);    // request 6 bytes from device
 int i = 0;
 while (Wire.available())
 {
   _buff[i] = Wire.read();    // receive a byte
   i++;
 }
 Wire.endTransmission();         // end transmission
}

uint8_t readRegister(uint8_t address, uint8_t reg){
 Wire.beginTransmission(address);
 Wire.write(reg);
 Wire.endTransmission();
 Wire.requestFrom(address, 0x01);
 return Wire.read();
}

Mais ce qui devait arriver, arriva : la compilation remonte des erreurs :

In file included from /home/remi/Arduino/test4-adxl-sur-attiny85/test4-adxl-sur-attiny85.ino:2:0: /home/remi/.arduino15/packages/ATTinyCore/hardware/avr/1.5.2/libraries/Wire/src/Wire.h: In function 'uint8_t readRegister(uint8_t, uint8_t)': /home/remi/.arduino15/packages/ATTinyCore/hardware/avr/1.5.2/libraries/Wire/src/Wire.h:141:13: note: candidate 1: uint8_t TwoWire::requestFrom(int, int) uint8_t requestFrom(int, int); ^~~~~~~~~~~ /home/remi/.arduino15/packages/ATTinyCore/hardware/avr/1.5.2/libraries/Wire/src/Wire.h:138:13: note: candidate 2: uint8_t TwoWire::requestFrom(uint8_t, uint8_t) uint8_t requestFrom(uint8_t, uint8_t); ^~~~~~~~~~~ Le croquis utilise 3356 octets (50%) de l'espace de stockage de programmes. Le maximum est de 6586 octets. Les variables globales utilisent 180 octets (35%) de mémoire dynamique, ce qui laisse 332 octets pour les variables locales. Le maximum est de 512 octets.

Ce ne sont que des warnings, mais j’aime les codes sans warming. La solution c’est de « caster » certaines valeurs. Il a donc fallu modifier les lignes

SoftwareSerial mySerial(rxPin, txPin);
 Wire.requestFrom(address, 0x01);

Et là, c’est bonheur ! Zéro erreur !!!!
L’envoi vers le Digispark ce fait avec la lib AttinyCore de la même façon que la lib officielle.
Il faut juste choisir, dans ’Outils’->’Type de carte’ : ’ATTInyCore’ puis ’ATtiny85 (Micronucleus/Digispark)’

On laisse les paramètres par défaut (ce sont ceux affichés sur la copie d’écran), et ça roule :

Le croquis utilise 3356 octets (50%) de l'espace de stockage de programmes. Le maximum est de 6586 octets.
Les variables globales utilisent 180 octets (35%) de mémoire dynamique, ce qui laisse 332 octets pour les variables locales. Le maximum est de 512 octets.
> Please plug in the device (will time out in 60 seconds) ...
> Device is found!
connecting: 16% complete
connecting: 22% complete
connecting: 28% complete
connecting: 33% complete
> Device has firmware version 2.5
> Device signature: 0x1e930b
> Available space for user applications: 6650 bytes
> Suggested sleep time between sending pages: 7ms
> Whole page count: 104  page size: 64
> Erase function sleep duration: 728ms
parsing: 50% complete
> Erasing the memory ...
erasing: 55% complete
erasing: 60% complete
erasing: 65% complete
> Starting to upload ...
writing: 70% complete
writing: 75% complete
writing: 80% complete
> Starting the user app ...
running: 100% complete
>> Micronucleus done. Thank you!

Et est-ce que cela fonctionne ?

init ok
X= 101
Y= 7
Z= -83
X= 89
Y= 2
Z= 0
X= 133
Y= 1
Z= 21
X= 133
Y= 2
Z= 23
X= 133
Y= 3
Z= 24
X= 89
Y= 26
Z= -70
X= 133
Y= 4
Z= 24
X= 132

oui !!!!!! J’ai des valeurs négatives, mais mes premiers tests sur le nano étaient identique. Et je suis en alimentation USB. Cool.
Et voici le code final fonctionnel, diodes branchées

fichier final sur attiny85

Reste à tout monter dans la boule :)

Je posterai la suite ici, en fin de mois j’espère.