Robotique-Projet
Bonjour et bienvenu sur le forum ROBOTIQUE-PROJET

Merci de nous rejoindre, pour avoir accès aux forum en entier,

il suffis juste de s'inscrire sa prends 2 minutes, et bien sur de faire sa

présentation, au plaisir de se croisé sur le forum.
Robotique-Projet

Forum sur la Robotique & Informatique & Programmation


Vous n'êtes pas connecté. Connectez-vous ou enregistrez-vous

Voir le sujet précédent Voir le sujet suivant Aller en bas  Message [Page 1 sur 1]

Seb03000

avatar
Fondateur
Fondateur
La programmation sur Arduino se fait
dans un langage qui s'inspire à la fois du C et du C++ . Le C
intervient surtout pour la création de librairies, ce que
nous verrons plus tard.

Pour l'instant, nous resterons essentiellement dans le domaine de la programmation en C.

Sachons déjà pour commencer que dans
tout code, il est fondamental de glisser des commentaires qui peuvent
être utiles soit lorsqu'on le reprend après un long
moment, soit lorsque l'on diffuse notre code.

Les commentaires ne sont pas évalués par le compilateur, ils ne s'adressent qu'au développeur.

En C et en C , les commentaires sur une seule lignes commencent par // et ceux placés sur plusieurs lignes
sont encadrés par les signes /* et */.

I -
Les types

Pour programmer, nous allons utiliser
plusieurs sortes de données. Par exemple, si nous voulons incrémenter
un compteur, nous utiliserons une variable de type
entier. Si nous voulons calculer la moyenne d'une série de données
fournies par un capteur, nous aurons besoin d'un nombre réel. S'il
s'agit de tester une condition, nous pourrions avoir besoin
d'un simple booléen. Voici un rappel des principaux types :


  • void : c'est un mot clef utilisé pour spécifier qu'il n'y a pas de variable,
    on le retrouve
    généralement dans le prototype d'une fonction pour indiquer que
    celle-ci ne renvoie pas de paramètre (ou qu'elle n'en prend pas)



  • boolean : c'est une variable logique qui ne peut prendre que deux états : false, true. Elle
    sert essentiellement à tester des conditions, des états binaires.



  • char : traditionnellement, le char est utilisé pour les caractères. En fait, il s'agit
    d'une variable codée sur un octet, qui peut donc prendre 256 valeurs (2^8) différentes. Les caractères ayant longtemps été indexés sur un table à 256 entrées,
    on a tendance à ne réserver l'usage du type char qu'aux seuls caractères. Mais il peut de fait être utilisé pour toute variable qui n'a pas besoin d'excéder
    l'intervalle [-128 ; 127].



  • unsigned char : le mot clef unsigned signifie que l'on considère des valeurs
    positives
    uniquement. Ainsi, si un char permet de représenter des valeurs allant de -128 à 127, le type unsigned char utilise quant à lui
    l'intervalle [0, 255].



  • byte : le byte est un synonyme du unsigned char, c'est-à-dire qu'il se
    code sur un seul octet et prend des valeurs pouvant aller de 0 à 255. Il est particulièrement adapté pour les sorties PWM.



  • int : un int (pour integer) est un entier relatif codé
    sur deux octets, ce qui signifie qu'il possède 2^16 valeurs différentes. Il peut prendre des valeurs comprises dans l'intervalle [-32,768 ;
    32,767]
    .



  • unsigned int : c'est un entier positif codé sur deux octets, prenant ses
    valeurs dans l'intervalle [0 ; 65,535].



  • word : synonyme de unsigned int.



  • long : entier relatif codé sur 4 octets, pouvant donc prendre des valeurs
    allant de -2,147,483,648 à 2,147,483,647.



  • unsigned long : entier positif codé sur 4 octets, prenant dès lors ses
    valeurs dans l'intervalle [0 ; 4,294,967,295].



  • float : il s'agit d'une variable de type réel, codée sur 4 octets. Sa
    précision n'excède pas 6 ou 7 décimales.



  • double : traditionnellement, le type double offre une précision deux fois supérieure à
    celle du float. Dans le cas du microcontrôleur Arduino, les deux types sont synonymes : double = float.



  • String : le type String est le premier type complexe que nous rencontrons. Ce n'est
    d'ailleurs plus vraiment un type, mais un Objet, au sens de la POO (programmation object oriented). Pour faire simple dans un premier temps, considérons qu'il
    s'agit d'une chaîne de caractères, que l'on peut donc y stocker des mots, des phrases, ... Le type String vient avec plusieurs méthodes qui
    permettent de traiter, comparer, manipuler, ... les chaînes de caractères.



  • array : ce n'est pas un type à proprement parler. Il est possible de déclarer pour chaque
    type
    un tableau de données de ce type,
    un tableau d'entiers par exemple pour stocker des états, ou un tableau
    de booléens, pour caractériser une série de données. On
    utilisera pour cela les crochets [ ] placés après le nom de la variable.
