Free Memory : pas le même résultat

L'allocation mémoires pour les variables locales lors de l'appel d'une fonction prend toujours le même temps car c'est juste un déplacement du pointeur de pile.

Par contre l'écriture des valeurs passées en paramètre peut prendre du temps. Si les valeurs doivent êtres modifiées par la fonction il est intéressant de passer simplement un pointeur sur une structure.

JLB

Petite précision pour agrément l'excellente explication de Super_Cinci :
Contrairement à un PC sur arduino (et plus généralement sur toute plateformes utilisant des micro-contrôleurs) il n'y as pas de notion de "charge CPU".

Sur un PC on peut ouvrir le gestionnaire de taches et ce dire "ya cette bip d'application qui me bouche 100% du CPU !", avec un micro-contrôleur ce n'est pas possible.
Le micro-contrôleur tourne sur un signal d'horloge (8MHz ou 16MHz en général avec les cartes arduino), à chaque "tick" de l'horloge le CPU prend une instruction depuis la mémoire flash, la décode et agit en conséquence.
Le CPU est donc toujours "à 100%" en train d'effectuer une tache, même faire une série de "nop" (instruction assembleur "no operation") revient à occuper le CPU.

En gros il n'y as pas de notion de "idle process" comme c'est le cas sur un PC.

La seul notion de "temps cpu" que l'on peut avoir est par exemple le % de cycles cpu occupé par une interruption / fonction par rapport au reste du programme.
Mais il n'existe aucune fonction pour connaitre ce "temps cpu" en temps réel, la meilleur façon de le déduire et de le mesurer avec un oscilloscope et une broche que l'on fait commuter.

JLB a déjà répondu : l'allocation est immédiate puisqu'elle se fait par le déplacement d'un pointeur dans la pile.
Et la taille de ce déplacement est connu à la compilation
MAIS LE C ne vérifie pas si la pile est assez grande.

Puisque Super_Cinci en parle, sur un processeur évolué disposant de gestion avancée de la mémoire (MMU) et surtout de mémoire paginée, la taille de la pile peut grandir automatiquement au fur et a mesure. Au risque de "bouffer" tout si tu fait une fonction récursive qui s'appelle sans fin genre :

int boufe_tout( int in )
{
  return bouffe_tout( in + 1 );
}

De même sur PC/Windows/Linux ou Mac/OSX, pas de problème pour allouer une variable globale de grande taille :

void grosse_variable()
{
  int gros_tableau[1024*1024]; // même pas mal même si tu n'as que 2MO de RAM, Windows alloue de la mémoire sur le disque...
}

Par contre sur un micro embarqué, la taille mémoire est fixe et toutes les tailles sont connues à l'avance.
Une taille fixe est allouée à la pile par l'éditeur de lien (pas facilement changeable dans l'environnement Arduino je pense) et on peut très rapidement exploser la limite si on ne fait pas attention.

Comme je le disait, par défaut le C ne vérifie pas cette possibilité (ou du moins il n'est pas spécifié qu'il doive le faire). Il existe dans certains compilateur une option de compilation que l'on peut activer si on le souhaite pendant la phase de mise au point qui va vérifier a l'entrée d'une fonction que l'on a pas dépassé la taille de la pile. Si c'est le cas : blocage de sécurité. Cette fonctionnalité est désactivée par défaut pour des raisons de performance.

Au contraire, le langage Pascal effectue généralement plus de vérification et génère un code plus sûr. Ce qui explique le grand succès de Borland et TurboPascal puis Delphi dans les années 90 et début 2000.

Pour ce qui est du "défragmenteur" (en anglais on parle de Garbagge collection (ramassage des poubelles)) ceci n'existe pas en C mais uniquement dans des environnements qui n'autorisent pas un accès par pointeurs directs mais il a surtout été popularisé dans les systèmes de machines virtuelles telles que Java et DotNet. Dans ces environnements on ne n'accède jamais à la mémoire directement par un pointeur mais par une référence qui elle contient l'adresse en mémoire. Cela autorise l'environnement à défragmenter la mémoire en tâche de fond en mettant à jour les références.

