| Le passage de paramètres dans les fonctions |
Page 2 |
Si l'intérêt de l'écriture de fonctions paraît évident, la maîtrise du passage de paramètres est déclicate, surtout pour les paramètres qui ressortent des fonctions ...
J'ai fait une programme ultra-commenté pour synthétisé cela : "07_synthese_A" et ses routines associées.
L'impression de ces pages est certainement utile ...
#define versionx "07_synthese_A"
/*
GoodFields Synthese des regles de bases langage C ARDUINO
=========================================================
INTRODUCTION :
Ce programme tente de regrouper quelques explications et règles de base,
dans les paragraphes de commentaires /* */
/*
NOM et VERSION :
Il est prudent de nommer chaque programme par la 1° ligne ci-dessus
(16 caractères maximum pour affichage sur LCD).
'versionx' sera utilisé comme annonce sur la voie Serial ou le LCD
*/
//******************************************************************70**********
// BIBLIOTHEQUES
/*
Cette library/bibliothèque Streaming_ger.h permet de simplifier l'utilisation de Serial,
en chainant les différentes zones par des '&&', ainsi :
Serial.print (" i=");
Serial.print (i);
Serial.print (" j=");
Serial.prinln (j);
devient :
Serial && " i=" && i && " j=" && j && endli; // plus compact et clair non ?
On peut aussi utiliser : _HEX(i) (et autres) pour avoir une valeur en hexadécimal
NB: cette library utilisait initialement la surcharge de >>,
mais pour des raisons de compatibilité avec d'autres library, j'ai changé en &&
*/
#include <Streaming_ger.h>
// GESTION DU TEMPS (voir plus bas)
#include <Time_ger.h> // Time.h modifiée
#include <ger_time.h> // routines GoodFields
unsigned int tempo_petite = 25000; // 25s au premier coup
unsigned long int tempo_grande = 35000; // 35s au premier coup
unsigned long tours, tours_pm; // compteur de vitesse
//******************************************************************70**********
// DECLARATIONS de VARIABLES GLOBALES
/*
Ces déclarations globales ont l'avantage de donner accès à ces varaibales de
partout ( programme principal comme routines)
Mais l'inconvénient de réserver de la place dans la RAM,
qui est limité à 2048 octets dans un ARDUINO UNO !
*/
// DECLARATION des entrées-sorties
/*
#define : c'est une instaruction de compilation, c'est à dire pour le compilateur
Un #define est à utiliser pour définir des CONSTANTES plutôt que un 'int' ou
autre type de variable, ceci évite d'utiliser de la RAM.
Ici, e/s compatible module domotique (numéro 36)
*/
#define led_a 5
#define led_b 3
#define bp A0
int bp_etat, bp_memoire;
// vitesse de clignotement
/* *****************************************************************70**********
Le fait de donner une valeur à une variable l'initialise. On gagne un peu sur la partie initialisation.
*/
unsigned int tempo_a_reset = 300;
unsigned int tempo_b_reset = 550;
// temporisations
unsigned int tempo_a, tempo_b;
// GRAFCETS
int grafcet_a = 1, grafcet_b = 1;
/*
J'ai recherché la façon la plus économique de stocker un texte en mémoire :
Les plus économiques (noter qu'il faut une position de plus que la longueur du texte)
char texte[] = "ceci est un texte";
char texte[18] = "ceci est un texte";
Evidente, mais 'deprecated' c'est à dire à abandonner
char* texte = {"ceci est un texte"}; // 0 / 0 référence, WARNING deprecated
Faire appel à la fonction F() qui place le contenu dans la zone programme
(donc c'est une constante)
Serial && F("ceci est un texte") // +68 / -20
Comme pour un #define :
#define texte "ceci est un texte" // 0 / 0
Et ...
//char texte[18] = F("ceci est un texte"); // erreur de compil
Une fonction peut être utile :
strlen (texte) qui donne les nombre de caractères avant le \0 final de la chaine.
Alors que sizeof(texte) donne la longueur en octet de la VARIABLE.
*/
//******************************************************************70**********
// Chaines de caractères : strncpy et strncat
/* A FINALISER *** ??? (voir test 207)
//
// Voici une routine GER bien pratique :
// char* format_ib (int val, int n, int base, char* out) {
// formate un nombre entier relatif (-99999 à +99999) dans N caractères
// ATTENTION ! A l'appel bien vérifier que n < (longueur de 'out') -1
// 'strlen' est exact mais c'est la longueur utilisée, donc si le buffer n'est pas initialisé, c'est inutilisable !
// 'out' à l'appel peut être 'valueh' ou 'valuef'
//
// On veut obtenir : l=49:dec=0062 hex=0003E bin=00111110 oct=000076 B36=1Q
// index= 01234567 10 234567 20 234567 30 234567 40 234567 50 234567 60
// initialisation du buffer indispensable,
// car 'strncpy' ne pose pas le NULL final, et commence au debut de la chaine
// et 'strncat' commence au premier NULL trouvé, ajoute, puis pose un NULL
memset(valueh, 0, sizeof(valueh));
strncat (valueh, "dec=", 4);
// ajout + inutile
strncat (valueh + 4, format_ib (ix, 4, 10, tx2), 4);
strncat (valueh, " hex=XXXXX bin=XXXXXXXX", 23);
// l'intérêt de 'strncpy' est que l'on peut insérer des données au milieu du buffer sans écraser la suite
strncpy (valueh + 13, format_ib (ix, 5, 16, tx2), 5);
// sur cette ligne on obtient un WARNING à la compilation car 23+8 > 31, longueur du buffer
strncpy (valueh + 23, format_ib (ix, 8, 2, tx2), 8);
// ATTENTION : mais là, pas de problèmes !!! OR on dépasse la longueur du buffer à l'exécution,
// et c'est là que les ennuis commencent !
strncat (valueh, " oct=", 5);
strncat (valueh, format_ibX (ix, 6, 8, tx2), 6);
strncat (valueh, " B36=", 5);
// calcul puis transfert
format_ib (ix, 3, 36, tx2);
strncat (valueh, tx2, 3);
Serial && "l=" && strlen(valueh) && ":" && valueh && endli;
*/
//******************************************************************70**********
// déclarations pour tests
// Variables à tout faire
char texte[80] = "Texte Vide ";
// 1234567 10 234567 20 234567 30 234567 40 234567 50 234567 60 234567 70 234567 80
char textc[20] = "Texte Vide ";
int i, j, k;
float f, g, h;
// pour r05
float valeurs[10], valeurs2[10];
char* libel[] = {"Diametre", "Rayon", "Perimetre", "Surface", "Volume", "?", "?"};
/*
Si l'on a des routines dans des modules sources séparés,
il est bien de les mettre ici
*/
#include "_07_routines.h"
//******************************************************************70**********
// INITIALISATIONS
void setup() {
// initialize the digital pins
/*
En francais : déclaration des entrées / sorties
*/
pinMode(led_a, OUTPUT);
pinMode(led_b, OUTPUT);
pinMode(bp, INPUT);
/*
Pour les Entrées, le fait d'ecrire dedans un état HIGH mets en service
une résistance de tirage au +5V (ou 3,3V) (10 à 20 kOhms).
C'est bien pratique, cela simplifie le câblage externe : un simple bouton-poussoir
ou 'contact sec' peut ainsi être utilisé directement.
*/
digitalWrite(bp, HIGH); // mets en service la résistance de Pull-Up
// ligne série (pour traces)
/* j'ai pris l'habitude d'utiliser la vitesse de 57600,
car c'est le maximum admis par les ARDUINO Mini Pro en 3,3V à 8Mhz.
*/
Serial.begin(57600); // ou 9600 selon votre port COM
/*
Annonce de la version
Si on le fait sur un LCD, (lcd && versionx;) on peut ajouter :
delay (2000);
Pour avoir le temps de lire ...
*/
Serial && versionx && endli;
}
//******************************************************************70**********
// PROGRAMME PRINCIPAL
void loop() {
/* ***************************************************************70*****
* Le test qui suit n'a que pour objet d'éviter l'exécution
* du code des exemples à chaque tour !
* millis() est le nombre de millisecondes écoulées depuis le démarrage
* de l'ARDUINO, c'est un 'unsigned long'. Il repasse à 0 lorsqu'il arrive à
* la valeur 2^32-1 = 4294967295 soit 49j 17h 2m 47s. MAis ceci n'influe pas
* les calculs de temps passés et les temporisations.
*/
if (millis() < 10 ) {
/*
* Si l'on n'initialise pas l'horloge, elle commence
* le 1/1/1970 à 0:0:0 (c'est le 0 des horloges UNIX)
*/
setTime (9, 23, 00, 24, 11, 2015);
/*
* Chapitre sur les passages de paramètres aux routines
* ====================================================
* Les routines sont dans le module séparé : _07_routines.h
* Une routine simple , par exemple, pour calculer la circonférence d'un cercle :
* voir explications dans la source de cette routine
*/
f = 12.407; // diamètre pour les exemples
Serial && "Diam\xE8tre =" && f && endli;
r01_circonference (f);
/*
Un peu plus sophistiqué : retour = valeur calculée
voir explications dans la source de cette routine 2
*/
Serial && "Pourtour =" && r02_circonference(f) && endli;
/* ***************************************************************70*****
* On ne peut retourner d'une routine qu'une seule valeur :
* octet(byte ou char), int ou float.
* Si l'on veut retourner plusieurs valeurs, ou une chaine de caractères,
* il faut fournir dans l'appelant une variable passée en argument
* (on passe en fait l'adresse de la variable).
* voir explications dans la source de cette routine 3
*/
memset (textc, '.', 20); textc[20] = 0;
// textc est trop petit et provoque une erreur 'volontairement'
k = r03_volume(f, textc);
Serial && "r03:" && k && "car.<" && textc && ">" && endli;
// indispensable car test de longueur dans la routine
memset (texte, '.', 60); texte[60] = 0;
k = r03_volume(f, texte);
Serial && "r03:" && k && "car.<" && texte && ">" && endli;
delay(50);
//CA BLOQUE ICI §?§
/* ***************************************************************70*****
* Une autre solution plus élégante est de retourner l'adresse de la chaine.
* Ici, on initialise le buffer qui est supposé assez grand pour l'opération!
* Cette initialisation peut être dangereuse si le buffer est trop petit !
*/
memset (textc, '.', 20); textc[20] = 0;
Serial && "r04:" && strlen(textc) && "car.<" && r04_vol(f, textc) && ">" && endli;
memset (texte, '.', 60); texte[60] = 0;
Serial && "r04:" && strlen(texte) && "car.<" && r04_vol(f, texte) && ">" && endli;
/* ***************************************************************70*****
* Ici, on va utiliser des array de valeurs
*/
valeurs[0] = f; // diametre
r05_calcul(valeurs);
Serial && "r05:" && endli;
for (i = 0; i < 5; i++) Serial && libel[i] && "=" && valeurs[i] && endli;
valeurs2[0] = f / 4; // diametre
r05_calcul(valeurs2);
Serial && "r05:" && endli;
for (i = 0; i < 5; i++) Serial && libel[i] && "=" && valeurs2[i] && endli;
valeurs[0] = f / 10.; // diametre
r05_calcul(valeurs);
Serial && "r05:" && endli;
for (i = 0; i < 5; i++) Serial && libel[i] && "=" && valeurs[i] && endli;
/* ***************************************************************70*****
Gestion du temps 'GoodFields'
=============================
L'arduino comporte une horloge. On peut donc facilement utiliser
des variables décrivant le temps :
Il faut inclure Time_ger.h (dérivée de Time.h, encore pour des raisons de
compatibilité et de francisation)
*/
Serial && hour() && ":" && minute() && ":" && second() && endli;
/*
Pour faciliter l'usage, et avoir un formatage plus propre, j'ai créé des
routines (dans ger_time.h, voir détails dans la source) telles que :
*/
Serial && horodatage_d() && " date et heure" && endli;
Serial && horodatage_lcd(10, 0, 0) && " heure locale (h=hiver e=ete)" && endli;
Serial && horodatage_lcd(0, 10, 0) && " temps UTC ou GMT" && endli;
Serial && horodatage_lcd(0, 0, 10) && " date en clair" && endli;
/*
* A propos, les modules ger_xxx.h sont dans un répertoire de library 'Goodfields_ger'.
* Ce n'est pas une library, mais un paquet de modules sources.
*
* Gestion des TEMPORISATIONS
* ==========================
* Pour gérer des temporisations de façon simple, voici ma méthode :
* On va déclarer une tempo comme un 'unsigned int' ou 'unsigned long int'.
* Lorsque l'on veut démarrer la tempo, on y mets la valeur désirée (en millisecondes)
* Lorsque cette valeur tombe à 0, la tempo est écoulée !
* Voir dans la source de 'ger_top_centieme();' les explications de mise en oeuvre
*/
} // if (millis() < 10 ) {
/* ***************************************************************70*****
* Le programme principal ne commence réellement qu'ici
*
* Gestion du temps
* Ce compteur est destiné à calculer le nombre de tours de programme principal
* exécuté en 1 minute
*/
tours++;
// gestion horloge, generation tops ...
ger_top_centieme();
/*
* Actions cadencées selon les tops générés ci-dessus
* Les variables top_xx contiennent le nombre de millièmes écoulés depuis
* le top précédent. Il faut les remettre à 0 après utilisation.
*/
// 1 ms
if (top_1) {
// ger_tempos (tempo_X1,top_1); // si on veut des tempos très très courtes
top_1 = 0;
}
// Nb : en général, top_1 = au moins 2 (du à la gestion des ms de l'ARDUINO)
// 10 ms
if (top_10) {
ger_tempos (tempo_petite, top_10); // top_10 est un int contenant les ms passées
ger_tempol (tempo_grande, top_10); // tempos en 'unsigned long int' (valeurs > 65536)
ger_tempos (tempo_a, top_10);
ger_tempos (tempo_b, top_10);
top_10 = 0;
}
if (top_100ms) {
// top_100ms est un int contenant les ms passées
// ger_tempos (tempo_X,top_100ms);
top_100ms = 0;
}
// pour gérer les tempos plus lentes, par exemple en SECONDES :
if (top_1000ms) {
// top_1000ms est un int contenant les ms passées
// ger_tempos (tempo_en_ms,top_1000ms);
top_1000ms = 0;
}
// pour gérer les évenements plus lents (chaque minute)
if (top_55s) {
Serial && horodatage_h() && "top 55" && endli;
top_55s = false; // true/false
}
if (top_60000ms) {
tours_pm = tours;
tours = 0;
Serial && horodatage_h() && "top Minute " && tours_pm && "t/minute = " && tours_pm / 60 && "t/s" && endli;
top_60000ms = false; // true/false
}
//--------------------------------
// utilisation de temporisations cycliques (cadencement):
if (tempo_petite == 0) { // tempo terminée
tempo_petite = 33000; // 33 sec. // maxi 65,535 sec
Serial && horodatage_h() && "top Tempo courte" && endli;
}
if (tempo_grande == 0) { // tempo terminée
tempo_grande = 123000; // 2 minutes et 3 sec.
Serial && horodatage_h() && "top Tempo longue" && endli;
}
//--------------------------------
// affichage de changements d'état du Bouton-poussoir
bp_etat = !digitalRead(bp);
if (bp_memoire != bp_etat) {
if (bp_etat) {
Serial && "BOUTON appuy\xE9 grafcet_a=" && grafcet_a && " tempo_a=" && tempo_a && " grafcet_b=" && grafcet_b && " tempo_b=" && tempo_b && endli;
} else {
Serial && "BOUTON lach\xE9" && endli;
}
// mise en mémoire pour le prochain tour
bp_memoire = bp_etat;
}
/* ***************************************************************70*****
* Ici, 2 grafcets indépendants commandant 2 leds
*/
/* ***************************************************************70*****
* GRAFCET A
*/
switch (grafcet_a) {
case 1:
if ( tempo_a == 0 ) { // si la tempo est terminée,
digitalWrite(led_a, HIGH); // on allume la LED
tempo_a = tempo_a_reset; // on arme la tempo
grafcet_a++; // et on passe à l'étape suivante
}
break; // cette instruction vous fait sauter à la fin du "switch"
// sinon, on continue, et cela fait perdre du temps, et il peut arriver que d'autre "case" fonctionnent !
case 2:
if ( tempo_a == 0 ) {
digitalWrite(led_a, LOW); // turn the LED off by making the voltage LOW
tempo_a = tempo_a_reset; // on arme la tempo
grafcet_a = 1; // on reboucle
}
break;
// si grafcet_a n'a pas une valeur correcte, on passe ici
default:
grafcet_a = 0; // on arrête
break;
} // fin du "switch"
/* ***************************************************************70*****
* GRAFCET B
*/
switch (grafcet_b) {
case 1:
if ( tempo_b == 0 ) { // si la tempo est terminée,
digitalWrite(led_b, HIGH); // on allume la LED
tempo_b = tempo_b_reset; // on arme la tempo
grafcet_b++; // et on passe à l'étape suivante
}
break; // cette instruction vous fait sauter à la fin du "switch"
case 2:
if ( tempo_b == 0 ) {
digitalWrite(led_b, LOW); // turn the LED off by making the voltage LOW
tempo_b = tempo_b_reset; // on arme la tempo
grafcet_b = 1; // on reboucle
}
break;
// si grafcet_a n'a pas une valeur correcte, on passe ici
default:
grafcet_b = 0; // on arrête
break;
} // fin du "switch"
// FIN GRAFCET B
/* ***************************************************************70*****
* FIN PROGRAMME PRINCIPAL
*/
}
//******************************************************************70********80
//34567 10 234567 20 234567 30 234567 40 234567 50 234567 60 234567 70 234567 80
//******************************************************************70********80
ET voici les les ROUTINES
// #define _07_routines.h
/* ***************************************************************70**********
Routine qui affiche la circonférence du cercle de diamètre 'diametre'
A noter : le nom d'une routine ne PEUT PAS commencer par un chiffre.
*/
void r01_circonference (int diametre) {
float circ;
/*
PI est un 'built-in', c'est à dire utilisable directement comme ça
*/
circ = PI * diametre;
/*
Les caractères accentuées posent problème :
pour : utiliser :
à : \xE0
â : \xE2
é : \xE9
è : \xE8
ù : \xF9
*/
Serial && "circonf\xE9rence =" && circ && endli;
return;
}
/* ***************************************************************70**********
Cette seconde routine retourne la valeur à l'appelant
Ceci est utilise si on veut en faire autre chose ...
*/
float r02_circonference (int diametre) {
float circ;
circ = PI * diametre;
return circ;
}
/* ***************************************************************70**********
Conversions numérique->vers->texte : dtostrf(FLOAT, WIDTH, PRECISION, BUFFER)
Cette routine transforme un 'float' en chaine de 'width' caractères,
dont 'precision' chiffres après la virgule, dans le 'buffer'.
Ces routines sont dans : #include<stdlib.h>
On a aussi AUTRES UTILITES :
char * dtostrf (double __val, signed char __width, unsigned char __prec, char *__s)
char * ltoa (long val, char *s, int radix)
char * utoa (unsigned int val, char *s, int radix)
char * ultoa (unsigned long val, char *s, int radix)
long random (void)
void srandom (unsigned long __seed)
long random_r (unsigned long *__ctx)
char * itoa (int val, char *s, int radix)
http://www.nongnu.org/avr-libc/user-manual/group__avr__stdlib.html
*/
/* ***************************************************************70**********
On ne peut retourner d'une routine qu'une seule valeur,
octet(byte ou char), int ou float.
Si l'on veut retourner plusieurs valeurs, ou une chaine de caractères,
il faut fournir dans l'appelant une variable passée en argument
(on passe en fait l'adresse de la variable avec *).
* * *
Cette troisième routine modifie un buffer texte donné par l'appelant ,
Avec un test de sécurité sur la longueur du texte :
En effet, si l'on dépasse la longueur réelle du buffer tranmsis,
on va écraser les variables qui suivent (on ne maîtrise rien)
Ceci est un effet de bord des pointeurs en C, et un gros problème !
Le test n'est donc pas superflu, sauf à être sûr de soi ! ? !
*/
int r03_volume (float dia, char *tex) {
/* strlen (tex) marche si et SEULEMENT SI le buffer est initialisé
* correctement avec des espaces et un NULL en fin. Sinon, il faut faire
* confiance au programmeur qui sait ce qu'il fait ...
* Et ne pas faire ce test (mais c'est dangereux !)
* if (sizeof(tex) < 53) sizeof ne marche pas,
* car retourne la longueur du pointeur !
*/
if (strlen(tex) < 53) {
strcpy(tex, "Err"); // si pas assez de place, on retourne Erreur
return strlen(tex); // retourne le nombre de caractères
}
strcpy (tex, "Une boule de diam\xE8tre "); // copie (donc dès le début de tex)
/*
On notera que le décalage dans tex est obtenu par simple addition du
nombre de caractères.
*/
dtostrf(dia, 6, 3, tex + strlen(tex)); // 28
strcat (tex, " a un volume de "); // 44
dtostrf(PI * pow((dia / 2), 3) * 4 / 3, 8, 2, tex + strlen(tex)); // 53
strcat (tex, "\0");
return strlen(tex); // retourne le nombre de caractères
}
/* ***************************************************************70**********
* On peut aussi retourner le buffer texte, ou plutot son adresse.
* Ceci a l'avantage de rendre l'écriture d'appel plus élégante encore :
* Serial && r04_vol(f, textc) && endli;
*/
char* r04_vol (float dia, char *tex) {
if (strlen(tex) < 53) {
strcpy(tex, "Err"); // si pas assez de place, on retourne Erreur
return tex;
}
//
strcpy (tex, "Une boule de diam\xE8tre "); // 22
dtostrf(dia, 6, 3, tex + strlen(tex)); // 28
strcpy (tex + strlen(tex), " a un volume de "); // 44
dtostrf(PI * pow((dia / 2), 3) * 4 / 3, 8, 2, tex + strlen(tex)); // 53
strcat (tex, "\0");
return tex;
}
/* Remarque :
* le buffer est donc déclaré dans les varaibles globales, on pourrait donc
* l'utiliser directement, sans le passer en paramètres. Mais alors la routine
* ne pourrait 'sortir' que dans ce buffer, ce qui a rendrait moins 'générale'.
*/
/* ***************************************************************70**********
* On peut aussi travailler sur des array de valeurs
*/
int r05_calcul (float *val) {
val[1] = val[0] / 2.; // rayon
val[2] = val[0] * PI; // périmètre
val[3] = PI * val[0] * val[0] /4; // surface
val[4] = PI * pow((val[0] / 2), 3) * 4 / 3; // volume
return true;
}
/* ***************************************************************70**********
*/
/* ***************************************************************70**********
*/
/* ***************************************************************70**********
#if 0==1 est une solution sûre et élégante pour mettre hors service un morceau de code.
*/
#if 0==1
/*
PS : on pourrait retourner un pointeur sur le pointeur de texte ... mais bon, je crois que j'ai un exemple, mais c'est pas simple !
à tester sur ARDUINO, bien que je pense que cela soit très lourds !
/*
J'ai découvert cette fonction en programmant en Perl, elle permet de découper une chaîne de caractère suivant un délimiteur et de placer chaque sous-chaîne dans un tableau terminé par NULL.
Tant que strtok nous renvoi une adresse non nulle (1), on augmente la taille du tableau d'une case (2) dans laquelle on stocke l'adresse retournée par (3).
*/
char **str_split (char *s, const char *ct)
{
char **tab = NULL;
if (s != NULL && ct != NULL)
{
int i;
char *cs = NULL;
size_t size = 1;
/* (1) */
for (i = 0; (cs = strtok (s, ct)); i++)
{
if (size <= i + 1)
{
void *tmp = NULL;
/* (2) */
size <<= 1;
tmp = realloc (tab, sizeof (*tab) * size);
if (tmp != NULL)
{
tab = tmp;
}
else
{
fprintf (stderr, "Memoire insuffisante\n");
free (tab);
tab = NULL;
exit (EXIT_FAILURE);
}
}
/* (3) */
tab[i] = cs;
s = NULL;
}
tab[i] = NULL;
}
return tab;
}
#endif
/* **************************************************************************
*/
/* **************************************************************************
*/
/* **************************************************************************
*/
/* **************************************************************************
#if 0==1 est une solution sûre et élégante pour mettre hors service un morceau de code.
*/
#if 0==1
#define versionx "207_tests "
// programme minimum de test
//**********************************************************
// BIBLIOTHEQUES
// ajoutées
#include <Streaming_ger.h>
#include <ger_format.h>
// *********** EEPROM
#include <EEPROM.h>
//**********************************************************
// DECLARATIONS
int i, j, k; // etat : programme / RAM
//char* texte = {"ceci est un texte"}; // 1632 / 202
//const char* texte = {"ceci est un texte"}; // 0 / 0
//char texte[18] = "ceci est un texte"; // -6/ -2
//#define texte "ceci est un texte" // -6 / -2
//#define texte F("ceci est un texte") // +20 / -20
//char* texte[] = {"c","e","c","i"," ","e","s","t"," ","u","n"," ","t","e","x","t","e"}; // +32 / +32
//char texte[18] = F("ceci est un texte"); // erreur de compil
//**********************************************************
// INITIALISATIONS
void setup() {
// ligne série (pour traces)
Serial.begin(57600); // ou 9600 selon votre port COM
Serial && versionx && endli;
// Serial && texte;
}
//**********************************************************
// PROGRAMME PRINCIPAL
char tx2[30] = "12345678901234567890123456789";
void loop() {
// Serial && sp(millis()) && ":" ;
// Serial && sp2(millis(), tx2) && "=" && tx2 && "!" && endli;
gr_eeprom_mot (16 * (1 + millis() / 1000), 16, tx2);
Serial && tx2 && ".EEPROM." && strlen(tx2) && endli;
delay(1001);
}
//**********************************************************
// sous-PROGRAMMEs
//**********************************************************
/*
ceci ne peut pas marcher :
Le char tx est effacé avant la sortie du sp
Si on veut l'exploitare, il faut le rendre 'static',
il se retrouve alors en variable gloable et consomme de la RAM
Donc la solution est en sp2
char *sp(unsigned long ii) {
char tx[15]; // 5108 / 241
formatt((float) ii / 1000., 's', 5, tx);
Serial && tx && "=tx=";
return tx;
}
*/
/*
Il faut passer en argument l'adresse d'une chaine globale que le sp2 va remplir
En retour, on peut seulement renvoyer un entier ou byte, donc par exemple le nombre d'octets générés
*/
int sp2(unsigned long ii, char *tx2 ) {
int i = 5;
formatt((float) ii / 1000., 's', i, tx2);
Serial && tx2 && "=tx2=";
return i;
}
//********************************************************************
// récupère n octets dans un char à partir de adr // 5842 / 274
int gr_eeprom_mot (int adr, int n, char *motx) {
// motx : chaine (à initialiser !)
int i;
for (i = 0; i < min(n, strlen(motx)); i++) { // 16 par sécurité, mais bon ...
motx[i] = EEPROM[adr + i];
}
motx[i] = '\0';
// Serial && "motx=" && adr && "=" && motx && "=" && endli;
return i;
}
//********************************************************************
#endif
| Sortie sur la ligne série de ce programme |
07_synthese_A
Diamètre =12.41
circonférence =37.70
Pourtour =37.70
r03:3car.<Err>
r03:52car.<Une boule de diamètre 12.407 a un volume de 1000.00>
r04:3car.<Err>
r04:52car.<Une boule de diamètre 12.407 a un volume de 1000.00>
r05:
Diametre=12.41
Rayon=6.20
Perimetre=38.98
Surface=120.90
Volume=1000.00
r05:
Diametre=3.10
Rayon=1.55
Perimetre=9.74
Surface=7.56
Volume=15.62
r05:
Diametre=1.24
Rayon=0.62
Perimetre=3.90
Surface=1.21
Volume=1.00
9:23:0
24/11/2015 09:23:00 date et heure
24/11 09:23:00h heure locale (h=hiver e=ete)
24/11 05^23^00U temps UTC ou GMT
Mar 24 Nov 2015 date en clair
09:23:25 top Tempo courte
09:23:35 top Tempo longue
09:23:55 top 55
09:23:58 top Tempo courte
09:24:00 top Minute 1359847t/minute = 22664t/s
...
Documents en ligne
Documents en ligne (en anglais)
Photos de la page :
|
|
|
|
|
07_alim |
07_boitier |
07_boitier_arrierefaceavant |
07_boitier_face |
07_boitier_interieur |
|
|
|
|
|
07_boitier_modem |
07_boitier_std |
07_boitier_std_arduino_pb |
07_boitier_std_arduino_pile |
07_boitier_std_porte |
|
|
|
|
|
07_clavier_analogique |
07_clavier10 |
07_entree |
07_IOport |
07_LCD_Optrex |
|
|
|
|
|
07_LM2596_alim_3A |
07_LM2596_alim_chargeur_batterie |
07_modem |
07_monprotoshiel_ar |
07_monprotoshield |
|
|
|
|
|
07_monprotoshield_ar |
07_monprotoshield_detail |
07_monshield |
07_monshield_soudures |
07_MP3_sparkfun |
|
|
|
|
|
07_planchette |
07_proto_shield_enplace |
07_pullup |
07_relais |
07_shield_proto |
|
|
|
|
|
07_shield_proto_complete |
07_shield_proto_monte |
07_shield_proto_vide |
07_sortie_NPN |
07_sorties |
|
|
|
07_sorties_esp |
07_V9 |
07_velleman2853 |
Dernière mise à jour : 11:39:53 18/09/2020