Ainsi, lorsque l'on souhaitera créer
une variable, on commencera par spécifier son type, puis son nom, et
éventuellement on lui assignera une valeur qu'il sera
ensuite possible de modifier.

Exemples :

int age = 13 ; // on créé un entier contenant la valeur 13

String message = "hello world" ; // on créé une chaîne de caractères
contenant la valeur "hello world"

char key = 'c' ; // on créé une variable de type char contenant le
caractère 'c', ou plus exactement la position du caractère 'c' dans le tableau indexant les principaux caractères

int tabValeurs [1024] ; // on créé un tableau pouvant contenir 1024
entiers. Les valeurs ne sont pas initialisées, elles peuvent donc contenir absolument n'importe quoi dans un premier temps.

Pour accéder à une valeur stockée dans un tableau, on utilisera l'index de sa position que l'on indiquera entre les crochets, tout
en faisant attention au fait que l'indexation commence à 0. Ainsi, pour un tableau de 1024 éléments, le premier éléments sera accessible en appelant tabValeurs[0] et le dernier
en invoquant tabValeurs[1023].

Pourquoi tous ces types ? N'est-il
pas plus simple de ne déclarer que des long, voire uniquement des floats
? L'intérêt réside dans l'utilisation de la
mémoire
. La mémoire d'un microcontrôleur est fortement
limitée (32 ko pour l'Arduino). Créer un tableau de 1024 entiers prend
2048 octets, soit 2 ko, soit 1/16 de la mémoire disponible.
Si l'on sait par avance que les valeurs ne seront jamais supérieures
à 255 (et toujours positives), par exemple dans le stockage de sorties
analogiques, on pourrait utiliser à la place des
bytes et gagner ainsi la moitié de l'espace.

Supposons par exemple que l'on veuille stocker une image couleur de 80x60 pixels. On aura un tableau contenant 200x200x3 =
14400 entrées. Si on les déclare comme des int, l'espace mémoire utilisé est 28800
ko
, soit la quasi-totalité des ressources du
micro-contrôleur. Autant dire que l'on ne pourra pas faire de traitement
vraiment intéressant de cette image. Maintenant, comme on sait que
les codes couleurs sont codés sur un seul octet, on peut décider d'utiliser des bytes plutôt que des int. On n'utlise alors que 14
ko
, soit moins de la moitié de la mémoire totale, ce qui laisse de la place pour un traitement de l'image.

II -
Les fonctions

Une fonction possède un nom, des
paramètres d'entrée et des paramètres de sortie. On appelle prototype
d'une fonction la spécification de ces trois données. Par
exemple, on peut vouloir créer une fonction qui prend deux entiers
en paramètre, puis renvoie leur produit. Son prototype sera :

int multiplication(int, int)

Si la fonction ne renvoie aucune donnée, son type de retour sera void. Si elle ne prend aucun paramètre, on
pourra soit ne rien mettre entre les parenthèses, soit écrire également void.

Si la fonction renvoie une donnée, elle devra le faire avec le mot-clef return.

Enfin, tout ce que fait la fonction doit être placé entre deux accolades.

Exemples :

int multiplication (int a, int b)

{

int c ;

c = a * b ;

return c ;

}

que l'on pourra écrire plus succinctement :

int multiplication (int a, int b)

{

return a * b ;

}

Ainsi, à chaque fois que nous aurons à
exécuter une multiplication, il suffira d'appeler la fonction que nous
venons de définir :

void quelques_calculs()

{

int a = 7 ;

int b = 8 ;

int c = muliplication(a, b) ;

}

III -
Les structures de condition et d'itération

Les structures principales sont
grosse merdo de deux sortes : structure conditionnelles et structures
itératives. Les principales sont les suivantes :

1 - Structure conditionnelle IF ... ELSE

La structure conditionnelle IF ... ELSE permet de vérifier une condition logique. Elle repose donc sur
l'évaluation d'une expression simple ou complexe, à laquelle elle donne la valeur Vrai (TRUE ou 1) ou la valeur Faux (FALSE, ou 0).

Par exemple, on veut vérifier sur la valeur donnée par un capteur de distance est supérieure à un certain seuil. On écrira :

int seuil = 80 ;

int valeur = analogRead(capteur_distance) ;

if (valeur > seuil)

{

// traitement si la valeur est strictement supérieure

}

else

{

// traitement si la valeur est inférieure ou égale

}

Ici, si la valeur lue est supérieure
au seuil, le code situé entre les deux premières accolades sera exécuté,
mais pas celui entre les deux accolades
suivantes.

Si la valeur est inférieure - ou
égale -, alors c'est l'inverse. Le code situé entre les deux premières
accolades ne sera pas exécuté, mais celui placé entre les
deux suivantes le sera.

Il est possible d'utiliser les
opérateurs logiques pour évaluer plusieurs conditions en même temps. On
utilisera l'opérateur de négation ! pour avoir l'inverse d'une valeur (si P est Vrai, !P est faux), l'opérateur de conjonction && qui renverra Vrai uniquement si les deux conditions
qu'il rassemble sont vraies ensembles, l'opérateur de disjonction || qui renverra Vrai si et seulement si une des valeurs est Vraie, et enfin
l'opérateur de disjonction exclusive ^ qui renverra Vrai si une seule des conditions est vrai et l'autre fausse.

Exemple :

int a = 80 ;

int b = 30 ;

int c = 2 ;

( ( (b == c) || ! (b > a) ) ^ (a < c) )

renverra Vrai.

En effet ;


  • l'expression (b == c) est fausse, puisque b est différent de c

  • l'expression ( b > a ) est fausse

  • donc l'expression !(b > a) est vraie

  • par conséquent, ( (b == c) || ! (b > a) ) est
    vraie, puisque l'une des deux expressions est vraie

  • Ensuite, (a < c) est fausse.

  • En conclusion, comme ( (b == c) || ! (b > a) ) est
    vraie et (a < c) est fausse, leur disjonction exclusive est vraie. L'expression
    est donc vraie.
On peut bien-sûr enchaîner séquentiellement les évaluations conditionnelles :

int a = 80 ;

int b = 30 ;

int c = 2 ;

if ( a > b )

{

// traitement

}

else

if ( a > c)

{

// traitement

}

else

{

// traitement
}

Notons que le ELSE est facultatif.

Enfin, la condition du IF ... ELSE peut-être un simple booléen, comme dans l'exemple suivant :

boolean estActif = true ;

... // traitements qui peuvent modifier la valeur de estActif

if ( estActif )

{

// traitement

}

2 - Structure de branchement SWITCH ... CASE ... DEFAULT

Le SWITCH
peut être imaginé comme un carrefour. On arrive à un moment du code où
l'on peut prendre plusieurs
directions. On suppose par exemple que l'on cherche à savoir parmi
quatre boutons-poussoirs lequel a été actionné. On a pour cela une
variable qui contient le numéro du bouton-poussoir que l'on
recherche, valeur que l'on examine et en fonction de laquelle on
exécute différents traitements.

Exemple :

byte boutonActif = 0 ;

... // traitement qui permet de savoir sur quel bouton on a appuyé, contient 0 si aucun bouton n'a été utilisé

switch ( boutonActif )

{

case 1 :

// traitement si c'est le bouton 1

break ;

case 2 :

// traitement si c'est le bouton 2

break ;

case 3 :

// traitement si c'est le bouton 3

break ;

case 4 :

// traitement si c'est le bouton 4

break ;

default :

// traitement si aucun bouton n'a été utilisé

break ;

}

La limitation principale du SWITCH ... CASE ... DEFAULT est qu'il opère de façon discrète (par opposition à
continue) et sur des expressions simples. On ne peut par exemple pas avoir un case a < b, ou un case
a && b
.

