Go Down

Topic: [1er Projet] Horloge Pong modifié (Read 7730 times) previous topic - next topic

DizHell

Bonsoir à tous,

Des petites news de mon projet. Alors pour faire cour j'ai tout recommencé suite au mauvais cablage de ma carte protoShield, et aussi au passage de mon PC sous Ubuntu.

A ce jour je fait mes test à l'arrache comme on dit avec tout plein de fil partout.
Ce qui fonctionne :
- Le module RTC,
- Le code du capteur de lumiére et le reglage auto de la luminosité de l'affichage,
- La température avec un buffer sur 20 mesures et calcul de la moyene,
- L'appui sur 2 boutons voir plus...
- L'affichage de l'heure, sec, température, et reglage luminosité,
- Le code de Pong fournit avec la classe HT1632c est adapté à mon code à 80%,

Mais là je galére sur une erreur de débutant et je n'arrive pas à m'en sortir tout seul, mes cours de prog sont assez loin dans ma memoire tout se que je me rappel c'est que je l'ai déjà rencontré, mais je n'arrive plus à me rappeler l'astuce à appliquer.

Venons en à mon code de ma fonction menu :
Code: [Select]
void switch_mode() {
  char* modes[] = {"Classic", "Rgl Heure"};
  flagMenu=1;

  if(menuCompt<80) {
    if(boutonA.uniquePress()){
      menuCompt=0;
      diz_mode++;
      if(diz_mode>=2){
        diz_mode=0;
      }
    }

    ledMatrix.setfont(16);
    int len = strlen(modes[diz_mode]);
// Sa bloque ici ...
    char toto[len]=(char) modes[diz_mode];
// ----------------------------------------
    for (int i=0; i<len; i++)
    {
      ledMatrix.putchar(0,(8+i*6),toto[i],1);
    }
    ledMatrix.putchar(0,0,'>',1);
    menuCompt++;
  }
  else
  {
    menuCompt=0;
    flagMenu=0;
  }
}

Voici l'erreur affiché par Arduino 1.0 :
Quote
error: cast from 'char*' to 'char' loses precision
error: variable-sized object 'toto' may not be initialized


En gros j'ai un tableau modes[] qui contient à chaque ligne la description de mes mode et menu, et pour afficher chacun de ces mode sur mon menu il me faut les saisir Caractère par Caractère via cette fonction :
"putchar(int x, int y, char c, uint8_t color = GREEN, uint8_t attr = 0, uint8_t bgcolor = BLACK);"

DizHell

J'ai résolu avec ce code :
Code: [Select]
int len = strlen(modes[diz_mode]);
    for (int i=0; i<len; i++)
    {
      ledMatrix.putchar(0,(8+i*6),modes[diz_mode][i],1);
    }

:%

fdufnews

Code: [Select]
    char toto[len]=(char) modes[diz_mode];

2 erreurs dans la même ligne
char toto[len]=
Tu n'as pas le droit de faire ça. La taille d'un tableau doit être connue à la compilation.
Si tu veux travailler sur des tableaux dynamiques, il faut utiliser des pointeurs et allouer la mémoire avec malloc().

(char) modes[diz_mode]
modes est un tableau de chaines de caractères donc tu ne peux pas faire un cast en (char)

DizHell

Bonjour à tous,

Un petit retour sur mon projet qui avance petit à petit...

J'arrive à géré la température, la luminosité, l'affichage en mode Pong et un menu Basique.

Mais je me pose une question qui pourrait remettre en cause tout mon code.

La plus part des projet sur cette matriceLed fonctionne grosomodo de cette maniére :
Code: [Select]
loop(){

Vérification du buffer et effacement de la led non utilisé si besoin.
Si menu actif
        Vérification du buffer et effacement de la led non utilisé si besoin.
Dessine dans buffer le mode menu
        Envoi du buffer à la MatriceLed pour affichage
sinon
        Vérification du buffer et effacement de la led non utilisé si besoin.
Dessine dans buffer le mode en court
        Envoi du buffer à la MatriceLed pour affichage
}

En gros il verifie efface et renvoi les donnée à la MatriceLed à chaque fonction d'affichage.

