[Résolu] Librairie maison

Bonjour,
Je n'ai rien trouvé qui réponde positivement à ma question ni sur internet ni su ce forum.
Cette question est :
Peut-on faire nous mêmes des librairies, si oui :

  • doit-on télécharger un logiciel spécial ? (je suis sur mac)
  • est-ce la même référence si non est-elle sur www.arduino.cc/fr

Bonjour

Rien de plus facile que de faire une bibliothèque.
Contrairement à un environnement de développement traditionnel où les bibliothèques sont fournies dans des packages précompilés, sur Arduino, une bibliothèque n'est qu'un ensemble de fichiers sources CPP et H

Tu peut regarder comment est faite par exemple la biblio Servo qui se trouve dans le répertoire arduino\libraries\Servo
Tu trouveras :

Servo
+--- Servo.cpp      : le code de la bibliothèque
+--- Servo.h        : l'interface de la bibliothèque
+--- keywords.txt   : un fichier qui liste les différents mots clefs pour activer la coloration syntaxique
+--- examples       : le répertoire des exemples
         +--- exemple1 
                  +--- exemple1.ino
         +--- exemple2
                  +--- exemple2.ino

Le plus simple pour développer ta bibliothèque c'est de procéder comme pour un sketch normal (le sketch d'exemple) et d'avoir les sources dans le même répertoire :

MesSketches
    +--- MaLib
             +--- exemple1
                  +--- exemple1.ino
                  +--- MaLib.cpp      : le code de la bibliothèque
                  +--- MaLib.h        : l'interface de la bibliothèque
                  +--- keywords.txt   : un fichier qui liste les différents mots clefs pour activer la coloration syntaxique

L'IDE Arduino va ainsi ouvrir automatiquement dans d'autres onglets Malib.cpp et MaLib.h
Tu travailles sur l'exemple et la lib en même temps.

Quand tu es prêt, tu met en place comme indiqué plus haut.

Bonjour,

Il existe un tutoriel (en anglais) sur le site officiel arduino.cc :

Il existe aussi une version "francisé" de l'ancienne version du tutoriel officiel pour arduino <=0023 :
http://www.robot-maker.com/index.php?/tutorials/article/30-creer-une-bibliotheque-arduino/

Merci à vous deux pour votre aide.
Pour les utilisateurs de mac qui nous liront, le dossier "librairy" est accessible par :

Clic droit sur l'app. Arduino
Afficher le contenu du paquet
Contents
Ressources
Java

J'ai du ouvrir les *.cpp avec "TextEdit"
J'ai encore quelques questions et je vous les poserai plus tard mais juste une pour l'instant :
Dois-je l'écrire avec TextEdit ?

Merci pour votre aide !

Relis mon message.
j'explique comment faire avec l'IDE Arduino

Je cherche mais je confond *.h et *.cpp
Ma bibliothèque doit servir pour un ou plusieurs afficheur(s) comme ceux des réveils numériques (avec des 8)
H
HG HD
M
BG BD
B

Mon ancien programme est joint.

J'aimerais pouvoir :

  • créer des caractères personnalisés (0001001 pour =) avec "createChar"
  • avoir déjà 0123456789 avec "numLCD.write(x)"
  • tout effacer avec "numLCD.clear()"
  • Faire un ensemble de plusieurs '8' pour envoyer un nombre et non un chiffre à chaque '8'
  • le tester avec "numLCD.test()"

Je crois que la première partie de par exemple Serial.begin(9600); donne la bibliothèque et que la seconde partie sert à donner le void correspondant.

Merci de m'avoir lu et merci pour votre future aide !!!

Afficheur_ordi.ino (11.1 KB)

En général, un CPP est le fichier source qui contient l'implémentation, là où est le vrai boulot (fonctions et variables)
Le H est la définition de l'interface qui explique à ceux qui veulent l'utiliser comment l'utiliser.