Le mot-clef BREAK signifie que l'on sort du SWITCH à la
fin du traitement. Il faut en effet savoir que chaque case correspond à une entrée, mais qu'une fois dans le SWITCH,
on est censé parcourir
toutes les valeurs qui suivent jusqu'à la dernière. On peut le voir
comme un toboggan à plusieurs entrées. On choisit à quelle hauteur on
arrive, mais une fois dans le toboggan, on doit parcourir
toute la distance, toutes les hauteurs, et cela jusqu'en bas. Le BREAK permet d'avoir des points de sortie. Traditionnellement, il vient
conclure chaque CASE, mais on peut imaginer évidemment des situations plus compliquées. Par exemple, on veut savoir quel actionneur d'un
robot doit être activé. On veut que si les valeurs des actionneurs 1, 3, ou
5 ont a être modifiées, les actionneurs qui leur succèdent doivent s'adapter également (respectivement (2, 4 et 6). En revanche, si on décide de modifier les
valeurs de 2, 4 ou 6 (pour une
correction suite à une information donnée par le retour d'un capteur), on ne veut pas modifier les actionneurs 1, 3 et 5. On aura alors :

switch ( valeur_indiquant_l_actionneur_a_modifier )

{

case 1 :

// traitement si c'est l'actionneur 1

case 2 :

// traitement si c'est l'actionneur 2

break ;

case 3 :

// traitement si c'est l'actionneur 3

case 4 :

// traitement si c'est l'actionneur 4

break ;

case 5 :

// traitement si c'est l'actionneur 5

case 6 :

// traitement si c'est l'actionneur 6

break ;

default :

break ;
}

Si on modifie l'actionneur 1, on passe ensuite au second qui est lui aussi modifié, puis on sort du
SWITCH. Si par contre on commence par modifier l'actionneur 2, on sort immédiatement
après et rien d'autre n'est modifié.

Notons enfin que le mot-clef DEFAULT qui vient conclure un SWITCH
est utilisé comme traitement par défaut. Dans le cas par exemple où la
valeur considérée correspondrait à une touche de clavier, dont seules
les
pressions sur les flèches nous intéresseraient, toute autre pression
de touche sera renvoyée sur DEFAULT.
On peut imaginer que ce n'est pas
obligatoire, mais certains compilateurs vous hurleront aux oreilles
si vous n'envisagez pas tous les cas. Il est donc toujours préférable de
le mettre, même s'il reste vide. Le BREAK
qui le suit est évidemment inutile, mais on peut le laisser par souci
d'homogénéité du code (et rien n'oblige à finir par le traitement par
default. Il peut très bien figurer en début de branchement).