Alors que moi je suis partie dans l'optique d'effacer tout le buffer au debut du loop, et refaire tout les tracé.
Code: [Select]
loop(){

Efface tout le Buffer de l'afficheur LCD

Récupération de la valeur du Capteur de luminosité.

Récupération de la température

// Selection de l'affichage
Si menu actif
Dessine dans buffer le mode menu
sinon
Dessine dans buffer le mode en court

Réglage de la luminausité de la MatriceLed.
Envoi du buffer à la MatriceLed pour affichage
}

L'avantage est que mon loop ne doit pas etre bloqué par une fonction For pour faire défilé du texte (par exemple) ça me permet de géré plusieurs données animé en meme temps, mais je me pose la question de savoir si j'ai pas fait une bétise car sa va m'obligé à retaper une partie des fonctions d'affichage de la matriceLed (exemple le Scrool de text).

Vous en pensez quoi ???

De-plus j'aurai besoin d'info pour utiliser l'ethernetShield avec un arduinoMega, surtout sur la partie déclaration des PIN utilisé pour l'ethernet et la SD.


patg_

Je procède aussi en effaçant tout le buffer puis en calculant chaque led allumée, puis j'envoie le buffer à la matrice de led.

Dans mon cas j'ai un scrolling dans certaines situations et je le gère par une boucle dédiée (par décalage de bits etc..., j'en parle ici: http://breizhmakers.over-blog.com/article-un-peu-d-animation-ou-le-scrolling-a-base-de-max7219-105669349.html

J'ai aussi une autre sorte d'animation, plus lente celle-là, qui avance d'un pas à chaque itération de loop()

Mais dans les deux cas je commence par un buffer vide puis je l'envoie à la matrice une fois complètement calculé.
Mes Arduineries: http://breizhmakers.over-blog.com/

DizHell


Je procède aussi en effaçant tout le buffer puis en calculant chaque led allumée, puis j'envoie le buffer à la matrice de led.

Dans mon cas j'ai un scrolling dans certaines situations et je le gère par une boucle dédiée (par décalage de bits etc..., j'en parle ici: http://breizhmakers.over-blog.com/article-un-peu-d-animation-ou-le-scrolling-a-base-de-max7219-105669349.html

J'ai aussi une autre sorte d'animation, plus lente celle-là, qui avance d'un pas à chaque itération de loop()

Mais dans les deux cas je commence par un buffer vide puis je l'envoie à la matrice une fois complètement calculé.

Merci pour ton avis, donc ma solution reste viable, j'y ai pensé des le début de mon projet du fait de vouloir activer le maximum d'animation...
Mais je me suis trop souvent posé la question de la viabilité de mon projet avec cette optique et c'est pour cette raison que je n'ai pas encore attaqué les animation afin d'évite de retaper le code 2 fois si c'était pas réalisable.

Je vais regarder ton lien avec attention, pour mes scrool de text je pense utilisé la fonction milliss() pour faire une comparaison dans le temps sans bloqué le programme, je l'utilise d'ailleurs pour actualiser la valeur de la température seulement toute les 2 sec.

D'ailleurs en parlant de cette fonction j'ai une question toute bête :
Si je l'utilise pour faire des comparaison dans le temps, que ce passera t'il lorsque cette fonction arrivera à sa valeur maxi...?
Ma  Comparaison risque de ne plus marché, je présume.

Du coup quel peut bien être cette valeur maxi sur un arduino Mega1280 ?

patg_



D'ailleurs en parlant de cette fonction j'ai une question toute bête :
Si je l'utilise pour faire des comparaison dans le temps, que ce passera t'il lorsque cette fonction arrivera à sa valeur maxi...?
Ma  Comparaison risque de ne plus marché, je présume.

