Merci pour ces réponses même tardive
oui en éffet je viens de trouver le câblage ici merci!
Code:http://ww1.microchip.com/downloads/en/DeviceDoc/30277d.pdf
-----
Merci pour ces réponses même tardive
oui en éffet je viens de trouver le câblage ici merci!
Code:http://ww1.microchip.com/downloads/en/DeviceDoc/30277d.pdf
Encore mieux, voici le schéma, si certains sont intéressés, attention schéma pour PIC16F1826
Salut Seb,
Il y a une petite erreur dans le schéma. Une des résistances "to normal connections" devrait bien sûr être sur la ligne Clock
a+
Je reviens vers vous car j'ai de nouveau un petit problème au sein de mon programme,
au niveau de l'entrée cette fois je pense que ma variable n'est pas bonne...
Lorsque j'appuie sur mes BP j'aimerai que ça incrémente une variable et selon la valeur de cette variable, je sélectionne une sortie en particulier...
mais la partie Selection_Vit et Selection_Mot de mon prog n'a pas l'air de marcher...
Merci pour votre aide!
Code:#include <htc.h> #include <stdio.h> int Selmot; //sélection moteur int Selvit; //sélection vitesse int Selvitbp; //sélection bp vitesse int buffer; int buffervit; //Déclaration des sous fonctions void Selection_Vit (void); void Selection_Mot (void); void Defaut (void); void Init (void); //================================================================ void main(void) { Init(); //Init entrées et sorties Defaut(); //Mode défaut au démarrage while (1) //boucle infinie { Selection_Vit (); Selection_Mot (); if (RA3==1) { while(RA3==1) { Selvit=1; } } //----------------------------------------- if (RA4==1) { while(RA4==1) { Selvit=LATB4; Selvit=1; } } //----------------------------------------- if (RA5==1) { while(RA5==1) { Selvit=LATB5; Selvit=1; } } //----------------------------------------- if (RA6==1) { buffer++; } //----------------------------------------- continue; } } //================================================================ void Init (void) { OSCCON=0b10000010; //oscillateur interne on a 31KHz TRISB=0x00; //PortB en sortie TRISA=0xff; //PortA en entrée ANSELA=0x1f; //entrée analogique ANSELB=0x00; //sortie analogique buffer=1; //buffer sélection moteur buffervit=2; //buffer sélection vitesse PORTB=0; //init port B } //================================================================ void Defaut (void) { LATB0=0; //sélection moteur 1 on LATB1=1; //sélection moteur 2 off Selvit=LATB3; } //================================================================ void Selection_Mot (void) { if (RA2==1) { LATB0=1; LATB1=1; } else { Selmot=buffer; buffer = 1; if (RA0==1) { buffer++; } if ((Selmot % 2)==0) //si selmot est pair { LATB0=1; LATB1=0; } else { LATB0=0; LATB1=1; } } } //================================================================ void Selection_Vit (void) { if (RA7==1) { Selvit=LATB6; //Sur du 12V directement } else { Selvitbp=buffervit; if (RA1==1) { buffervit++; } switch (Selvitbp) { case 1: Selvit=LATB2; break; case 2 : Selvit=LATB3; break; case 3: Selvit=LATB4; break; case 4: Selvit=LATB5; break; default: Selvitbp=1; } } }
LATB à utiliser pour une sortie , LATB5=1
PORTB à utiliser pour une entrée , mavariable=PORTB0
Non c'est inexact, PORTB n'a rien à voir dans le fait que ce soit une entrée ou une sortie, c'est TRISB qui permet de donner la direction du port.
TRISB = 0xFF tout le port B est en entrée.
TRISB = 0 tout le port B est en sortie.
Seb, pour utiliser des BP il faut utiliser de préférence le mode interruptif en connectant tes BP sur des entrées prévues pour détecter des changements de niveaux et provoquer une interruption.
Donc regarde le PORTB qui est prévu à cet usage.
En d'autres termes il ne faut pas focaliser sur LATx pour ton problème, ce qui compte avant tout c'est de bien saisir l'importance des bits de config qui sélectionnent correctement les fonctions des ports multiplexés, de l'oscillateur, etc. et du bon usage des interruptions.
Ca c'est vraiment le plus important.
Un programme bien écrit peu se passer des LATx pour des fonctions de programme aussi simplistes.
@+
Il faut que tu postes un schéma pour indiquer clairement ce qui va sur tes entrées (B.P ou jumper, etc).
Par exemple quand tu écris ça:
c'est plutôt tiré par les cheveux cette histoire de pair et impair.Code:if (RA0==1) { buffer++; } if ((Selmot % 2)==0) //si selmot est pair { LATB0=1; LATB1=0; } else { LATB0=0; LATB1=1; } }
D'autant que ta boucle est tellement courte que tu vas incrémenté buffer à la vitesse grand V... rien que le temps que tu vas enlever ton doigt du BP buffer sera déjà à 150 au moins.
Il faut donc que tu n'autorises qu'une impulsion de BP à chaque appui à mon avis pour mieux maitriser ce que tu veux déclencher.
Au passage il est inutile d'écrire:
Cela suffit:Code:if(RA0 == 1)
étant donné que RA0 ne peut prendre que la valeur 0 ou 1 et que le if est accédé dès l'instant que la condition est vraie donc qu'elle vaut 1.Code:if(RA0)
Enfin, si tu bloques, le mieux est de commencer simple avec juste la détection des appuis de B.P.
Tu appuies-> tu allumes la led qui va bien, ensuite ça ira tout seul et tu ajoutes progressivement ton code.
Evites les simulateurs et autres conneries qui ne t'apprendront rien de bon.
Un grand merci pour ton aide!! je vais essayé de mettre tout ça en code!
voici mon schéma!
Pour revenir sur l'action des BP,
J'aimerai que le BP sur RA0 me sélectionne le moteur à utiliser selon si le nombre d'appui sur le bouton est pair ou impair,
et pour le bp sur RA1 il me sélectionnerait "l'alim" qui alimente mes moteurs, pareil j'aimerai sélectionner la sortie en appuyant sur le BP (appuie 1 fois sortie 1, 2 fois sortie 2, 3fois sortie 3...)
Mais la je m'y perds un peu en effet avec la tempo...
merci pour ton aide, aussi courtoise soit-elle... -_-"
tu as surement raison, les mosfet n'ont jamais était mon fort, je pensais pourtant que la commande marcherait, tu aurais une solution à m'apporter?
SI le port est configuré en entrée , lire latb retournera la valeur du registre latb mais pas la valeur réel des pin d'entées.
c'est pas comme si on avai passé une page du post à lui expliquer la différence entre latx et portx.En d'autres termes il ne faut pas focaliser sur LATx pour ton problème, ce qui compte avant tout c'est de bien saisir l'importance des bits de config qui sélectionnent correctement les fonctions des ports multiplexés, de l'oscillateur, etc. et du bon usage des ......
@+
Certainement, en même temps quand on lit ce qui traine sur la toile sur ce sujet c'est assez consternant...
Je pense que ceux qui vont lire les soi-disantes "explications" trouvées vont bien confuser ensuite.
Pour ton schéma Seb:
sur RB0 et RB1 notamment il faut toujours mettre une résistance entre grille et source de ton NMos (100K par exemple) sans quoi il va osciller si ton port se trouve en entrée ou en haute impédance ce qui est le cas avant que le programme fige le port en sortie avec un niveau 1 ou 0 ou pendant la prog.
Idem pour les autres Mos évidemment.
Comme le disait Daudet, l'usage d'un NMos sur les autres port avec la charge à la source ne donnera rien bien sur donc il faut nécessairement que le moteur soit dans le drain avec une diode anti-retour pour protéger le Mos.
De manière générale comme je te le disais plus tôt il faut mettre tes BP sur les entrées interruptives RBx prévues pour cela.
Pour RB6 et RB7 il ne faut pas les laisser en l'air sans quoi tu vas consommer inutilement, tu peux mettre une résistance de 10K à la masse en fixant ces 2 ports en entrée.
Cela ne perturbera pas la programmation via l'ICSP.
RA0 idem, une entrée de µC étant Cmos on ne laisse jamais une entrée en l'air.
Enfin pour terminer, tu ne représentes pas l'alimentation du µC source de tant de déboires pourtant.
Il faut mettre un 10µF céramique multicouche ou un tantale 10µF avec un 100nF en parallèle au plus près des pattes d'alim.
Comme tout Cmos un µC consomme pendant les changements de niveaux logiques, le but de ce découplage est de créer un réservoir d'énergie suffisant afin de fournir ce que réclame l'alimentation du µC, et de minimiser ainsi les pics de courant le long de la ligne d'alimentation.
@+
Merci Hulk28 pour ton aide! je viens de revoir tout mon schéma
je recommence également mon programme C pas à pas, et j'ai une petite question à propos de ça...
j'aimerai que lorsque j'appuie sur BP1, appui long de 2secondes voir 3, je change de sortie pour sélectionner mes moteurs, mais mon problème c'est que la sortie bouge une fraction de seconde, j'ai donc le changement mais dessuite ça revient à l'état du début, au lieu d'être permanent...
voici mon code à l'intérieur de ma boucle
Code:if (RA6) //ra6 est relié à BP1 { Tempo(); //tempo d'environ 2secondes if (BP1) { ok=1; } } if (ok==1) { LATB2=1; // permutation moteur LATB3=0; }
Je t'ai déjà expliquer qu'il faut utiliser les interruptions pour gérer les évènements sur les BP.
Ta tempo suivi du if n'a aucun sens quand on sait comment réagit un BP, je ne vois aucun anti-rebonds soft dans ton code après tes 2 secondes de tempo... et il faudrait voir le reste du code pour savoir comment s'effectue le retour à l'état initial des moteurs.
Voici le code sur lequel je suis entrain de me pencher,
je pensais pourtant avoir activé comme il fallait les interruptions,
Code:#include <htc.h> #include <stdio.h> #define BP1 RB0 #define BP2 RB1 unsigned tempo; unsigned tempo2; int ok; void antirebond(void); void Tempo(void); void main(void) { INTCON=0b10001001; //interruptions on OSCCON=0b01110010; //oscillateur interne on TRISB=0x03; //PortB en sortie TRISA=0xff; //PortA en entrée ANSELA=0x00; //entrée analogique PORTB=0; //init port B LATB2=0; //sélection moteur 1 au démarrage on LATB3=1; //sélection moteur 2 au démarrage off while(1) { (RA1==1)?LATB4=1:LATB4=0; if(BP1) { antirebond(); Tempo(); if (RA6) { ok=1; } while (BP1); antirebond(); } if (ok==1) { LATB2=1; LATB3=0; } else { LATB2=0; LATB3=1; } } } void Tempo(void) { for (tempo=0;tempo<65535;tempo++); for (tempo=0;tempo<65535;tempo++); for (tempo=0;tempo<65535;tempo++); for (tempo=0;tempo<65535;tempo++); } void antirebond(void) { for (tempo2=0;tempo2<2000;tempo2++); // anti-rebond }
Bon il y a des choses à revoir
Déjà concernant tes variables:
Pourquoi déclares-tu ok en int ??
ok c'est 0 ou 1 (ok ou pas ok), ici un char est grandement suffisant non ?
Si je peux me permettre un conseil évite cette écriture très peu lisible tant que faire se peut, l'opérateur ternaire permet une écriture plus reserrée certes, mais personnellement je la trouve plutôt confusante et ça n'apporte pas grand chose.Code:(RA1==1)?LATB4=1:LATB4=0;
kesako ?Code:if(BP1) { antirebond(); Tempo(); if (RA6) { ok=1; } while (BP1); antirebond(); }
On ne fait pas un anti-rebonds tout à fait comme ça.
L'anti-rebonds est une subtilité qui consiste à masquer les imperfections d'un contact qui n'offre pas un niveau fixe au moment où on lui appuie dessus, résultat -> on a des oscillations parasites qui sont détectées à 1 ou à 0 pendant 100ms à 200ms ce qui fausse le résultat escompté.
En pratique voici la séquence lors de l'appui:
On appui -> mise à 1 puis rebonds (0,1,etc) -> 200ms -> relâchement de l'appui -> retour à 0
Donc il est plus logique d'attendre le retour à 0 définitif pour prendre en compte l'appui.
Appui -> mise à 1 -> premier retour à 0 (au premier rebond) -> on valide comme si on venait de relâcher le bouton -> on interdit une nouvelle validation pendant 200ms minimum.
L'inconvénient d'un délai est qu'il bloque le reste du programme.
Le mieux est donc comme souvent le mode interruptif qui lui a le gros avantage de ne bloquer personne ni de rater aucun autre évènement.
En résumé ça donnerait un premier exemple comme ça:
C'est un exemple écrit comme ça sans vérification mais tu as ci-dessus le principe général.Code:.... #define tempo_antirebonds 100 // valeur à fixer selon le réglage du timer0 volatile char flag_tempo_antirebonds = 0, fin_tempo_anti_rebonds = 0 ; ... void main(void) { ..... if (BP1) { while (BP1); on attend le premier relâchement ou rebond flag_tempo_antirebonds = 1; // flag activé pour valider un comptage de temps en interruption while (!fin_tempo_anti_rebonds); // on attend la fin de la tempo traitée en interruption ok = 1; // } .... } void interrupt (void) // voir la déclaration correcte selon le compilo C { if( T0IF && flag_tempo_antirebonds) { T0IF = 0; // clear du flag de Timer0 tempo_antirebonds --; // on décompte à chaque débordement de timer0 if(tempo_antirebonds == 0) { fin_tempo_anti_rebonds = 1; // la tempo est terminée flag_tempo_antirebonds = 0; // on interdit l'interruption } } }
Il y a d'autres façon de faire en matière d'anti-rebonds mais l'usage des interuptions est (très) grandement conseillée.
Dans ton programme tu as autorisé les interruptions mais en fait tu ne t'en sers pas
Tu dois faire appel à la routine d'interruption, c'est là que tu vas gérer les évènements.
Avec Hitech C c'est void interrupt it_gene(void); la fonction qui gère les évènements sous interruptions.
Avec C18 c'est void it_prioritaire(void);
Dans tout les cas bien lire la doc de son compilo pour savoir comment déclarer la syntaxe exacte.
@+
Merci pour toutes ces infos! tu m'aiguilles énormément !
j'ai essayé de modifier le code à ma sauce, mais je n'arrive pas à switcher de moteur... si je comprends bien le code, une fois appuyé sur BP1 (et une fois la tempo finie mon moteur devrait changer) mais ce n'est pas le cas...
Code:#include <htc.h> #include <stdio.h> #define BP1 RB0 #define BP2 RB1 int tempo_antirebonds=40; // valeur à fixer selon le réglage du timer0 volatile char flag_tempo_antirebonds = 0, fin_tempo_anti_rebonds = 0 ; char ok; void interrupt it_gene(void); void main(void) { INTCON=0b11101001; //interruptions on // TMR0IE = 1; // GIE = 1; TMR0=0x00; OPTION_REG=0x07; //tmr0 option OSCCON=0b01110010; //oscillateur interne on TRISB=0x03; //PortB en sortie TRISA=0xff; //PortA en entrée ANSELA=0x00; //entrée analogique PORTB=0; //init port B LATB2=0; //sélection moteur 1 au démarrage on LATB3=1; //sélection moteur 2 au démarrage off while(1) { (RA1==1)?LATB4=1:LATB4=0; if (BP1) { while (BP1); //on attend le premier relâchement ou rebond flag_tempo_antirebonds = 1; // flag activé pour valider un comptage de temps en interruption while (!fin_tempo_anti_rebonds); // on attend la fin de la tempo traitée en interruption ok = 1; } if (ok==1) { LATB2=1; LATB3=0; } else { LATB2=0; LATB3=1; } } } void interrupt it_gene(void) // voir la déclaration correcte selon le compilo C { if( TMR0IF && flag_tempo_antirebonds) { TMR0IF = 0; // clear du flag de Timer0 tempo_antirebonds--; // on décompte à chaque débordement de timer0 if(tempo_antirebonds == 0) { fin_tempo_anti_rebonds = 1; // la tempo est terminée flag_tempo_antirebonds = 0; // on interdit l'interruption } } }
Normal tu as mis en commentaire les interruptions, donc par défaut elles sont toutes off
Il ne faut pas confondre la routine d'interruption qui gère les évènements et les bits d'interruptions des registres du µC qui déclenchent ou pas les interruptions matériels.
Bien entendu pour s'en servir de ces interruptions il faut les activer au niveau du matériel (registres du µC)
Autant pour moi
je pensais avoir validé les bits TMR0IE et GIE directement dans le registre INTCON.
Mais même en mettant
Le moteur ne switch pas :/ comme si la fonction interruption ne marchait pasCode:INTCON=0b11101001; //interruptions on TMR0IE = 1; GIE = 1;
Au temps pour moi en fait tu avais autorisé tes interruptions deux fois (avec INTCON correctement et ensuite avec GIE et PEIE qui eux étaient en commentaire).
Une bonne règle quand ça ne fonctionne pas est de limiter le code à ce que l'on veut cibler en priorité.
Je te suggère donc de te cantonner à Timer0 et son usage.
Par exemple tu fais clignoter une simple led à une fréquence visible genre 5Hz ou 10Hz.
Une fois que ça fonctionne il est plus facile de régler à la tempo que tu souhaites et surtout tu auras bien compris comment déclencher le processus de temporisation sous interruption.
Tu as à priori choisis l'oscillateur interne à 8MHz, vérifie que le fusible de config est correctement sélectionné (HFINTOSC)
Je vois qu'avec OPTION_REG tu as déclaré le prescaler à 256.
Je vois aussi que tu ne recharges pas la tempo_antirebonds (que tu as initialement fixé à 40) lorsque elle atteint 0 pour un autre décompte ultérieur.
C'est pour cela que je te conseille vivement de faire un essai du maniement des interruptions et du timer0 avec une simple led pour commencer, que tu vas faire clignoter, c'est la base, ensuite le reste va venir tout seul.
@+
je vais essayé de faire ça à taton, mais là j'avoue être bloqué... :/ je n'arrive pas à rentrer dans l'interruption
rien ne se passe lors de l'appui BP
Salut,
Avant d'aller plus loin dans ton soft commence par simplement mettre en oeuvre le timer0 en faisant clignoter une led dans l'interruption sans action sur un bouton poussoir.
Une fois que cela marche ton interruption est validée et tu peux continuer sur des choses plus compliquées.
Je te recommande pour les interruptions de programmer les bits d'interruptions un par un. C'est beaucoup plus lisible.
Si tu utilises le compilateur XC8 qui a remplacé le compilateur Hitech tu peux utiliser ce genre de syntaxe qui est portable au travers de tous les compilateurs XC :
Ton code d'interruption est incorrect, il faut toujours nettoyer un flag d'interruption sans que cela dépende d'une variable de ton programme...Code:.. INTCONbits.TMR0IF = 0; //nettoyer flag interruption TIMER0 INTCONbits.TMR0IE = 1; //autoriser interruption TIMER0 INTCONbits.PEIE =1; //interruption des périphériques on INTCONbits.GIE =1; //interruption globale on ...
La seul méthode qui fonctionne si tu as une ou plusieurs interruptions actives :
a+Code:if( INTCONbits.T0IE & INTCONbits.T0IF) { INTCONbits.T0IF=0 ... } if (.....)
Ca y'est ça marche ! ^^
ton post m'a bien aidé Risc! Merci à tous les 2 pour votre aide!
Maintenant le principe assimilé, j'aimerai réalisé l'opération suivante, si j'appuie brièvement sur BP1 ok =0 (moteur 1 marche) et si j'appuie plus de 3secondes ok=1 (moteur 1 off, moteur 2 marche)
En modifiant un peu le code j'ai réussi à créer l'appui long, mais le problème c'est que je n'arrive pas à revenir au moteur 1 avec un appui bref, et le second problème c'est qu'une succession d'appui BP est compris comme un appui long...
Si quelqu'un a une idée? Merci encore!
Code:while(1) { (RA1==1)?LATB4=1:LATB4=0; if (BP1) { TMR0=0x00; INTCONbits.TMR0IF=0; tempo_antirebonds=100; ok=0; while(BP1) { flag_tempo_antirebonds = 1; // flag activé pour valider un comptage de temps en interruption while (!fin_tempo_anti_rebonds); // on attend la fin de la tempo traitée en interruption ok=1; flag_tempo_antirebonds = 0; while(BP1); } } if (ok==1) { LATB2=1; LATB3=0; } else { LATB2=0; LATB3=1; } } } void interrupt it_gene(void) // voir la déclaration correcte selon le compilo C { if(INTCONbits.TMR0IF && flag_tempo_antirebonds) { tempo_antirebonds--; // on décompte à chaque débordement de timer0 if(tempo_antirebonds == 0) { fin_tempo_anti_rebonds = 1; // la tempo est terminée //flag_tempo_antirebonds = 0; // on interdit l'interruption } } if( INTCONbits.TMR0IE & INTCONbits.TMR0IF) { INTCONbits.TMR0IF=0; } }
Oui sauf que :
... ne sert à rien du tout, car si TMR0IF = 1 c'est que forcément TMR0IE = 1 .Code:if( INTCONbits.TMR0IE & INTCONbits.TMR0IF) // ne sert à rien du tout !!!!! { INTCONbits.TMR0IF=0; }
Je ne vois pas bien non plus comment avant tu n'avais pas d'erreur de compilation en déclarant TMR0IF ou TMR0IE au lieu de INTCONbits.TMR0IE et INTCONbits.TMR0IF
Oui je m'en suis aperçue après, mais ça m'a permis de voir que l'erreur venait de la syntaxe INTCONbits.
Est-ce que tu saurais pourquoi, lorsque j'appuie brièvement sur BP1, je ne retombe pas dans mon cas de ok=0?
Mon programme me paraissait correct, moche mais correct :/
J'avoue tourner un peu en rond... Heureusement que vous êtes de bons conseils!
Ca dure quelques µs car tu n'entres jamais dans la routine d'interruption puisqu'elle n'est pas correctement initialisée, du coup pas de tempo anti_rebonds, donc pour que ça puisse fonctionner il faut que ton appui soit extrêmement bref ! En fait n'essaie pas c'est impossible.Code:if (BP1) { TMR0=0x00; INTCONbits.TMR0IF=0; tempo_antirebonds=100; ok=0; .....
Tu charges antirebonds à 100, très bien mais tu as oublié que pour entrer dans l'interruption la condition est que:
Tu as bien positionné la première condition, le flag sera à 1 dès le prochain débordement du timer, mais pas la seconde, le flag antirebonds lui reste désespérément à 0...Code:void interrupt it_gene(void) { if(INTCONbits.TMR0IF && flag_tempo_antirebonds) { .....
Donc essaye avec:
Ca devrait coller, lorsque ce sera le cas on verra comment il faut (bien) s'y prendre, plus proprementCode:if (BP1) { TMR0=0x00; tempo_antirebonds=100; // on charge le temps désiré INTCONbits.TMR0IF=0; // on efface le flag de débordement du timer0 flag_tempo_antirebonds = 1; // on valide le flag tempo ok=0; while(BP1) { ....