3 - Structure d'itération FOR ( initialisation ; condition de traitement ; incrémentation )

Il est parfois utile d'exécuter un
traitement un grand nombre de fois. On veut par exemple parcourir un
tableau - pour en faire la moyenne -, ou faire clignoter un
nombre défini de fois une LED, ou encore faire avancer tourner une
tourelle sur laquelle est fixé un capteur. On utilisera pour cela une
boucle FOR. Dans sa forme la plus simple, un FOR utilise
un compteur que l'on incrémente.

Exemple :

int tab[128] ; // définition d'un tableau d'entiers contenant 128 cases, indexées de 0 à 127

... // traitement pour remplir le tableau avec des valeurs provenant d'un capteur

int somme = 0 ;

for (int i = 0 ; i < 128 ; i )
{
somme = tab[i] ;
}
float moyenne = somme / 128.0 ;

On commence donc par définir un
tableau de 128 cases. On remplit ensuite ce tableau avec des valeurs
issues par exemple d'un capteur. On initialise ensuite une
variable entière à 0, la variable somme.

La boucle FOR nous permet ensuite de parcourir le tableau. A chaque tour de boucle, la valeur contenue dans la
case du tableau correspond à l'index donné par la variable i est ajoutée à la variable somme.

Une fois le tableau parcouru, on créé une variable de type DOUBLE, et l'on divise la somme par le nombre
d'éléments pour obtenir la moyenne.

Plusieurs remarques déjà d'ordre syntaxique :

  • l'écriture i est un raccourci pour i = i 1.
    C'est-à-dire qu'à chaque tour de boucle, on augmente la valeur de i d'une unité

  • l'écriture somme = tab[i] est un raccourci pour somme = somme tab[i].
    A chaque tour de boucle, somme ajoute à sa valeur précédente la valeur
    contenue dans la case du tableau sur laquelle on pointe.

  • enfin, on écrit 128.0 pour en faire un float et non un
    entier. En effet, si la division est effectuée entre deux entiers, elle agira comme une division entière. Ainsi, 5/2 = 2, 3/8 = 0, et 1000/128 = 7. En
    forçant l'une des deux valeurs à être de type float, on a alors
    une division au sens usuel, et son résultat sera un nombre réel, de type float.
