bonjour a tous, j'ai un petit problème de code que je n'arrive pas a solutionner j'utilise un récepteur infrarouge type TSOP34856 surveiller par un une fonction ISR comme ceci :
//ISR ROUTINE
ISR(TIMER2_OVF_vect, ISR_NOBLOCK){
//RECEPTION
rxRead1 = (PIND & B10000000) >> 7; //aka read pin 7, the fast way
rxRead2 = (PIND & B00010000) >> 4; //aka read pin 7, the fast way
rxTimer++;
switch (rxState) { //check current state of rx message CAPTEUR 1
case STATE_IDLE: //idle, waiting for something to start
if (rxRead1 == MARK) {
if(rxRead2 == MARK){
dircapteur = 1;
}
else{
dircapteur = 0;
}
rxTimer = 0;
rxState = STATE_MARK; // transmission begins, check HDR (header)
}
break;
case STATE_MARK: // timing MARK
if (rxRead1 == SPACE){ // MARK ended, record time
rawData[rawIndex] = rxTimer;
rawIndex++;
rxTimer = 0;
rxState = STATE_SPACE;
}
break;
case STATE_SPACE: // timing SPACE
if (rxRead1 == MARK){ // MARK ended, record time
rawData[rawIndex] = rxTimer;
rawIndex++;
rxTimer = 0;
rxState = STATE_MARK;
}
else if(rxTimer > 34) {rxState = STATE_STOP;}
break;
}
}
Cette fonction marche très bien sauf quel est perturbé par la librairie LIquid_CrystalI2c ou wire.
Le récepteur infrarouge reçoit des trame de code en rafale et si l’écran est utilisé en même temps certains code sont erronée, par-contre si je n'envoie pas de commande a l’écran il décode 100% des trame.
...
receivehit(); //Il s'agit de la fonction qui décode les trame
//osd(); //Gestion de l'affichage de parametre
//Gestion backlight
if(backlightlcd == 1){
//lcd.backlight();
backlightoff = 0;
}else if(backlightlcd == 0 && backlightoff == 0){
backlightoff = 1;
//lcd.noBacklight();
}
....
void receivehit(){
// COMPUTE INCOMING DATA
if(rxState == STATE_STOP){ // DATA! a STOP has been issued meaning there's something to compute
for(rawIndex = 0; rawIndex < 40; rawIndex++){
if(rawIndex % 2 == 0){ //even positions, no spaces
if(rawIndex == 0 && !match_hdr(rawData[rawIndex])) { //first position (hdr)
break;
}
else if(rawIndex != 0) { //not the hdr
if(match_one(rawData[rawIndex])) rxData = (rxData << 1) | 1;
else if(match_zero(rawData[rawIndex])) rxData <<= 1;
else{
break;
}
}
}
else{ //odd positions, spaces
if(rawData[rawIndex] == 0) break;
else if(!match_zero(rawData[rawIndex])){
break;
}
}
//Serial.print(" ");
//Serial.print(rawData[rawIndex]);
}
//Serial.println("");
Serial.println(rxData,HEX);
//prepare for next data
for(rawIndex=0; rawIndex<40; rawIndex++){ //clear rawData array
rawData[rawIndex] = 0;
}
rxData = 0;
rawIndex = 0;
rxState = STATE_IDLE; // sets the state of the receiver to idle (default)
}
}
Si je dé commente une de ces lignes la réception infrarouge n'est plus fiable.
Regarde le code de LiquidCrystal_I2C mais j'ai comme l'impression que tu as un conflit de ressource.
Ton code utilise le timer 2 pour la réception et je suis quasi sûr que LiquidCrystal_I2C utilise ce même timer 2 pour faire la PWM qui fait marcher le rétroéclairage de l'écran.
Une lecture rapide du code source de la lib te donneras toutes les réponses à tes questions.
En fait je suis idiot (ou alors vraiment pas réveillé ... je sais pas).
Ta version de LiquidCrystal_i2c n'utilise pas de PWM pour le rétro-éclairage.
Il est juste éteint ou allumé. Donc pas de problème de Timer2.
Par contre la lib utilise Wire pour l'I2C. Et Wire utilise en interne une interruption pour fonctionner.
Donc si tu utilises l'écran trop souvent, l'interruption de Wire s’exécute tout le temps et bloque ton interruption à toi.
Le mieux que tu puisses faire c'est de réduire/limiter la fréquence de rafraîchissement de l'écran pour éviter de perdre trop d'interruptions de ton côté. Tu peux pas faire grand chose d'autre ...
Ah ok, enbetant cette histoire, la réception infrarouge correspond a tir d'un autre joueur car il s'agit d'un système de laser game donc je ne peut pas vraiment perdre de trame pour l’équité du jeu.
Je ne peut pas donner la priorité a mon instruction, ou autre ?
lemat:
Ah ok, enbetant cette histoire, la réception infrarouge correspond a tir d'un autre joueur car il s'agit d'un système de laser game donc je ne peut pas vraiment perdre de trame pour l’équité du jeu.
Effectivement c'est assez embêtant ...
lemat:
Je ne peut pas donner la priorité a mon instruction, ou autre ?
Non ce n'est pas possible.
Et il me semble pas avoir vu un jour une version modifié de Wire n'utilisant pas d'interruptions ...
haifger:
Peut-être essayer de diminuer la fréquence du bus I²C. Ça ne résoudra sans doute pas le problème, mais ça peut en diminuer la fréquence d'apparition.
Diminuer la fréquence de l'i2c risque d'être compliqué vu que c'est la lib qui fait l’initialisation.
Diminuer la fréquence de rafraîchissement de l'écran est plus simple et plus rapide, en bonus on peux aussi essayer de rendre l'interruption de l'IR pour la rendre plus rapide (mais c'est déjà plus complexe).
Pour le rafraîchissement de l’écran je peut le limiter a toutes les une seconde (Car affichage d'un compte a rebours avec MM:SS).
J'ai des événement qui demande a être plus rapide que ça mais je peut les afficher que lorsque c'est vraiment nécessaire.
skywodd:
Diminuer la fréquence de rafraîchissement de l'écran est plus simple et plus rapide, en bonus on peux aussi essayer de rendre l'interruption de l'IR pour la rendre plus rapide (mais c'est déjà plus complexe).
De quelle manière pourrait t'on rendre l'ISR plus rapide ?
Mise a jour de l'affichage des donnée quand celle ci sont modifié
Compte a rebours mis a jour a l'affichage toutes les 5s quand le rétroéclairage de l’écran est éteint (quand même lisible).
J'ai aussi fait en sorte qu'il n’écrive pas en boucle sur l’écran des donnée qui vont être remplacer quelques seconde puis ré-afficher ensuite surtout pour celle ou ça peut arriver seulement 3-4 fois par partie.
Voila ci c'est quelques petites infos sur la correction de ce problèmes peuvent en aider d'autre tant mieux
Merci beaucoup skywodd, le problème est résolue je ne ressent presque plus du tout l'interruption wire.
quel type d'ecran i2C est-ce?
ce que tu as sur ton montage s'en tiend a IR + 1 lcd + I/O basique?
1ere solution simple: passer sur un ecran en com // 7 fils: la lib n'est pas interruptive
2eme solution plus penible: reproduire la com i2c pour piloter l'ecran (le briquoler un peu si besoin)
Je ne savais même pas que je pouvais faire :
ISR(TIMER2_OVF_vect, ISR_BLOCK){
Je viens de faire un essais même en déclenchant des action de l’écran pendant les réception, plus aucuns code raté
Tu vient de régler définitivement mon problèmes jean-l MERCI
J'ai un écran alphanumérique 2x16 lignes de caractères.
J'utilise presque tout ce que sais faire l'arduino :
Bluetooth en serial
NRf24l01+ en SPI
I2C pour l'ecran
I/0 basique et pwm pour émission et réception IR
L’écran était obligatoirement en I2C sinon je n'avait pas assez de pin sur le 328PU ^^
Mais bon maintenant que tout roule ce n'est plus un problèmes
les interruptions c'est tres simple et tres compliqué a la fois.
ISR(TIMER2_OVF_vect, ISR_BLOCK)
est la meme chose que
ISR(TIMER2_OVF_vect)
une interruption peut en interrompre une autre, c'est a toi de gerer l'imbrication.
d'une maniere generale, une interruption materielle sera prioritaire.
il faut dans la mesure du possible reduire au minimum le temps d'interruption.
l'utilisation de
rxRead1 = (PIND & B10000000) >> 7; //aka read pin 7, the fast way
rxRead2 = (PIND & B00010000) >> 4; //aka read pin 7, the fast way
est donc plus que judicieuse. et si tu te sert de rxRead que dans cette routine, tu peut meme t'abstenir de shifter >>.
...
c'est quoi comme module bluetooth que t'utilise?
quand tu fait
rxRead1 = (PIND & B10000000) >> 7;
rxRead1 vaut donc 0 ou 1, pas autre chose.
tu test ensuite si
if (rxRead1 == MARK)
ou
if (rxRead1 == SPACE)
je presume que MARK et SPACE sont soit 0, soit 1.
tout ce qui est 0 n'est forcement pas 1, y'a pas besoin de shifter, le masque & renvoi 0 ou pas 0.
... ni meme donc d'effectuer un test de comparaison.
si en plus rxRead1, MARK ou SPACE sont des int au lieu de char, ca fait 2 octets a tester (j'ai pas chercher a savoir comment le compilateur pouvait optimiser)
si tu t'en tiend a
if (rxRead1)
et
if (not rxRead1)
t'economise quelques cycles horloges (et quelques octets de prog, t'as qu'a regarder la difference au message de compil).
mais bon, ca n'a pas l'air critique a ce point, vu que ca fonctionne.
Je n'ai pas tout a fait compris, par quoi devrait je remplacer :
rxRead1 = (PIND & B10000000) >> 7;
par :
rxRead1 = (PIND & B10000000) ;
?
MARK et SPACE sont des #define
Comme tu le dit ça fonctionne mais si je peut gagner quelques octet je prend ça commence a être juste, par rapport a ma première version j'ai réussi a gagner presque 6Ko d'espace en optimisant (type de variable, fonction, non répétition de code etc)