Pour ce qui est de la charge CPU, comme le dit Skywodd ce n'est pas aussi immédiat.
Mais normalement, une application Arduino tourne avec loop()
Donc on peut considérer que plus souvent on fait des tour de loop(), moins le CPU est chargé.
Plus longtemps dure l'exécution de loop() (et donc moins de tour on effectue) plus le CPU est chargé.

Dans une application j'ai fait une estimation de la charge CPU à l'aide de la LED de la carte (PIN13) en éteignant la LED à l'entrée de loop() et en l'allumant sur la dernière ligne.
Plus l'exécution de loop() est courte, plus la LED est allumée.
Plus l'éxécution de loop() s'allonge, plus la LED diminue d'intensité.

On pourrait aussi faire une estimation en mesurant le nombre de tour de loop() par unité de temps.

Ca ne reste qu'une estimation et considère de programmer l'Arduino d'un façon absolument non bloquante (pas de delay, pas de boucle bloquante ou d'attente).
Mais c'est de toute façon la seule manière de programmer efficacement une plateforme telle que l'Arduino sans ordonnanceur de tâches.

Je n'ai même pas résumé, car il y a autant de choses à décrire qu'il y a de transistors dans le µP (en gros...)

Pour les histoires d'allocation des variables locales, je viens d'apprendre un truc, merci les gars!

Selon le nombre de fonctions de mon programme, j'utilise au max les interruptions. Par exemple, j'ai trouvé un moyen d'utiliser un clavier matriciel sans aucun appel de fonction : je branche les colonnes sur un port (prenons le port X par exemple) et les lignes sur le port Y. le port Y contient l'interruption PCINT1 (Pin Change INTerrupt). cette interruption est déclenchée dès qu'une des pin du port change, ce qui est très pratique dans mon cas, la lecture du clavier dans mon programme se résume alors à la lecture de la variable key :

#define NO_KEY 0xFF;  // code "pas de touche"
volatile byte lignes, colonnes, key;

void KeybInit(){       // initialisation du clavier
  PORTX en sortie;  // Préparation des colonnes
  PORTX = 0x00;

  PORTY en entrée;  // Préparation des lignes
  PORTY = 0xFF;  // pullup sur les lignes

  Autoriser PCINT1 sur PORTY;  // démarrer la lecture sur interruption
}

ISR(PCINT1-Vect)(){        // routine d'interruption appelée dès qu'une pin du port Y change d'état (appui sur une touche ou relâchement)
  Désactiver PCINT1 sur PORTY;
  colonnes = PINY;     // lecture de la ligne qui a changé d'état

  PORTX en entrée;  // Préparation des colonnes
  PORTX = 0xFF;  // pullup sur les colonnes

  PORTY en sortie;  // Préparation des lignes
  PORTY = 0x00;

  lignes = PINY;  // lecture de la ligne de la touche enfoncée
  key = decodeKey(lignes, colonnes);  // décodage du code de la touche
  keybInit();  // réinitialisation du clavier
}

void setup(){
  key = NO_KEY;
  keybInit();
}

void loop(){
 if (key != NO_KEY){
  switch (key){  // ne fait appel à aucune fonction (donc très rapide)
    case 0x00 :
      //traitement touche code 0x00
      break;
    case 0x01 :
      //traitement touche code 0x01
      while (key == 0x01);  // attente du relâchement de la touche
      // faire quelque chose
      while (key == NO_KEY);  // attente de l'appui sur une nouvelle touche
      // faire encore quelque chose
      while (key != NO_KEY);  // attente du relâchement de toutes les touches
      break;
  }
 }
}