Au sein de la boucle FOR, on commence
donc par initialiser un compteur à 0. On spécifie que l'on continue à
rentrer dans la boucle tant que sa valeur est inférieure
à 128 (on va donc jusqu'à la case 127). Puis, à chaque tour, on
incrémente la valeur de 1.

Supposons que l'on souhaite faire
exécuter à un servo-moteur une rotation de 180 degrés, avec un relevé
d'un capteur tous les 5 degrés. On écrira alors :

Servo s ; // on créé une variable de type Servo (ce que l'on verra plus tard)

s.attach(9) ; // on spécifie que la communication avec le Servo se fair sur le connecteur 9 de
l'Arduino

... // quelques traitements

for (byte degre = 0 ; degre <= 180 ; degre = 5)

{

s.write(degre) ; // on indique en degre la position que doit atteindre le Servo

lireCapteur() ; // on exécute une fonction qui lit un capteur

... // traitement, par exemple un envoi de données en série si la valeur du capteur dépasse un seuil

}

Ici, dans la boucle, on initialise la valeur de degre à 0. Dans le premier tour de boucle, le Servo se dirige
vers la position 0 qui se trouve être le point le plus à gauche. A la fin de la boucle, on augmente la valeur de degre
de 5. Puis on augmente
à nouveau de 5 au tour suivant, etc etc etc ... A chaque tour, le
Servo se déplace donc de 5 degrés, jusqu'à ce qu'il atteigne 180 degrés.
A la fin de ce dernier tour, la variable est incrémentée
de 5, elle vaut donc 185, et la condition de traitement n'est plus
respectée. On sort donc de la boucle.

4 - Structure d'itération WHILE

Si le WHILE et le FOR sont interchangeables, ils sont
utilisés dans des cadres différents. Lorsqu'on utilise un FOR, on suppose que l'on connaît à l'avance le nombre d'itérations. Celui-ci est
fixé en dehors de la boucle FOR. Pour un WHILE,
la condition d'arrêt dépend d'un
événement qui inervient durant le processus de bouclage. On attend
par exemple une entrée au clavier, ou un signal Bluetooth, ou par
exemple une valeur située dans un intervalle. Quand un
WHILE démarre, on ne sait pas à l'avance quand - et si - il va s'arrêter.

Pour rappel, on a dans la structure du FOR une initialisation, une condition de déroulement, et une
incrémentation. Dans le cas du WHILE, l'initialisation se fait avant la boucle. La condition de déroulement se fait à l'appel du WHILE,
et la modification des variables impliquées dans la condition se fait
au sein de la boucle. Elle dépend de l'environnement (environnement
physique, utilisateur, ...), et n'est pas fixée par le programme. On
peut dire que le FOR est une boucle aux conditions immanentes, tandis
que le WHILE est une boucle aux conditions transcendantes.

D'un point de vue syntaxique, la WHILE est défini ainsi :

... // initialisation des variables de condition de traitement

while ( condition )
{
// différents traitements

// réactualisation de la condition

// différents traitements
}

On a donc pour le FOR :

FOR (initialisation, condition, actualisation)
{
// traitement
}

et pour le WHILE

// initialisation

WHILE ( condition )
{
// traitement

// actualisation

// traitement
}

Quelques exemples.

Dans le premier cas, on lit les
valeurs d'un capteur de distance. Quand celui-ci détecte un objet situé à
une proximité inférieure à une valeur seuil donnée, on
sort de la boucle. Tant qu'on est dans la boucle, on fait par
exemple avancer un robot en ligne droite.

int distance = 800 ; // initialisation de la distance à 800 mm

int seuil = 40 ; // fixation du seuil à 40 mm

while (distance > seuil)
{
avanceRobot(2) ; // fonction faisant avancer le robot

distance = analogRead(capteur_distance) ; // actualisation de la variable de distance par lecture du capteur

delay(100) ; // attente de 100 millisecondes entre chaque lecture
}
tourneGaucheRobot(90) ; // fonction faisant tourner le robot

On commence donc par initialiser les
variables de contrôle. A chaque tour de boucle, on vérifie que l'on est
pas trop proche d'un obstacle. Si la condition est
vérifiée, on avance de 2 millimètres, et on lit la nouvelle valeur.

Si la valeur est inférieure à 40 mm -
parce que le robot avance par exemple vers les jambes de quelqu'un,
alors la condition n'est plus vérifiée, et on sort de la
boucle. On tourne alors vers la gauche de 90 degrés.

Deuxième exemple : on attend
l'activation d'un bouton poussoir. Tant que celui-ci n'est pas activé,
on fait clignoter une LED signalant un mauvais fonctionnement.
Une fois la pression effectuée, la LED est en position éteinte, et
on allume une LED signalant le rétablissement des fonctions du système.

int state = LOW ; // on suppose le bouton inactivé