Dans le cas des afficheurs 7-segments, avant de te préoccuper des de la bibliothèque, préoccupe toi de

  • comment ca marche
  • comment tu connecte a ton arduino
  • fait marche un sketch de test
    Si tu es grand débutant, ce n'est pas le moment de commencer a tout mélanger et de vouloir faire une bibliothèque dès le début

Repose les bases : que veux tu faire, commant penses tu y arriver.

Je profite du sujet pour exposer ma première tentative de librairie maison. j'ai bien le .c, le .h, le keywords.txt...
Ca ne veut pas compiler :

Mega_lcd_Keyb_debug.cpp.o: In function loop': C:\DOCUME~1\FREEPO~1\LOCALS~1\Temp\build8396374676808604553.tmp/Mega_lcd_Keyb_debug.cpp:36: undefined reference to kb_read()'
Mega_lcd_Keyb_debug.cpp.o: In function setup': C:\DOCUME~1\FREEPO~1\LOCALS~1\Temp\build8396374676808604553.tmp/Mega_lcd_Keyb_debug.cpp:28: undefined reference to keyB_init()'

Je comprends pas, car c'est pas dans mes fichiers que ça coince... une histoire de public / private? Je ne veux pas utiliser les classes, ce n'est vraiment pas justifié ici.

la lib est assez simple, donc je mets tout ici :

le .h :

#include "WProgram.h"

// fonctions
void keyB_init();
uint8_t kb_read();

// variables
volatile uint8_t kb_available;

le .c

#include <MEGA_LCD_KB_debug.h>
#include "WProgram.h"

volatile uint8_t tbl_key[16] = {0xBE, 0x77, 0xB7, 0xD7, 0x7B, 0xBB, 0xDB, 0x7D, 0xBD, 0xDD, 0xE7, 0xEB, 0xED, 0xEE, 0xDE, 0x7E};
volatile uint8_t tbl_btn[5] = {0x1E, 0x1B, 0x1D, 0x17, 0x0F};

#define btn_nobtn 0x1F
#define debounce 100  // délai anti-rebond
#define max_key_buff 16
volatile uint8_t kb_key = kb_nokey;
volatile uint8_t kb_tmp;
volatile uint8_t kb_index;
volatile uint8_t kb_buffer[max_key_buff];

void keyB_init(){
  DDRA = 0x07;  // trois leds en sortie
  DDRB &= 0xE0;  // B4:0 input : 5 boutons
  DDRK = 0xF0;
  PORTB |= 0x1F;
  PORTK = 0x0F;  // pulup clavier 4 x 4
  PCMSK2 = 0x0F;  // active PCINT23:16
  PCMSK0 = 0x1F;  // active PCINT4:0
  PCICR = 0x05;  // active PCI2 et PCI0;
}

uint8_t kb_read(){  // lit la prochaine touche dans le buffer
  static uint8_t kb_r_index;
  uint8_t key_to_return;
  
  if (kb_available){
    kb_r_index++;
    kb_r_index &= 0x0F;  // assure la rotation de l'index
    kb_available--;
    key_to_return = kb_buffer[kb_r_index];
  } else {
    key_to_return = kb_nokey;
  }
  return(key_to_return);
}

// la suite, plein de fonctions internes, ISR etc etc...

le programme qui utilise la lib :

#include <LiquidCrystal.h>
#include <MEGA_LCD_KB_debug.h>

LiquidCrystal lcd(38, 39, 40, 41, 42, 43);

void setup() {
  keyB_init();
  lcd.clear();
}

void loop() {
  if (kb_available){
    lcd.setCursor(0,0);
    lcd.print(kb_read(), HEX);
    lcd.print(' ');
  }
}

Comme promis j'envoie un exemple de programme :

int numLED1 = (2,3,4,5,6,7,8); //Définis l'afficheur n°1
int point = P; //Si Serial.available() > 0