Ici, j'ai grandement simplifié, la fonction decodeKey n'est pas là, elle transforme le couple (lignes, colonnes) en un code sur un octet (utile pour un clavier à touches numérotées... la touche "1" donne la valeur 1 etc etc.

J'avoue qu'un arduino Mega sera bien plus adapté à ce genre de code car il possède beaucoup de PCINT, permettant de gérer ainsi des claviers de 256 touches voire plus, sans avoir besoin de balayer les lignes et colonnes en continu, le gain de temps est bien plus que considérable, car si on n'appuie sur aucune touche, alors on peut résumer la loop ainsi :

void loop(){
 if (key != NO_KEY){
    // peu importe ce qu'il se passe ici, car on n'appuie sur aucune touche : key = NO_KEY...
 }
}

et donc loop boucle uniquement sur un simple if. Ce n'est qu'un exemple, mais de cette même manière, on peut gérer le clavier quand et comme on veut!

Dans mes programmes utilisant ce genre de manip d'int pour un clavier, la loop contient un menu (dans lequel on navigue via le clavier).

si ça peut donner des idées, prenez, prenez! faudrait que j'en fasse une lib (je sais toujours pas comment on fait, j'ai essayé une fois sans résultat), ça serait grandement pratique pour beaucoup, car la lib Keypad est vraiment très lente (du digitalWrite et Read à foison avec je ne sais combien de if()...) et bug de temps en temps...

barbudor:
Pour ce qui est du "défragmenteur" (en anglais on parle de Garbagge collection (ramassage des poubelles)) ceci n'existe pas en C mais uniquement dans des environnements qui n'autorisent pas un accès par pointeurs directs mais il a surtout été popularisé dans les systèmes de machines virtuelles telles que Java et DotNet. Dans ces environnements on ne n'accède jamais à la mémoire directement par un pointeur mais par une référence qui elle contient l'adresse en mémoire. Cela autorise l'environnement à défragmenter la mémoire en tâche de fond en mettant à jour les références.

Barbudor, la fonction du garbage collector Java n'est pas exactement un défragmentage. Plus exactement c'est la récupération des instances d'objets qui ne sont plus référencées. Contrairement au C++ le programmeur java ne s'occupe pas de désinstancier les objets créés alors qu'en C++ le moindre oubli provoque des "fuites de mémoire".

JLB

Le garbage collector Java récupère la mémoire des objets non référencés puis défragmente ensuite l'espace mémoire.
Il y a d'ailleurs plusieurs algorithmes disponibles.

Je crois me souvenirs que la défragmentation mémoire peut aussi être transparente même en manipulant des pointeurs directement pour peu que le système dispose d'une MMU (Memory Managemen Unit), mais c'est pas le cas d'un micro-contrôleur tel que l'AVR :grin:

patg_:
Le garbage collector Java récupère la mémoire des objets non référencés puis défragmente ensuite l'espace mémoire.
Il y a d'ailleurs plusieurs algorithmes disponibles.

L'activation du garbage collector en java (et dérivé, android, etc) est le truc chiant par excellence quand on code un jeu ou une application graphique ...
La 1er chose à faire est de le désactiver, et de lancer le garbage collector à la main pendant un temps "libre", sinon -> lags.
(En gros vive System.gc(); \o/)

De toute façon pour l'ingé soft obsédé d'optimisation maximaliste il n'y a que le C++ avec du C et de l'assembleur inside... Mais je croyais cette population en voie d'extinction... Le sable est moins cher que les neurones... Il y a même des pervers qui pourfendent l'utilisation de l'enclume à écraser les mouches... Alors qu'il est quand même moins cher d'utiliser un DSP plutôt que de mettre au point le montage à trois transingues qui fait la même chose...

JLB

skywodd:

patg_:
Le garbage collector Java récupère la mémoire des objets non référencés puis défragmente ensuite l'espace mémoire.
Il y a d'ailleurs plusieurs algorithmes disponibles.

L'activation du garbage collector en java (et dérivé, android, etc) est le truc chiant par excellence quand on code un jeu ou une application graphique ...
La 1er chose à faire est de le désactiver, et de lancer le garbage collector à la main pendant un temps "libre", sinon -> lags.
(En gros vive System.gc(); \o/)