Si ça continue de marcher, car la différence des deux valeurs est toujours correcte (j'ai plus le lien qui explique ça en tête).
Mes Arduineries: http://breizhmakers.over-blog.com/

barbudor



Si je l'utilise pour faire des comparaison dans le temps, que ce passera t'il lorsque cette fonction arrivera à sa valeur maxi...?
Ma  Comparaison risque de ne plus marché, je présume.

Si ça continue de marcher, car la différence des deux valeurs est toujours correcte (j'ai plus le lien qui explique ça en tête).


Pour ce qui est du temps, il ne faut jamais comparer la valeur de millis() ou micros() en absolu mais toujours des différences.

Par exemple pour faire changer d'état une led toute les seconde (je zappe les initialisation/setup etc./..)

Première version : on conserve la date de l’évènement précédant et on calcule le temps écoulé depuis.
On reste en "unsigned long" car le temps écoulé depuis l’évènement précédant est toujours un nombre positif.

Code: [Select]
unsigned long derniere_date = 0;

byte etat_led = 0;
byte led = 13;

void loop()
{
  unsigned long maintenant = millis();
  unsigned long temps_ecoule = maintenant - derniere_date;
  if ( temps_ecoule >= 1000 )
  {
    digitalWrite( led, etat_led = ~etat_led );
    derniere_date = maintenant
  }
}


Dans certains cas, plutôt que de raisonner sur le temps écoulé depuis le précédent évènement, on préfère (ou on doit) calculer la date à laquelle le prochain évènement doit intervenir
Il s'agit donc de savoir si on se trouve avant ou après cet évènement
malheureusement ce code si ne marche pas :
Code: [Select]
if ( millis() > date_prochain_evenement )
{
}


Tout simplement parce que la valeur de millis() étant compté en millisecondes sur un entier de 32 bits, cette valeur reboucle par 0 toutes les 49 jours.
Donc ce code va marcher la plupart du temps mais va faire une connerie tout les 49 jours

Donc pour savoir si on a dépassé une date ou pas, on va travailler toujours en différence mais signée :

Code: [Select]
long date_prochain_evenement = (long)millis();   // le (long) est un cast qui force la valeur de millis() a être pris comme un long (signé) au lieu d'un unsigned long

byte etat_led = 0;
byte led = 13;

void loop()
{
  long maintenant = (long)millis();
  long temps_ecoule = maintenant - date_prochain_evenement;
  // si la valeur est négative on n'a pas encore atteint la date attendue
  // si la valeur est positive ou nulle, c'est fait
  if ( temps_ecoule >= 0 )
  {
    digitalWrite( led, etat_led = ~etat_led );
     // on ajoute 1 seconde pour que le prochain évenement se passe dans 1 seconde par rapport à l'évenement courant
     date_prochain_evenement += 1000;
  }
}


Au fait, pourquoi ai-je écrit :
Code: [Select]
     date_prochain_evenement += 1000;
Plutot que
Code: [Select]
     date_prochain_evenement = maintenant + 1000;
?
Barbuduino: Arduino sur Breadboard & VinciDuino: Clone Leonardo // WR703: Mini-routeur hacké // LauchPad MSP430 et Stellaris // Panda II Arduino-like .NetMF sous VisualC#
RTFC: Read That F.....g Code / RTFD: Read That F.....g Doc / RTFDS: Read That F.....g DataSheet / RTFS: Read That F.....g Schematic / Wot da ya wanna D.I.Y. today ?

DizHell

#53
Jun 01, 2012, 09:30 am Last Edit: Jun 01, 2012, 11:34 am by DizHell Reason: 1
Merci Barbudor pour ces explication bien détaillé, je n'utilise pas tout a fait la même méthode.

Pour l'instant je n'utilise millis() que pour récupérer la température d'un capteur qui met 750ms à se rafraichir tout seul.

Donc à a base il y avait un Delay(750) dans le code qui me bloquait tout durant cette période. (dommage qu'il n'y est pas de thread avec l'arduino).

Du coup voici mon code :
Code: [Select]
 if(millis() >= (tempActuMillis+1000)){   // Toutes les 1 secondes
   if(millis()>2000){   // Au lancement le programme attend 2 secondes avant de de récupéré la temp.
     temps[indexT]= sensors.getTempCByIndex(0) * 10; // Récupére la valeur du capteur et remplir le tableau "temps" afin de faire une moyene sur 10 récupérations
     indexT++;
     if(indexT==10){
       indexT=0;
       tempInit=false;
     }

   }
   // Actualisation de la connexion a la sonde
   sensors.requestTemperatures();
   tempActuMillis = millis();
 }
 // Calcul de la moyenne des 10 derniers relevé de Temp
 for(int x=0; x<9; x++){
   temp += temps[x];
 }
 temp = temp/10;
}


Voilà c'est un peu brut de pomme, mais je réfléchi à faire une classe qui pourrai gérer des timers en fonction soit de millis() soit d'une valeur RTC(sec, min, heure, jour) fournit par mon programme.

EDIT ou peut etre pas car je viens peut etre de trouver mon bonheur :
http://arduino.cc/playground/Code/Timer

barbudor

Je te propose de remplacer :
 if(millis() >= (tempActuMillis+1000))

Par
 if( (millis() - tempActuMillis) >= 1000)

Pour etre compatible avec le rebouclage des 49jours

Le 2nd test peut etre aussi supprimé en utilisant la methode 2) avec des longs signés au lieu d'unsigned long. Il suffit alors d'initialiser dans setup la valeur date_prochain_evenement a millis()+2000

Personne pour tenter de répondre a la question que je pose a la fin du precedant message ?
Barbuduino: Arduino sur Breadboard & VinciDuino: Clone Leonardo // WR703: Mini-routeur hacké // LauchPad MSP430 et Stellaris // Panda II Arduino-like .NetMF sous VisualC#
RTFC: Read That F.....g Code / RTFD: Read That F.....g Doc / RTFDS: Read That F.....g DataSheet / RTFS: Read That F.....g Schematic / Wot da ya wanna D.I.Y. today ?

fdufnews

Quote
Personne pour tenter de répondre a la question que je pose a la fin du precedent message ?

Pour ne pas accumuler les retards liés au temps de traitement.

barbudor

Je devrais préciser quand les questions sont interdites aux "Edison Members"  :D

Effectivement puisque il est impossible de garantir que le traitement sera fait exactement au bon moment, cette méthode évite que l'erreur s'accumule a chaque opération. Ainsi certaines opérations pourraient être effectuées en retard mais en moyenne l'intervalle entre les opérations sera correct.
D'ailleurs sans certains cas, cela pourrait ne pas être le comportement souhaité. Si on souhaite garantir un temps minimum entre opérations plutôt qu'un temps moyen (et donc laisser l'erreur s'accumuler et la moyenne être supérieure)  l'autre écriture serait alors valide.
Barbuduino: Arduino sur Breadboard & VinciDuino: Clone Leonardo // WR703: Mini-routeur hacké // LauchPad MSP430 et Stellaris // Panda II Arduino-like .NetMF sous VisualC#
RTFC: Read That F.....g Code / RTFD: Read That F.....g Doc / RTFDS: Read That F.....g DataSheet / RTFS: Read That F.....g Schematic / Wot da ya wanna D.I.Y. today ?

DizHell

Bonsoir à tous,

J'ai un BUG débile qui me fait cherché depuis trop longtemp.

Voici mon code :
Code: [Select]
    if(boutonA.uniquePress()){
      curseur_rgldate++;
    }
     if(curseur_rgldate==7){
        curseur_rgldate=0;
        Serial.println(curseur_rgldate);
      }

Petite explication, ce code à pour but d'incrémenté ma position dans les menu (via curseur_rgldate) lorsque j'appui sur le boutonA.
Par-contre si jamais je suis à la derniére position alors je remet le menu à 0 via curseur_rgldate=0 dans le deuxiéme if.

Là j'ai déjà dut en perdre la moitié de mes lecteurs...  :smiley-sweat:

Mon programme se conpile mais l'arduino se bloque lorsqu'il passe dans le 2eme if()... voici se qui j'ai eu sur le moniteur serie et je trouve celà bizare :
Code: [Select]
0






























En gros il me met plein d'espace à cette variable "curseur_rgldate", puis la valeur 0 (que j'ai demandé), et ensuite des retour à la ligne à gogo....

Petit précision : curseur_rgldate est déclaré avant le setup comme un int à 0.

zoroastre

Yep!

Pas sur de résoudre le problème, cependant...

Essayes avec :

Code: [Select]

if(curseur_rgldate >= 7)
...


En plus, il n'y a pas de else...pas bieeennn !!!

@+

Zoroastre.
Gné! ;)

DizHell

Justement c'était mon code à l'origine mais vu que sa bug je l'ai modifié...


En plus, il n'y a pas de else...pas bieeennn !!!

Pourquoi pas bien...? on n'est pas obligé de mettre une condition sinon à chaque if...

J'ai regardé ce matin et j'ai le même type de code pour un autre menu qui lui fonctionne nickel...

Donc je pense que l'arduino doit bugué dans la suite du code.
C'est bizarre quand même que je me retrouve avec des saut de ligne à l'infini dans le serial monitor.
Je vais vous mettre le code entier de mes 2 menu (celui qui marche et celui qui bug) dans la journée.

Tant que j'y suis, j'ai besoin d'info sur les broches utilisé par le module ethernet sur un MEGA1280 car j'utilise déjà le SPI pour la matriceLed et quand je test un code basique sa fait un conflit entre la matrice et le module ethernet.

Go Up