void setup() {
  numLEDa.begin(1); //pinMode(..., OUTPUT); avec toutes les broches et définis le groupe afficheur a contenant l'afficheur n°1
  pinMode(Point, OUTPUT);
  Serial.begin(9600);
  numLEDa.test(); //Teste les broches (voir mon ancien programme)
  if(numLEDa.result() != 0) {
    Serial.println("Ces broches ne marchent pas :")
    Serial.write(numLEDa.result()) //Exemple : 0100101
}

void loop() {
  if(Serial.available() > 0) {
    numLEDa.write(Serial.read()); //Affiche le chiffre reçu sur le groupe afficheur a
    digitalWrite(point, HIGH); //Remplit sa fonction
  }
  delay(10); //Attend que Serial se remplisse
  if(Serial.available() == 0) {
    digitalWrite(point, LOW); //Dis que le dernier chiffre est affiché
  }
  delay(990); //Totalise 1"
  numLEDa.clear();
}

2 problèmes :

  • Ton .H et ton .C ne sont pas compatibles IDE 1.0
  • Ta Lib est en C alors que ton sketch INO est compilé comme du C++
    Hors, il s'avère que la fonction toto() dans toto.c n'est pas la même chose que toto() dans un fichier .cpp
    Donc quand ton test.ino (tranformé par l'IDE en test.cpp) cherche la fonction keyB_init() il cherche une fonction C++ et non pas C

la raison est que dans le fichier objet compilé, le C++ ajoute des caractères au nom de la fonction ce qui permet la notion de surcharge, c'est à dire d'avoir 2 fonctions qui ont le même nom mais pas les mêmes paramètres.
Ainsi dans un CPP tu as le droit de faire :

void toto( int a )
{
...
}

void toto( unsigned int a )
{
...
}

mais pas en C

Donc dans le fichier objet compilé depuis le C, tu n'auras qu'une fonction toto() alors que dans le fichier objet compilé depuis le CPP tu auras une fonction toto_param_int et une fonction toto_param_unsigned_int.

Donc ton test.ino cherche une fonction keyB_init_void et non pas une fonction keyB_init.

La solution consiste a ajouter ce que j'ai ajouté dans le fichier H

J'en ai profité pour déclarer aussi KB_NOKEY (en majuscule...) parce que sinon ca compilait pas :wink:

MEGA_LCD_KB_debug.zip (2.01 KB)

Super analyse Barbu!

Je regarde ce que tu as fait, et je vais voir pour KB_NOKEY, car je suis sous l'IDE22 (pas le courage de me mettre encore à la 1.0... Mais je pense que ça passera. (il va falloir que je mette en majuscule tous mes define (y'en a plein d'autres que j'ai pas mis pour ne pas alourdir mon post)? ou c'est juste une spécificité du 1.0? j'aime pas trop les majuscules en prog, je trouve que ça surcharge un peu trop...

A tout'!

C'est pas obligatoire, c'est un standard.

Il existe de nombreux standards de règle de codages.
Les règles de codages servent à ce que l'on identifie au 1er coup d'oeil les éléments. Suivants les règles on va pouvoir distinguer par exemple les variables globales des variables locales et des paramètres de fonctions. Distinguer les noms de types des noms de variables ou de fonctions, ...
Il en existe des tas différentes.

Mais il y au moins une règle sur laquelle tout le monde s'accorde de le début : les constantes en #define sont en MAJUSCULES.

Suivre une règle de codage, c'est un bon principe. Ca donne de la rigueur à ton code et ca aide à la relecture et à la maintenance ultérieure.
C'est comme l'indentation.
Le compilateur il s'en contrefiche de l'indentation.
Mais si tu indentes correctement ton code, tu sauras mieux le relire et le maintenir
Idem avec les règles de codages.

Et quand tu partages ton code soit pour l'offrir à la communauté soit pour poser une question sur le forum, c'est comme un post : si c'est mal écrit, cela ne donne pas envie de le lire et d'y répondre.

Yep!

Super fort Barbudor :wink:

Il faudrait aussi rappeler les règles pour les #includes.

Les guillements pour les libs crées dans le répertoire courant.
Les crochets pour les libs standards.

@+

Zoroastre.

Salut à vous deux.

Il faut que je vous avoue que j'ai fait l'impasse complète en prog à l'école (quel con... mais ça ne m'a pas empêché d'avoir mon BTS électro haut la main, car à l'époque en 95, la micro n'était pas trop importante). Je suis donc totalement autodidacte en prog. Je pensais que le C++ était juste du C avec quelque fonctionnalités en plus plus (la notion de x++, ++x par exemple), et que les deux pouvaient marcher ensemble...

De plus, selon les langages, l'un est sensible à la casse, pas l'autre, etc etc... et pour ce qui est des règles de de codage, je me contente juste de conserver des espacement de début de ligne dans les blocs pour retrouver facilement la fin du bloc, et j'ai tendance à nommer mes variables comme en basic (je crois) : "nom_de_la_variable" et non "nomDeLaVariable" comme il faudrait (je trouve la première forme plus lisible, c'est du perso)...