Le choix du bon algorithme de GC et de ses divers paramètre est aussi une option envisageable...et moins radicale!
Mais bon, les développeurs Java qui savent tuner une JVM ça ne court pas les rues :grin:
Cependant je ne connais pas vraiment le développement de jeu en Java. Je suis plus dans l'info de (di)gestion. Et je m'amuse avec le dév sur AVR pour le plaisir.

Super_Cinci:
Je n'ai même pas résumé, car il y a autant de choses à décrire qu'il y a de transistors dans le µP (en gros...)

Pour les histoires d'allocation des variables locales, je viens d'apprendre un truc, merci les gars!

Selon le nombre de fonctions de mon programme, j'utilise au max les interruptions. Par exemple, j'ai trouvé un moyen d'utiliser un clavier matriciel sans aucun appel de fonction : je branche les colonnes sur un port (prenons le port X par exemple) et les lignes sur le port Y. le port Y contient l'interruption PCINT1 (Pin Change INTerrupt). cette interruption est déclenchée dès qu'une des pin du port change, ce qui est très pratique dans mon cas, la lecture du clavier dans mon programme se résume alors à la lecture de la variable key :

#define NO_KEY 0xFF;  // code "pas de touche"

volatile byte lignes, colonnes, key;

void KeybInit(){       // initialisation du clavier
  PORTX en sortie;  // Préparation des colonnes
  PORTX = 0x00;

PORTY en entrée;  // Préparation des lignes
  PORTY = 0xFF;  // pullup sur les lignes

Autoriser PCINT1 sur PORTY;  // démarrer la lecture sur interruption
}

ISR(PCINT1-Vect)(){        // routine d'interruption appelée dès qu'une pin du port Y change d'état (appui sur une touche ou relâchement)
  Désactiver PCINT1 sur PORTY;
  colonnes = PINY;     // lecture de la ligne qui a changé d'état

PORTX en entrée;  // Préparation des colonnes
  PORTX = 0xFF;  // pullup sur les colonnes

PORTY en sortie;  // Préparation des lignes
  PORTY = 0x00;

lignes = PINY;  // lecture de la ligne de la touche enfoncée
  key = decodeKey(lignes, colonnes);  // décodage du code de la touche
  keybInit();  // réinitialisation du clavier
}

void setup(){
  key = NO_KEY;
  keybInit();
}

void loop(){
if (key != NO_KEY){
  switch (key){  // ne fait appel à aucune fonction (donc très rapide)
    case 0x00 :
      //traitement touche code 0x00
      break;
    case 0x01 :
      //traitement touche code 0x01
      while (key == 0x01);  // attente du relâchement de la touche
      // faire quelque chose
      while (key == NO_KEY);  // attente de l'appui sur une nouvelle touche
      // faire encore quelque chose
      while (key != NO_KEY);  // attente du relâchement de toutes les touches
      break;
  }
}
}




Ici, j'ai grandement simplifié, la fonction decodeKey n'est pas là, elle transforme le couple (lignes, colonnes) en un code sur un octet (utile pour un clavier à touches numérotées... la touche "1" donne la valeur 1 etc etc.

J'avoue qu'un arduino Mega sera bien plus adapté à ce genre de code car il possède beaucoup de PCINT, permettant de gérer ainsi des claviers de 256 touches voire plus, sans avoir besoin de balayer les lignes et colonnes en continu, le gain de temps est bien plus que considérable, car si on n'appuie sur aucune touche, alors on peut résumer la loop ainsi :



void loop(){
if (key != NO_KEY){
    // peu importe ce qu'il se passe ici, car on n'appuie sur aucune touche : key = NO_KEY...
}
}




et donc loop boucle uniquement sur un simple if. Ce n'est qu'un exemple, mais de cette même manière, on peut gérer le clavier quand et comme on veut!

Dans mes programmes utilisant ce genre de manip d'int pour un clavier, la loop contient un menu (dans lequel on navigue via le clavier).

si ça peut donner des idées, prenez, prenez! faudrait que j'en fasse une lib (je sais toujours pas comment on fait, j'ai essayé une fois sans résultat), ça serait grandement pratique pour beaucoup, car la lib Keypad est vraiment très lente (du digitalWrite et Read à foison avec je ne sais combien de if()...) et bug de temps en temps...

