je cherche à créer des pages d' affichages pour mon boitier de contrôle de climat,
voici le contexte( si je puis dire):
-Un écran deux fois 16 lignes.
-Un encodeur utilisant " une seule " broche d' interruption ( INT1 / PD3 ).
-Un bouton "Valider" sur la broche PD4.
-Un bouton "Menu/Precedent" sur la broche PD2. ( INT0 ).
J' ai voulu coder l' interruption INT0 de cette manière:
void setMenu() // bouton Menu/Precedent
{ // Cette fonction est appelée dans le void setup()
DDRD &=~ (1<<2);
PORTD |= (1<<2);
EICRA |=1<<ISC00;
EIMSK |= 1<<INT0;
sei();
}
ISR(INT0_vect)
{
lcd.clear(); lcd.setCursor(0,0); lcd.print("Sélectionner");lcd.setCursor(0,1);
}
Le résultat du compilo:
core.a(WInterrupts.c.o): In function `__vector_1':
C:\Program Files (x86)\Arduino\hardware\arduino\cores\arduino/WInterrupts.c:309: multiple definition of `__vector_1'
sketch_may29a.cpp.o:C:\Program Files (x86)\Arduino/sketch_may29a.ino:138: first defined here
J' ouvre donc le WInterrupts.c et je fais une recherche de la chaine de caractères " __vector_1", et le moteur de l' éditeur de texte ( Geany) ne la trouve pas.
Je cherche donc le fichier " WInterrupts.h " pour voir les prototypes de fonctions, mais je ne le trouve nul part. Il me semble pourtant qu' on ne peut créer une librairie sans un fichier d' entête...
Quelqu'un saurait m' expliqué ce qui se passe et pourquoi?
#if defined(__AVR_ATmega32U4__)
// I hate doing this, but the register assignment differs between the 1280/2560
// and the 32U4. Since avrlib defines registers PCMSK1 and PCMSK2 that aren't
// even present on the 32U4 this is the only way to distinguish between them.
Je fais ça sur un 328p, ...
Mais pourquoi vouloir réinventer la roue ? attachInterrupt()
C' est parce que je voudrais juste me rapprocher du micro contrôleur en terme de programmation afin de progresser toujours un peu plus.
Mais je vais quand même le faire avec l' "attachInterrupt()", ne serait-ce que pour finir l' ensemble du code dans un premier temps. ( c' est une horreur ceci dit en passant ).
Mais pourquoi vouloir réinventer la roue ? attachInterrupt()
Ré-écrire la lib Wire oui ce serait réinventer la roue mais là ce n'est pas le cas, c'est optimiser la programmation.
Passé les petits désagréments du début c'est quand même plus simple coté programme --> on dit toujours qu'il faut qu'une interruption soit la plus courte possible, pourquoi ajouter une fonction alors que c'est inutile.
Chercher à faire fonctionner un ISR permet aussi de se rendre compte que l'on peut connecter une interruption sur n'importe quelle pin y compris A0 à A5 quand elles sont utilisées en pins numériques.
@weetoz :
Tu dit vouloir utiliser l'interruption int1 qui est associée à la broche D3.
or tu configure : EICRA |= 1<<ISC00
Ne serait-ce pas plûtot :
EICRA |= 1<<ISC10
pour l'int1
Pour la configuration des registres il y a des constantes prédéfinies dans les fichiers de l'avr-libc. La "surcouche" arduino utilise ces fichiers, ils sont donc disponibles à partir de l'IDE.
Par exemple pour un 328p le fichier des définitions se nomme iom328.h (sous Linux /usr/lib/avr/include/avr/iom328.h)
Il est possible d'écrire
DDRD |= (1<<DDRD3) ;
PORTD |= (1<<PORTD3);
Ce qui soit dit en passant me semble plus juste que ce que tu as écrit.
NB la macro Signal est "deprecared" depuis au minimum 2002
pas d' erreur sur mon code, pour l' INT1, c' est l' encodeur rotatif, lui ça passe...
L' INT0, celui que je veux causer aux registre est l' INT0 sur front montant.
J' ai essayé ça:
DDRD |= (1<<DDD2);
PORTD |= (1<<PORTD2);
En effet, ça ne change rien sur le nombre de bytes du programme, et c' est plus lisible, merci 68TJS.
D' ailleurs, en commentant la fonction ISR, le code compile sans erreur apparente et surtout plus celle là:
"core.a(WInterrupts.c.o): In function `__vector_1':"
C' est bizarre ça!
Sinon coté attachInterrupt();, ça compile, mais ça ne rentre pas dans la fonction attaché:
Partie attachInterrupt():
Si tu avais des problemes de rebond tu aurais des déclenchement excédentaires de l'interruption or si j'ai bien compris ( ça reste à prouver) l'interruption ne se déclenche pas.
Truc bête et si tu inverse les branchements (logiciel) de l'encodeur et du poussoir ?
Trois remarques, mais je ne vois pas tout loin de là.
iom328.h est déjà utilisé par l'environnement arduino --> il est déjà inclu, sans doute (je n'ai pas vérifié) dans arduino.h
Il est inutile de le ré-inclure. Mais comme les réinclusions sont protégées le problème n'est pas là.
effectivement il y a des actions qui posent problème dans un ISR.
Pourquoi ne pas simplement y changer la valeur d'un booléen et surveiller la valeur de ce booléen dans loop ?
Je ne sais pas comment tu as cherché à faire la mise au point mais tu as tout intérêt à faire autant de petit programme que tu as de problème à résoudre : moins il y a de choses à gérer plus c'est facile moins c'est difficile.
Toujours le problème de '__vector_1' dans WInterrupt.c.o
Pour la mise au point, ce sera au fur et à mesure et en fonction de ce que j' arrive à faire.
(exemple: comment gérer l' encoder avec 2 paramètres "min" et "max", alors que visiblement les ISR ne prennent pas de paramètres, à vérifier,bref...)
C' est sûre que je n' en ai pas fini, mais ça progresse, et c' est ce qu' il faut.
Pour l' instant je vais continuer à scruter la datasheet du 328p, et fouiller du coté de l' installation de l' IDE Arduino, la syntaxe 'ISR(INT0_vect)' doit appeler le fichier WInterrupts.c ou quelque chose dans ce genre.
Il y a ça dans la datasheet:
The External Interrupt 0 is activated by the external pin INT0 if the SREG I-flag and the corresponding interrupt
mask are set.
Non ISR n'as strictement rien à voir avec Winterrupt.
ISR est une micro Atmel. Elle est en haut de la pyramide.
ISR est utilisé par les fonctions arduino.
Winterupt fait partie de l'IDE arduino , c'est donc une sur-couche.
Si tu te sert de la fonction arduino attachinterrupt, Winterrupt est utilisé, mais si tu utilises directement ISR, Winterrupt ne sert strictement a rien puisque ISR fonctionne en dehors de l'environnement arduino.
Ok, j' ai une variable globale de type byte qui s' incrémente lorsque j' appuie sur le bouton, donc je rentre bien dans l' interruption par le biais d' " attachInterrupts ".
Donc, avec la fonction attachInterrupt(), pas de problème de WInterrupts.c, mais quand on code direct l' ISR, ça ne fonctionne pas!
....
Tu as un autre problème car comme tu peux le voir dans le fichier Winterrupt.c la fonction attachinterrupt() utilise la macro ISR.
Regarde au passage les configurations des registres pour un atmega328p.
@dfgh: Bonjour, et merci, pour moi, je crois que je vais finir par réinstaller l' ide arduino, et repasser en 1.0.5, ne serait-ce que pour écarter la cause "logiciel". Merci d' avoir vérifié que ça compile bien dans ton environnement.
@68tjs: c' est assez logique, pas d' appel d' ISR, donc pas d' interruption ( page 70 à 74 dans la datasheet ).
Je te remercie encore 68tjs, pour ta disponibilité, je sais que tu bosses beaucoup sur l' amélioration du forum et que ça te prends du temps, j' apprécie d' autant plus ton suivis.
Ce qui est très peu compréhensible, c' est le fait que quand on s' affranchi de la fonction attachInterrupt, c' est le fait que le compilateur appel la librairie WInterrupts.c, et c' est l' inverse qui se produit dans ce cas précis.
Je vais réinstaller l' IDE, et si ça ne fonctionne toujours pas, il va falloir que je revois mon approche.
Je te remercie encore 68tjs, pour ta disponibilité, je sais que tu bosses beaucoup sur l' amélioration du forum et que ça te prends du temps, j' apprécie d' autant plus ton suivis.
C'est fini, j'ai bien galéré avec l'écriture des liens.
Si quelqu'un y arrive du premier coup je suis preneur de la solution, moi il faut je poste puis que j'édite le message car dans l'opération de postage tout plein de "http:/\ " viennent s'ajouter dans le lien.
(Pardon j'ai appris dernièrement que "tout plein" c'est "basse classe").
Plutôt que de réinstaller l'IDE je referais un nouveau programme en partant de zéro, surtout pas de couper/coller.
Parce qu'il y a peut-être une faute d'inattention cachée.
Dans ce nouveau programme j'ajouterais les fonctions une par une.
Cela parait être du temps perdu mais au final ce sera du temps gagné.
Un moyen de tester simplement.
Tu déclare une variable test
volatile uint8_t test ;
volatile : parce que manipulée par une interruption
uint8_t : ce n'est pas obligatoire mais cela force un entier non signé sur 1 octet.
Dans setup tu initialise : test =0
Dans loop tu fais
if (test)
{
j'allume la led DEL de la pin 13 ;
pause pendant 1 seconde ;
test = 0 ;
}
Dans l'ISR tu fais :
ISR(vecteur_qui_va_bien)
{
test = 1 ;
}
Dés que tu appuis sur le bouton, test passe à 1.
Quand la boucle loop viendra lire la variable test elle allumera la del pendant 1 seconde puis s'éteindra, jusqu'au prochain appui sur le bouton..
Et ceci tu le fais successivement pour les deux interruptions.
Quand cela ne fonctionne pas il ne faut pas se prendre la tête mais revenir aux tests courts et basiques.
Nb : si j'ai écrit if (test) et non pas if (test==1) c'est que je suis une grosse faignasse et que depuis que je sais que dans une condition soit on a 0 et la condition est fausse, soit on a un entier quelquonque et la condition est vrai --> je vais au plus court et j'économise des cycles horloges.
bien vu, je n' ai plus ce problème avec WInterrupts()...
peut-être que le fait d' utiliser attachInterrupt() pour une interruption et les registre pour l' autre interruption, à fâché AVRDUDE.
Voici le code pour le bouton:
Et ça fonctionne très bien.
Je vais donc tout reprendre à zéro, merci 68tjs, ça remotive!
Nb : si j'ai écrit if (test) et non pas if (test==1) c'est que je suis une grosse faignasse et que depuis que je sais que dans une condition soit on a 0 et la condition est fausse, soit on a un entier quelquonque et la condition est vrai --> je vais au plus court et j'économise des cycles horloges.
J' avais vu ça dans une vidéo de Jean-Danièle NICOUD, mais je n' avais pas compris qu' on gagnait un cycle d' horloge. ( toujours bon à prendre ).
Je n' ai plus qu' à me débarrasser du digitalWrite() et ça va vraiment me permettre de progresser aussi sur la taille du code.
Non pas possible.
Le compilateur crée des fichiers objets. : *.o
L'éditeur de liens et quelques copains à lui créent un fichier *.hex à partir des fichiers *.o
Avrdude c'est un chauffeur de taxi qui récupère le fichier *.hex et qui le livre à l'intérieur de la puce micro-contrôleur.
Il ne contrôle pas qu'il y a dans le paquet qu'il livre.
Celui qui se fâche c'est le compilateur..
Je n' ai plus qu' à me débarrasser du digitalWrite()
Moi aussi j'aime bien aller au plus court mais il ne faut pas être intégriste non plus.
Il faut admettre qu'écrire DDRX = (1<< ACBD0) n'est pas ce que l'on fait de plus clair, même si c'est le plus efficace.
Ce n'est pas forcément le plus facile à débugger.
Personnellement dans le setup j'utilise les registres car le setup est statique.
Pour la mise au point des fonctions, sauf contre indication comme la gestion d'un DHT22, j'utilise digitalW/R. Quand la fonction est correcte je remplace si c'est utile.
Par contre on n'est pas obligé d'écrire digitalWrite(pin, HIGH) ou digitalWrite(pin, LOW) .
Ecrire digitalWrite(pin, 1) ou digitalWrite(pin, 0) fonctionne très bien et amha est plus clair et universel puisque cela fait réfèrence à un état logique et non pas à un état électrique.