[RESOLU] Créer ma première librairie... (PPMread)

Bonjour,

Je voudrais créer ma première librairie et elle aura pour rôle de fournir les valeurs lues d'un récepteur de modélisme (au format PPM).

Pourquoi une librairie :

  • J'utilise très souvent ce code que j'ai déjà développé, sous forme de librairie ça le rendra facilement intégrable et désintégrable :wink:
  • Je le fais parfois évoluer, et c'est pénible de copier/coller mes évolution dans les différents projets

Mais voila, c'est ma première librairie, je viens de loin, alors je suis parti de l'exemple de la librairie Morse.h sur le site Arduino et je l'ai vidé de son contenu et renommé en PPMread, ça me donne déjà une coquille vide.

Le H :

/*
  PPMread.h - Library for reading PPM 6ch (negative modulated).
*/

#ifndef PPMread_h
#define PPMread_h

class PPMread
{
  public:
    PPMread(int pin);
    void begin();
    void read();
  private:
    int _pin;
};

#endif

Le CPP :

/*
  PPMread.cpp - Library for reading PPM 6ch (negative modulated).
*/

#include "PPMread.h"

PPMread::PPMread(int pin)
{
}

void PPMread::begin()
{
}

void PPMread::read()
{
}

Et ça devrait s'utiliser à peu près comme ça comme ça :

#include <PPMread.h>

PPMread ppm(13);

void setup()
{
  ppm.begin();
}

void loop()
{
  ppm.read();
}

Pour l'instant mon soucis, c'est que j'aimerai ne pas avoir de paramètre pin dans PPMread, le fameux 13 ne me sert à rien, peut-on s'en passer ?

Oui oui pas de problème, vire les "int pin"

Tu as déclaré une variable _pin associé à ta classe.
Il suffit de l'initialiser dans le constructeur lorsque tu instancies ta classe (soit en passant la valeur en argument, soit en fixant une valeur par défaut). Ensuite les méthode que tu vas créer pourront utiliser cette variable directement et tu n'auras plus besoin de la passer en argument.

Bha oui mais ça ne veut plus compiler si j'enlève le paramètre pin (dont je n'ai pas besoin) :

Voici le H :

/*
  PPMread.h - Library for reading PPM 6ch (negative modulated).
 */

#ifndef PPMread_h
#define PPMread_h

class PPMread
{
public:
  PPMread();
  void begin();
  void read();
private:
};

#endif

Et le CPP :

/*
  PPMread.cpp - Library for reading PPM 6ch (negative modulated).
 */

#include "PPMread.h"

PPMread::PPMread()
{
}

void PPMread::begin()
{
}

void PPMread::read()
{
}

juste une question pour mieux cerné ton souci ,
tu cherche toujours a utiliser la pin 13 ou tu change dans ton code a certaint endroit ?

car si c'est du definitif , j'imagine que dans ta fonction tu peut simplement metre
le 13 la ou tu a besoin et te passer de a variable _pin.

ou alors comme dit fdufnews tu peut la rendre facultative lors de l'initialisation tu la declare dans le .h

comme cela je pense que ça doit marcher

PPMread::PPMread(int pin=13)
{
}

cela dit je suis pas sur d'avoir compris ton probleme!

En fait je veux juste m'en débarrasser, je n'ai pas besoin de paramètre.

Ma librairie utilisera une fonction HARDWARE du PIN 8, donc je n'ai pas besoin de ce paramètre.

Bonjour,

La déclaration de l'objet "ppm" dans ton code d'exemple est faux :wink:

PPMread ppm();

et :

PPMread ppm;

Ce n'est pas la même chose :wink:

Si ton constructeur n'as pas d'argument tu doit utiliser la seconde syntaxe.

Yes, ça compile, merci skywodd.

Je m'attaque donc maintenant aux "fonctions", et vous fait part de mon second problème :

J'ai alimenté la fonction begin avec le paramétrage du timer1 :

/*
  PPMread.cpp - Library for reading PPM 6ch (negative modulated).
*/

#include "PPMread.h"

PPMread::PPMread()
{
}

void PPMread::begin()
{
    // Timer1 setup
  TCCR1A=B00000000; // OCR2A/OCR2B : disconnected, Timer: normal mode
  TCCR1B=B00000010; // Falling edge CAPTUREPIN detection, Timer:normal mode, Prescaler=clk/8 
  TIMSK1=B00100001; // Activate CAPTUREPIN interrupt & OVF interrupt
}

void PPMread::read()
{
}

Et ça coince encore à la compilation, ce coup-ci au niveau des regsitres HARD, mais aussi au niveau des valeurs binaires :roll_eyes: :

Pourtant je n'utilisais aucune librairie supplémentaire dans mon code...

Il manque #include <Arduino.h>

Yesss ! Thank you, j'avai essayé avec #include "Arduino.h"... alors que c'est #include <Arduino.h>

Bon ça compile bien avec ça :

/*
  PPMread.cpp - Library for reading PPM 6ch (negative modulated).
*/

#include "PPMread.h"
#include <Arduino.h>

PPMread::PPMread()
{
}

// Données de capture du Rx
boolean endTrame=0,failsafe=0;
volatile unsigned int vchUp[8];
volatile unsigned int vchPos[6];
byte curEdge;