Et sur un mega, on peut pas faire de int sur l'ensemble des pin je suppose ? Il me semble avoir lu que c'etait limité à 6 pins chez arduino.

L'idée serait de prioriser l'ensemble des DI (digitals input) alors que le traitement "secondaire" type affichage LCD, écriture carte SD seraient moins prioritaire.
Évidement, les DI ne serait pas sollicitées à une cadence folle. Ça dans le cadre de la domotique.

OLIVIERC67:
Et sur un mega, on peut pas faire de int sur l'ensemble des pin je suppose ? Il me semble avoir lu que c'etait limité à 6 pins chez arduino.

il me semble qu'il y ait 1 PIN/INT par registre, mais qu'il est également possible d'avoir une interruption non sur une pin en particulier mais sur 1 registre et à ce moment là c'est à toi de vérifié laquel de ses pin correspondant au registre à été modifier.
Il me semble avoir vu quelque chose comme ça, avis aux expert ?

Edit: Je me disais bien avoir aperçu quelque chose dans le style récemment, voir le tuto de 68tjs http://arduino.cc/forum/index.php/topic,100906.0.html

PS: Pour java il est effectivement rare de rencontrer des personnes sachant tuner sa MV :sweat_smile:, souvent en entreprise il y a une personne dédié qui ce charge de calà, ainsi que du déploiement, etc.
Maintenant il est clair que java et ça MV il ne faut pas compter dessus pour faire un "call of duty", chaque langage sera choisi selon la situation et ça priorité (ressources, dépendances, etc) .

osaka:

OLIVIERC67:
Et sur un mega, on peut pas faire de int sur l'ensemble des pin je suppose ? Il me semble avoir lu que c'etait limité à 6 pins chez arduino.

il me semble qu'il y ait 1 PIN/INT par registre, mais qu'il est également possible d'avoir une interruption non sur une pin en particulier mais sur 1 registre et à ce moment là c'est à toi de vérifié laquel de ses pin correspondant au registre à été modifier.
Il me semble avoir vu quelque chose comme ça, avis aux expert ?

Edit: Je me disais bien avoir aperçu quelque chose dans le style récemment, voir le tuto de 68tjs http://arduino.cc/forum/index.php/topic,100906.0.html
...

Super merci.
Son tuto est très clair.

Définir des priorités de traitement peut très vite se transformer en une prise de choux tendant généralement vers une calvitie précoce... Car rappelons-le, même si je suis encore subjugué par les capacités de l'ATMEGA (j'avais pas touché à un processeur depuis le 68HC11 de l'école en 1995), l'arduino n'est vraiment pas puissant comparé aux µP que l'on trouve dans les imprimantes à 10€ et autres appareils récents. L'ATMEGA est très bien pour de petits projets avec de petites fonctions. On pourra toujours s'en sortir, mais c'est compliqué.

Pour le régulateur de vitesse que j'ai mis dans ma chouette renault11 (arduino UNO), la première des priorités est l'appui sur la pédale de frein ou d'embrayage qui désactive le régulateur, mais aussi le dépassement de vitesse imprévu dans une forte descente, ainsi que l'appui sur le bouton "Désactiver", sans oublier non plus d'avoir une mesure fiable de la vitesse du véhicule, ah oui, mais faut pas non plus que le LCD se "fige", il faut penser à lui... Et le servo qui commande l'accélérateur, j'ai pas le droit de le négliger non plus, faudrait pas qu'il bouge sans en en avoir reçu l'ordre!!! Reste encore le bouton "SETTINGS" pour rentrer dans un menu de configuration...