while (state == LOW)
{
digitalWrite(LED1, HIGH) ; // on allume la LED d'alarme

delay(500) ; // on attend une demi-seconde

digitalWrite(LED1, LOW) ; // on éteint la LED d'alarme

delay(500) ; // on attend une demi-seconde

state = digitalRead(button) ;
}
digitalWrite(LED2, HIGH) ; // on allume la LED indiquant un bon fonctionnement

En résumé, s'il est possible de transformer un FOR en WHILE et inversement, on préfèrera un FOR pour une série d'instruction dont on maîtrise les
conditions de sortie, et un WHILE lorsqu'il s'agit d'une intervention contingente au programme.


IV - Les directives de préprocesseur

Les directives de préprocesseur sont
généralement placées en début de programme. Les plus utilisées sont de
deux sortes : les inclusions et les définitions.

Une inclusion sert à utiliser des
bouts de programmes contenus dans un autre fichier. C'est le cas par
exemple lorsque l'on appelle une
bibliothèque (ou librairie). Lorsque l'on a utilisé plus haut une variable de type Servo,
c'est parce que
nous avons inclus une bibliothèque qui définit ce type d'objets. Si
l'on veut utiliser des fonctions de mathématiques avancées, on utilisera
une bibliothèque dédiée.

L'inclusion se fait à l'aide de la directive #include < nom_du_fichier > ou #include " nom_du_fichier ".
Dans le premier cas (chevrons), la bibliothèque se situe à un endroit
connu par le programme, défini pour contenir
l'ensemble des bibliothèques. Dans le second cas (guillements), le
fichier importé se situe dans le même répertoire que le fichier qui
l'appelle, ou à une position définie à partir de lui.

Ainsi, si l'on écrit :

#include < mes_librairies/ma_librairie.h>

on ira chercher les données contenues dans un fichier ma_librairie.h se situant dans le répertoire
mes_librairies qui lui-même se trouve dans le répertoire dans lequel sont usuellement placées les librairies.

En écrivant :

#include "mes_librairies/ma_librairie.h"

on se place au niveau du répertoire contenant le fichier dans lequel on écrit, on va dans un de ses sous-répertoires nommé mes_librairies, et on importe le fichier ma_librairie.h qui s'y trouve.


La seconde directive la plus utilisée est #define.
Elle sert principalement à remplacer une valeur par un mot.
Lors de la compilation, partout où ce mot aura été utilisé, le
compilateur placera la valeur. C'est utile par exemple pour définir la
hauteur et la largeur d'une image. On écrira :


#define HAUTEUR 600

#define LARGEUR 800

Dans le code, on pourra utiliser HAUTEUR et LARGEUR, ce
qui permettra de le rendre plus clair. A la compilation, ces valeurs seront remplacées par 600 et 800 respectivement. Elles ne peuvent être modifiées durant l'écriture ou l'exécution du programme.


V -
Les variables globales

Les variables globales sont placées
également en début de programme, et sont connues par toutes les
fonctions. De manière générale, une variable définie dans une
fonction n'existe qu'au sein de celle-ci. Aucune autre fonction ne
la connaît, à moins qu'elle lui soit passée en paramètre.

Avec les variables globales, on peut
partager des données. Ainsi, si plusieurs fonctions lisent un capteur,
ou l'actualisent, on définira ce capteur en dehors des
fonctions, ce qui évitera d'avoir à en recréer une instance à chaque
nouvelle fonction appelée, et de le transmettre à chaque fois en
paramètre.

Un bon code trouve l'équilibre entre
variables globales et variables locales. Les variables globales seront
généralement des variables du système physique (la
valeur d'un potentiomètre par exemple), tandis que les variables
locales pourront être des compteurs de parcours, des valeurs de stockage
pour des calculs intermédiaires, ...

SO, LET'S BEGIN !!

En route pour notre premier programme, et notre premier montage Arduino.


_________________
Voici ma chaîne YouTube: Drone-250-Time https://www.youtube.com/channel/UC3ArL72UR4AjpaF5r-pXpSg
Voici ma chaîne YouTube: Dark-Best https://www.youtube.com/channel/UCqHLYZ9IJyfguosa8_rz9Jg
Faite passé l'information les amies , merci a vous tous.
http://jarvise.atspace.cc/

J_W

avatar
Membre
Membre
Super, merci pour toutes ces explication :)

Voir le sujet précédent Voir le sujet suivant Revenir en haut  Message [Page 1 sur 1]

Permission de ce forum:
Vous ne pouvez pas répondre aux sujets dans ce forum