ISR(TIMER1_CAPT_vect)
{
  vchUp[curEdge]=ICR1; // Capture des timestamp 1 à 6
  curEdge++;
  if (curEdge>7) {     // A partie du 7ème...   
    TCNT1=0;           // RESET du counter pour éviter le FailSafe
    if ((vchUp[7]-vchUp[1]) > 30000) {  //Si la trame totale dépasse 15ms - Trame KO ou mauvaise synchro
      curEdge=0;            //Remise à 0 du compteur de fronts                      
    }
    else {                  //Sinon, une bonne trame est capturée, on calcule donc la valeur des canaux
      curEdge=1;
      for (int i=0;i<6;i++) {
        vchPos[i]=(vchUp[i+2]-vchUp[i+1]); //Mesure des canaux (diviser par 2 pour obtenir des µs)
      }
      endTrame=1;           // Pour dire à la MainLoop que de nouvelles valeurs sont disponibles
    }
  }
}

ISR(TIMER1_OVF_vect)
{
  failsafe=1;  // Le compteur a attends sa limite (32ms), on déclenche donc le FailSafe
}


void PPMread::begin()
{
    // Timer1 setup
  TCCR1A=B00000000; // OCR2A/OCR2B : disconnected, Timer: normal mode
  TCCR1B=B00000010; // Falling edge CAPTUREPIN detection, Timer:normal mode, Prescaler=clk/8 
  TIMSK1=B00100001; // Activate CAPTUREPIN interrupt & OVF interrupt
}

void PPMread::read()
{
  
}

J'espère que mes interruptions vont être correctement prises en compte :roll_eyes:

J'attaque maintenant la dernière partie, la fonction read, qui va permettre au programme "utilisateur" de lire les données du Rx... et la ça se complique parce qu'avant de vouloir librariser le truc c'était géré sous forme de tableau :

  if (endTrame==1) {
    cli();
    for (int i=0;i<6;i++) {
      if (vchPos[i] > (cha[i]+ecart) || vchPos[i]< (cha[i]-ecart)) { // Si la nouvelle valeur dépasse l'hystérésis
      cha[i]=vchPos[i]; // Recopie les valeurs des canaux
      }
    }
    sei();
    endTrame=0;
    }

Et j'ai cru comprendre qu'on ne pouvait pas passer un tableau en retour d'une fonction... à votre avis quel est la meilleure façon de faire, sachant que cette fonction ne demande rien en entrée et qu'elle doit retourner 6 valeurs ?

Je précise que la simplicité d'utilisation doit surtout être du côté de l'utilisateur, donc ça peut être un peu tordu côté librairie mais il faut que ça reste simple côtré "main code".

à votre avis quel est la meilleure façon de faire, sachant que cette fonction ne demande rien en entrée et qu'elle doit retourner 6 valeurs

La fonction pourrait retourner un pointeur mais c'est généralement mal compris par l'utilisateur lambda et source de problèmes.
Le plus simple serait de passer en argument un pointeur sur un tableau déclaré par la fonction appelante.

fdufnews:
La fonction pourrait retourner un pointeur mais c'est généralement mal compris par l'utilisateur lambda et source de problèmes.

Ca obligerait en plus à développer dans le main code un "truc" pour lire la mémoire et saucissonner le contenu dans des variables...

fdufnews:
Le plus simple serait de passer en argument un pointeur sur un tableau déclaré par la fonction appelante.

La fonction read, écrirait directement à l'emplacement mémoire indiqué, et mettrait à jour les variable du main code sans les connaitre, c'est l'idée ?
Dis-moi si j'ai bien compris, ça s'utiliserait comme ça :

unsigned int cha[6];
unsigned int* rxPoint=&cha[0];

void setup() {
}
void loop() {
  ppm.read(rxPoint)
}

??

Ça fonctionne, et j'en suis le premier étonné.

J'ai finalement fait évolué la fonction ppm.read() pour qu'elle renvoi une valeur 0, 1 ou 2 :

0 = Pas de nouvelles trame capturée depuis le dernier appel de la fonction
1 = Des nouvelles valeurs ont été mise à jour en mémoire
2 = Le signal radio est perdu, les donnée en mémoire sont figées

Un example d'utilisation :

#include <PPMread.h>          // On inclue la librairie

// Données du Rx
unsigned int cha[6];           // Les valeurs des canaux

PPMread ppm(&cha[0]);          // On lance l'instance, en fournissant le pointeur

void setup()
{
  Serial.begin(115200);        // On prepare la sortie série
  ppm.begin();                // On démarre la lecture PPM en arrière-plan
}

void loop()
{
  if (0 < ppm.read()){   // Si des nouvelles valeurs ou FAILSAFE
    if (1 < ppm.read()){   // Si FAILSAFE
      Serial.println("FAILSAFE");

    }
    else {               // Si des nouvelles valeurs, la variable est DEJA A JOUR
    for (int i=0; i < 6; i++){ // Imprimer les valeurs des canaux sur le port série
        Serial.print(cha[i]);
        Serial.print(";");
      }
      Serial.println(";");

    } 
  }
}

Il me reste à nettoyer le code & imaginer un truc cloisonné au niveau des interruptions... merci à tous, j'avance à pas de géants grâce à ce forum.

PPMread.h (247 Bytes)

PPMread.cpp (1.77 KB)