A coups de multiples interruptions (externes, timers...), j'y suis arrivé, mais ça a été assez long, et comme ça fait un an qu'il est dans la voiture et qu'il marche bien, je ne suis pas sûr de m'y retrouver dans mon code si je veux le faire évoluer vers une version 1.3... Il faudra donc que je recommence à zéro, ça ira bien plus vite...

Et je me dis que si je veux vraiment faire bien, alors il faudra certainement que je me tourne vers un µP un peu plus rapide.

C'était la petite histoire pour expliquer que finalement, il ne faut peut-être pas trop en demander à l'arduino, et que si le datasheet fait plusieurs centaines de pages, c'est pas pour rien.

Sur un méga2560, on a accès à trois vecteurs PCINT (3 x 8, soit 24 pins), mais les PCINT 11 à 15 (PCINT1) ne sont pas câblées. Car en plus, sur la carte MEGA2560, les pins non routées sont pourtant parmi les plus utiles (horloges externes des timers, INT externes...) C'est vraiment dommage. les pins accessibles ont des fonctions utiles mais par exemple, si on veut l'INT2 ou 3, on perd le port série 1, alors on pourrait utiliser l'INT7 (PORTE:7) car cette pin ne fait que l'INT7, ben non, elle n'est pas routée... c'est malin!

Eh... ! Super_Cincy faut pas exagérer le manque de performance de l'ATmega. Il peut largement faire tourner des dizaines de régulateurs de R11 en parallèle.

J'ai fait un test de calcul de sinus. Il ne met que 10 secondes pour en calculer 1 million soit 100 000 à la seconde.

Il ne faut pas oublier qu'il y a 1 000 000 de uS dans une seconde et que la plupart des instructions AVR ne prennent qu'un seul cycle soit 1/16 ème de uS sur une Arduino Uno.

Quand aux interruptions rien ne t'empêche de les vectoriser par soft et donc de gérer un masque d'interruption ainsi que des priorités. L'aiguillage d'interruption ne prend que quelques uS et sur une seconde il reste largement de quoi prendre des contacts divers, des capteurs de vitesse et faire des régulations PID et ensuite utiliser l'énorme temps processeur qui reste pour faire de l'animation.

Le premier PC avait un 8088 (8 bits) tournant à 4,77 MHz et un jeu d'instruction CISC très couteux en cycles d'horloge. En comparaison un ATmega est une fusée.