Pour revenir à ma lib maison, j'intègre les modifs et je teste ce matin même! Je suis sous IDE 0022, rappelons-le...

Merci encore à vous deux!

cinci

PS / EDIT :

In file included from C:\Program Files\arduino-0022\hardware\arduino\cores\arduino/WProgram.h:6,
from C:\Program Files\arduino-0022\libraries\MEGA_LCD_KB_debug/MEGA_LCD_KB_debug.h:8,
from C:\Program Files\arduino-0022\libraries\MEGA_LCD_KB_debug\MEGA_LCD_KB_debug.c:26:
c:/program files/arduino-0022/hardware/tools/avr/lib/gcc/../../avr/include/math.h:439: error: expected identifier or '(' before 'double'
c:/program files/arduino-0022/hardware/tools/avr/lib/gcc/../../avr/include/math.h:439: error: expected ')' before '>=' token

j'ai mis tout le bloc ci-dessous du .c en commentaire, et ça a compilé.

#include "Arduino.h"

#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "wiring.h"
#endif

et ça marche. Bon, faudrait un tuto un peu plus clair que ce qu'on trouve avec la lib Morse sur la façon de passer d'un prog à une lib, car j'aime pas trop ne pas comprendre ce que je fais, comme dans le cas présent. S'il le faut, je passerai au 1.0...

Super_Cinci:
Je pensais que le C++ était juste du C avec quelque fonctionnalités en plus plus (la notion de x++, ++x par exemple), et que les deux pouvaient marcher ensemble...

Oui et non.
Le C++ fait beaucoup plus que d'ajouter 2..3 fonctionnalités. En tout pas cas celles que tu cite : ++x et x++ existent depuis le début en C.
Mais la surcharge de fonctions que j'ai expliqué est un ajout qui impose un traitement différent sur les noms de fonctions.
Cela n'empêche pas de mélanger les 2, ils restent totalement compatible et la plupart du temps c'est transparent.
En dehors de la programmation objet, des templates etc ... le C++ ajoute au C :

  • la surcharge des fonctions et des opérateurs
  • la possibilité de déclarer des variables locales n'importe où et pas seulement en début de block.

La plupart du temps, je code dans un fichier CPP pour bénéficier sans m'en rendre compte des ajouts du C++ même si je ne fais pas de classes ou autre fonctionnalités purement C++.

De plus, selon les langages, l'un est sensible à la casse, pas l'autre, etc etc...

Tat le C que le C++ sont sensibles à la casse.

j'ai tendance à nommer mes variables comme en basic (je crois) : "nom_de_la_variable" et non "nomDeLaVariable" comme il faudrait

Il n'y a pas de "comme il faudrait". Ta règle est tout a fait valable que ce soit en C ou en Basic de même que l'inverse.
A part les define en majuscules qui est une règle de fait, toutes les règles sont possibles. En avoir une c'est mieux que ne pas en avoir.

j'ai mis tout le bloc ci-dessous du .c en commentaire, et ça a compilé.

#include "Arduino.h"

#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "wiring.h"
#endif

Arduino.h ne devrait être présent qu'une fois? j'ai merdé.
Essaye en enlevant juste le 1er #include Arduino.h et en gardant ce qui est entre #if ... #endif

Ce n'est pas temps le problème de passer d'un programme à une lib (les Lib Arduino n'étant pas de vrai lib) que le problème de tous les changements entre la version 022 et la version 1.0.
Perso je ne vois aucune raison de rester dans une vielle version alors que plusieurs problèmes ont été corrigés dans la lib core Arduino dans la v1.0.
Il vaut mieux avoir la 1.0(.1) et apprendre à migrer les exemples vers cette version plutôt que garder une version obsolète.

Bonjour,
J'ai tapé les éléments et les ai placés comme me l'a conseillé barbudor (merci).
J'ai étudié la biblio. LiquidCristal pour attribuer les broches mais comme ça ne compilait pas,
j'ai remplacé les "unit8_t" par "int" mais ça fait juste disparaître les "unit8_t was not declared in this scope".
Il ne colorie pas les appellations de "keywords.txt".
Il me dit que HIGH, LOW et mes constantes ne sont pas définies.
Est-ce qu'il faut mettre les fichiers dans la position classique pour que ça compile ?
J'ai mis le contenu de mon dossier. Je sais que pour l'exemple il porte mal son nom mais j'ai changé d'idée en cours de route.

Merci de votre aide !

keywords.txt (479 Bytes)

numLED.cpp (3.44 KB)

numLED.h (310 Bytes)

numLEDserial.ino (122 Bytes)

Pour la coloration syntaxique, cela est normal, cela est du a l'extension txt.

Pour ce qui est de ta librairie "Numled", je pense qu'elle ne devrai pas être dans ton dossier mais dans le dossier ou sont toutes tes librairies. N'oublie pas de nommer correctement ton dossier ou tu mets tes deux fichiers cpp et h.

Ensuite plusieurs remarques :

  • Dans ton fichier INO tu n'inclus pas ta librarie numLED
  • Dans ton INO tu écris : numLED.begin(9,2,3,4,5,6,7);
    Cela suppose que tu utilise un objet numLED mais il n'est pas déclaré !!

Ensuite suggestion dans ton switch case de la fonction write tu écris :

 case 0:
      digitalWrite(h, HIGH);
      digitalWrite(hg, HIGH);
      digitalWrite(hd, HIGH);
      digitalWrite(m, LOW);
      digitalWrite(bg, HIGH);
      digitalWrite(bd, HIGH);
      digitalWrite(b, HIGH);
    case 1:
      digitalWrite(h, LOW);
      digitalWrite(hg, LOW);
      digitalWrite(hd, HIGH);
      digitalWrite(m, LOW);
      digitalWrite(bg, LOW);
      digitalWrite(bd, HIGH);
      digitalWrite(b, LOW);

vu le nombre de LOW par rapport au HIGH je mettrais tout a HIGH et dans les CASE je mettrais la valeur nécéssaire a LOW tu diviseras la taille de ton SWITCH par trois.

Ensuite tu écris :

void numLED::draw(int eh, int ehg, int egd, int em, int ebg, int ebd, int eb) {
  if((eh) == 1) {
    digitalWrite(h, HIGH);
  }
  if((eh) == 0) {
    digitalWrite(h, LOW);
  }
  if((ehg) == 1) {
    digitalWrite(hg, HIGH);
  }
  if((ehg) == 0) {
    digitalWrite(hg, LOW);
  }
  if((ehd) == 1) {
    digitalWrite(hd, HIGH);
  }
  if((ehd) == 0) {
    digitalWrite(hd, LOW);
  }
  if((em) == 1) {
    digitalWrite(m, HIGH);
  }
  if((em) == 0) {
    digitalWrite(m, LOW);
  }
  if((ebg) == 1) {
    digitalWrite(bg, HIGH);
  }
  if((ebg) == 0) {
    digitalWrite(bg, LOW);
  }
  if((ebd) == 1) {
    digitalWrite(bd, HIGH);
  }
  if((ebd) == 0) {
    digitalWrite(bd, LOW);
  }
  if((eb) == 1) {
    digitalWrite(b, HIGH);
  }
  if((eb) == 0) {
    digitalWrite(b, LOW);
  }
}

tu pourrais le remplacer par :

void numLED::draw(int eh, int ehg, int egd, int em, int ebg, int ebd, int eb) {
    digitalWrite( h  , eh  );
    digitalWrite( hg, ehg );
    digitalWrite( hd, ehd );
    digitalWrite( m, em  );
    digitalWrite( bg, ebg );
    digitalWrite( bd, ebd );
    digitalWrite( b  , eb  );
}

En effet LOW=0 et HIGH=1

Privilégie :

 if( eb == 1)  digitalWrite( b, HIGH );
 else             digitalWrite( b, LOW );

à

 if((eb) == 1) {
    digitalWrite(b, HIGH);
  }
  if((eb) == 0) {
    digitalWrite(b, LOW);
  }

Sa évite de faire le test deux fois.

Comme il t'a été dit précédemment fais déjà un code qui marche sans faire de librairie optimise le, et personnellement quand je vois le contenu de ta librairie, je ne la trouve vraiment pas nécessaire.

Bonjour,

numero_744:
j'ai remplacé les "unit8_t" par "int" mais ça fait fuste disparaître les "unit8_t was not declared in this scope".

Il faut inclure <stdint.h> pour avoir ces types "dure" :wink:
Remplacer un uint8_t (8 bits non signé) par un int (16 bits signé) quand ce n'est pas nécéssaire est un non-sens car cela ralenti ton programme pour rien et le rend consommateur de ram inutilement :wink:

numero_744:
Il ne colorie pas les appellations de "keywords.txt".

Il faut que le fichier keywords.txt comporte des fins de lignes UNIX (soit \n) et non "windows" (soit \r\n).
Avec notepad++ il suffit de faire édition -> convertir les fin de lignes -> format UNIX.

numero_744:
Il me dit que HIGH, LOW et mes constantes ne sont pas définies.

Essaye :

#include "Arduino.h"

->

#if defined(ARDUINO) && ARDUINO >= 100
#include <Arduino.h>
#else
#include <WProgram.h>
#endif

--

Au sujet de ton code :

  1. Tes fonctions write(), clear(), draw() ne peuvent pas compiler, elle ont besoin de variables qui n'existe pas dans leur contexte.
    Tu doit mettre les variables hg, hd, m, ... en tant que membre de ta classe et les initialiser dans le constructeur.

  2. Les int -> uint8_t + #include <stdint.h>

  3. Dans la fonction draw() :

if((eh) == 1) {
    digitalWrite(h, HIGH);
  }
  if((eh) == 0) {
    digitalWrite(h, LOW);
  }

Par définition : HIGH = 1, LOW = 0, donc il suffit d'écrire :

digitalWrite(h, eh);
  1. Dans clear() et write(), pourquoi réinventer la roue, ta fonction draw() existe il suffit de l'appeler :wink:
void numLED::clear() {
  draw(LOW, LOW, LOW, LOW, LOW, LOW, LOW);
}
  1. Dans write() :
    Il manque les break; à la fin de chaque case !

-> J'ai fait un zip avec toute les modif :wink:

numLED.zip (1.06 KB)

Bonjour et merci, Blizzard27 et skywood.
Une question chacun :

  • Blizzard27 :
    Qu'est-ce que déclarer ?

Blizzard27:
Cela suppose que tu utilise un objet numLED mais il n'est pas déclaré !!

int ... = ...; ?

  • skywood :
    Cela ne compile pas mais dois-je changer
class numLED : public Pruint8_t {

en

class numLED : public Print8_t {

?
(As-tu compilé avec un exemple comme :

void setup() {
  numLED.begin(8,2,3,4,5,6,7);
}

void loop() {
  for(int a = 0; a <= 9; a++) {
    numLED.write();
  }
}

Merci encore !!!