N'oublie pas qu'il est possible de réautoriser les interruptions pendant le traitement d'une interruption. Faut juste savoir exactement ce qu'on fait et ne pas se mordre la queue (d'où l'intérêt de gérer un masque d'interruption software).

JLB

je ne compare pas deux processeurs qui ont 30 ans d'écart, mais plutôt l'exemple d'un simple PIC 32bits qui tourne à 80MHz... la fusée se traine un peu, non?

Pour mon régulateur, j'utilise les deux timers et les deux int externes dispos de l'arduino, donc peu de chances de réguler plusieurs véhicules avec un seul arduino... il faut rester réaliste, la "vectorisation par soft" crée beaucoup de temps variables qui se ressentent grandement sur un servomoteur qui se met à avoir la tremblotte (j'ai passez beaucoup de temps à trouver la solution pour stabiliser le tout, et autoriser une interruption pendant qu'on en traite déjà une n'est pas possible dans mon cas, j'ai besoin d'une précision exemplaire dans mes fenêtres de comptage et de gestion du servo).

Le gros avantage de l'arduino est qu'il est très simple à programmer et possède toute sorte de périphériques embarqués pour répondre à la plus part des fonctions que l'on recherche, mais malheureusement, on ne peut pas utiliser toutes ces ressources en même temps, ce qui restreint très vite les projets ambitieux ou gourmands.

Super_Cinci:
je ne compare pas deux processeurs qui ont 30 ans d'écart, mais plutôt l'exemple d'un simple PIC 32bits qui tourne à 80MHz... la fusée se traine un peu, non?

STOP ! Un cpu de la puissance d'une calculette d'aujourd'hui a fait poser une fusée sur la lune !

Comparer un ATMEGA à 16MHz à un PIC32 à 80MHz pour une application comme celle de ton régulateur n'as aucun sens !
Pourquoi ne pas carrément utiliser un STM32F4 à 168MHz dans ce cas là ?

Le choix de la plateforme lors de la conception d'un projet est un choix trés important, mais il ne faut pas sur-dimensionné le choix du micro-contrôleur.
Un PIC32, un LPC176x, ou un STM32Fx serait clairement "over kill" dans ton cas !
Ce serait une façon de dire "Je ne sait pas faire quelque chose d'optimisé, j'utilise donc une CPU d'une puissance monstrueuse pour faire pas grand chose".
Autant dire que si tu va sur avr-freaks et que tu leur dis que tu utilise un PIC32 à la place d'un ATmega pour ton projet ça va rigoler sec :wink:

Super_Cinci:
Le gros avantage de l'arduino est qu'il est très simple à programmer et possède toute sorte de périphériques embarqués pour répondre à la plus part des fonctions que l'on recherche, mais malheureusement, on ne peut pas utiliser toutes ces ressources en même temps, ce qui restreint très vite les projets ambitieux ou gourmands.

Les personnes qui ont besoin de 100% des ressources de l'ATmega ne se tourne pas vers arduino.
Tu l'as dit toi même arduino est "trés simple à programmer", et ceux au dépend des performances.

Il faut bien se rappeler qu'un ATmega ça ne ce programme pas qu'en langage arduino.
C'est un point qui reviens trés régulièrement sur avr-freaks, le projet arduino a tellement associé ATmega et Arduino dans la pensé des gens que l'ont pourrait presque dire ATmega -> Arduino.
Je le dit souvent il n'y as pas que arduino dans la vie, un bon makefile et la doc de avr-libc c'est pas plus compliqué à utiliser que arduino mais c'est beaucoup plus rapide / léger :wink:

Nous sommes bien d'accord. Si j'avais des yeux corrects, alors j'utiliserais des ATMEGA2560 en "standalone" pour bénéficier de toutes ces pins non routées qui me manquent cruellement. Des cartes au même format qu'arduino existent avec quelque connecteurs supplémentaires, et je ne tarderait pas à en prendre une ou deux.

Arduino est très pratique pour découvrir le monde merveilleux des µP, et comme tu le dis, s'il y a autant de µP disponibles sur le marché, ce n'est pas pour rien, ils ont l'air semblables, mais une infime différence rendra l'un bien plus performant que son petit frère selon le projet. Si j'utilise des cartes arduino, c'est en conséquence de cause, et que j'aime pas trop les lignes de commandes à répétition. on branche sur l'USB, on clique une fois, et hop, ça tourne pour des années. J'essaie juste de tirer le meilleur parti du système, et vu le nombre d'heures que j'ai passé sur le datasheet, ça me ferait mal de changer de plateforme. J'ai peut-être un projet de remettre en route un gros plotter en utilisant un arduino mega, car pour une ou deux liaisons série et 3 moteurs PAP, ça suffira amplement! Mais pour mon idée d'ordinateur de bord pour ma R11, même un MEGA ne suffira pas, il va falloir que je me tourne vers d'autres solutions ou rajouter des interfaces à base de PIC, donc apprendre un nouvel environnement de programmation etc etc.

Je ne crache pas dans la soupe, rassurez-vous! XD On parle juste ici de notions difficilement applicables au simple arduino, car on touche les limites.

Si tu veux rajouter des pins tu mets des latchs externes. Si t'en veux beaucoup tu peux les décoder avec un 138. Un simple 7400 te permet de masquer 4 interruptions par hardware. Et puis il esxiste aussi un vieux truc qu'on appelle PAL... Certains connaissent sans doute mais ATmega + 1 seul PAL ca en fait des choses...

JLB