Aller au contenu


Information tutoriel

  • Ajouté le: oct. 13 2009 07:17
  • Date Updated: janv. 25 2015 08:32
  • Lectures: 91062
 


* * * * *
4 Notes

Programmation d'un pic sous MicroC

Posté par Harry on oct. 13 2009 07:17
Introduction


Bonjour,

Ce cours a pour but de vous apprendre à programmer ce qu'on appelle un microcontrolleur :heu: ... Non ! Ne partez pas ! Je vous assure que c'est utile et accessible à tous ! Mais ce n'est pas simple, je le conçois ... Je vais faire en sorte que ça passe en douceur.

Image IPBCe cours nécessite de savoir programmer en C...

 

Une présentation des pics et de l'environnement de développement


Je vais commencer par décrire ce qu'est un pic : c'est un micro contrôleur qui intègre un processeur. Voilà, c'est fait et personne n'a rien compris. Donc on va décrire plus simplement... en disant à quoi ça ressemble et à quoi ça peut servir.

A quoi ça ressemble un pic ?

Un pic est un parallélépipède noir avec des "pattes" métalliques :

Image IPB

Mais, à quoi ça sert ce truc ?!?

Ce type de pic sert à gérer à peu près tout et n'importe quoi en robotique, grâce au processeur qui est intégré dedans : votre PC est rempli de ces processeurs et les pics les plus polyvalents actuellement (Février 2008) sont les pics dont la référence commence par 18F*****. En gros, grâce à ça, vous allez pouvoir gérer les contacteurs, les capteurs de distances, les moteurs, vos lumières... bref tout ce qui fait joli dans un robot Image IPB

Où puis-je m'en procurer ?


Vous pouvez vous en procurer à deux endroits :
- Tout magasin d'électronique qui se respecte devrait pouvoir vous en vendre certaines catégories pour environ une quinzaine d'euros chaque...
- Sinon, si vous avez un mail "étudiant" (j'entends par là, autre que Yahoo et Hotmail...), vous pouvez recevoir 2 échantillons gratuit par mois sur le site de microchip.


Image IPBBon, maintenant que j'ai mon pic, ... je fais comment pour le programmer ?

Image IPBCette question a une réponse simple : il vous faut un programmateur de pic qui permet de relier le pic au PC, et c'est ce qui est expliqué juste après.

La carte de développement

Le programmateur de pic - ou carte de dév (développement) - est un élément essentiel pour "FLASHER" votre pic : en gros cela consiste à charger votre programme (compilé grâce à un logiciel dont vous aurez tous les secrets plus tards Image IPB ) sur votre pic, et ce, grâce à un câble qui relie le PC au pic.

Différents programmateur

Il existe différentes carte de dév... certaines que vous pouvez faire vous-même, d'autres que vous pouvez acheter à divers endroits (en particulier sur le net ?

Où puis-je me procurer un schéma si je veux le faire moi-même ?

Voici un site qui donne un schéma d'un programmateur, mais je ne sais pas du tout ce qu'il vaut...

Où puis-je en acheter un tout prêt plutôt que de m'embêter à le faire moi-même ?

Pour ça, je vous conseille de préparer votre porte-feuille... certains ne coûtent effectivement pas cher, mais ils n'ont pas les del rouges, très utiles, surtout au début, pour voir en "live" si votre programme fonctionne, avec des boutons poussoirs qui permettent de tester la réactivité de vos programmes...

Voici le mien :

Image IPB

J'utilise personnellement l'EasyPic5 de MikroElectronika (hé oui, c'est en anglais... mais ce dont vous avez besoin se trouve dans la section "Developpement Tool" en haut) et après, il faut que votre programmateur de pic puisse utiliser les pics que vous aurez commandés chez microchip... l'EasyPic5 a l'avantage de justement pouvoir programmer tous les PIN-40 (c'est-à-dire tous les pic ayant 40 pattes : les 16F, et les 18F entre autres), ainsi que tous les autres pics de forme rectangulaire.

Sinon vous pourrez aussi en trouver sur eBay mais bon, là aussi, il faut faire attention à ce que vous faites...

A vous de choisir la solution qui vous convient. Sachez que les pics de forme rectangulaire sont plus faciles à manipuler que ceux à forme carré (avis personnel).

Euh, ça coûte trop cher je trouve... je peux essayer de juste programmer, sans le tester sur mes pics ?

Oui, bien sûr ! Un simulateur est intégré dans le logiciel que je vais détailler... mais il reste très rudimentaire ! Mais au moins, vous pourrez déjà savoir si la programmation d'un pic peut vous plaire ou non...

Lisez la notice d'utilisation de votre programmateur !

Une fois que vous aurez votre programmateur en main, n'hésitez pas à lire sa documentation, surtout pour le branchement et la mise en marche !

On a le pic, on a (peut-être...) la carte de développement, il nous manque une dernière chose : le logiciel qui va nous permettre de programmer notre pic !

Le logiciel de développement

Alors là, vous avez encore plusieurs possibilités qui s'offrent à vous... Mais bon, je vous conseille d'utiliser le même logiciel que moi si vous voulez suivre ce cours, c'est-à-dire la première des solutions que je vous propose.

La solution MicroC + PicFlash

Si vous avez commandé chez MikroElectronika, normalement un CD vous est fourni. Alors installez les logiciel PicFlash (qui vous permettra de flasher votre pic à partir du PC) et MicroC (qui vous permettra de programmer C... vous avez aussi MicroBASIC, etc...). Ces deux logiciels se trouvent normalement sous le dossier "zip" de la racine du CD. Installez-les.

D'autres logiciels de programmation

Le compilateur SDCC

Vous pourrez le trouver ici

Le programmateur MpLab de microchip

Vous pourrez le trouver ici

D'autres logiciels pour flasher votre pic

Logiciel de programmation des composants IC-Prog

Vous pourrez le trouver ici

J'utilise personnellement le logiciel MicroC avec PICFlash... Toute la suite est basée sur ce logiciel, mais si vous n'avez pas ce logiciel, vous pouvez toujours lire la suite pour apprendre à lire la datasheet, qui sera votre outil indispensable dans le futur pour programmer n'importe quel pic...

 

Première étape : préparer son espace de travail


L'espace de travail

Maintenant que vous avez tous les outils, il faut les préparer. Ceci implique donc 3 étapes.

Branchez votre pic sur la carte de développement

Normalement, la notice d'utilisation de votre carte de développement devrait vous indiquer comment faire. Voici à quoi ça ressemble chez moi :

Image IPB

Branchez votre carte de développement au pc

Là, de la même manière, la notice d'utilisation vous indique comment faire. Chez moi, il suffit de brancher la carte au pc via un câble USB qui permet également d'alimenter la carte en électricité.

Installez vos logiciels de programmation et de compilation

Là aussi, référez-vous à la documentation des logiciels que vous avez choisi (et pour MicroC et PICFlash, je l'ai déjà rapidement décrit).

Une fois que votre espace de travail "physique" est prêt, il faut préparer l'espace "virtuel"...

Documentation du pic

Toute programmation de pic nécessite absolument d'avoir la documentation du pic que l'on est en train de coder. Certes, c'est en anglais, donc rébarbatif, mais ne vous inquiétez pas, si vous suivez mes conseils, cela passera en "douceur".

Repérer la référence du pic que vous avez

Prenons ce pic :

Image IPB

La référence est écrite dessus (je sais, ce n'est pas un 18F... à vous de vous adapter ^^). Dans notre exemple, c'est un 16F877A

Trouver la datasheet

Une datasheet (littéralement « feuille de données ») est un fichier donnant toutes les caractéristiques d'un élément électronique. Il faut aller la chercher sur le site du constructeur.

Allez là et remplissez le champ en haut qui correspond à votre pic (pour moi, c'est donc le 16F877A) :

Image IPB

Image IPB

Cliquez sur la ligne correspondant à la "Sillicon Product", vous devriez obtenir :

Image IPB

Enfin cliquez sur l'icône "pdf" pour télécharger la Datasheet. Voici celle de mon pic, à la page la plus intéressante :

Image IPB

Vous remarquerez que j'ai regroupé les "RAi", "RBi", "RCi", "RDi" et "REi" sous des couleurs différentes. En réalité A, B, C, D et E sont les ports programmables. Les "i" varient (en gros) de 0 à 7 : vous aurez reconnu là la formation d'un octet: chaque RAi est un bit (un chiffre binaire, c'est à dire un 0 ou un 1) de l'octet correspondant au port A.

On est fin prêt pour créer notre premier projet !

Créer un projet

Je vais décrire comment créer un projet proprement sous MicroC... Et désolé pour ceux qui n'utilise pas ce logiciel :|

Fermez les projets qui seraient déjà ouverts

Avant tout, fermez tous les projets en cours (Project --> Close Project) :

Image IPB

Créez un projet sous MicroC

Puis créez votre premier projet (Project --> New Project) :

Image IPB

Ensuite, mettez le nom de votre programme, choisissez l'endroit où vous voudrez l'enregistrer (cliquez sur "choose"), sélectionnez votre PIC dans la liste, mettez le "clock" à 010.000000, et cliquez sur "Default" puis sur OK :

Image IPB

Oh le joli écran noir ! :tare: Non, sérieux, ne vous inquiétez pas, c'est normal ^^

Et voilà ! On peut ENFIN commencer à coder en tant que tel Image IPB




Deuxième étape : votre premier code


Les règles de base

Pour vous aider à faire votre premier code, je vais faire comme suit : d'abord je vais vous donner les règles à respecter, ensuite je vous laisserai vous exercer.

Les 5 commandements tu respecteras

Image IPBA partir de maintenant, voici les règles à respecter quoi qu'il en soit :
  • Les instructions en minuscules sont propres au C
  • Les instructions en MAJUSCULES sont propres aux micro contrôleurs
  • "0b" (zero Image IPB indique que la suite est écrite en binaire (0 ou 1)
  • un nombre écrit tel quel indique qu'il est écrit en décimal (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
  • "0x" (zero x) indique que la suite est écrite en héxadécimal (0, 1, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E et F... pas très utile)
Quelques instructions

A partir de là, j'ai décidé de travailler sur le port B. Voici les instructions de base à connaître et à utiliser à bon escient (le code suivant ne sert qu'à vous donner des définitions):

TRISB

L'attribution de TRISB permet de configurer le port B en entrée ou en sortie (ou à moitié en entrée et à moitié en sortie...)

TRISB = 0; //Le port B est configuré en mode sortie (le pic envoie des ordres à un système extérieur via ce port, par exemple à un moteur)

TRISB = 1; //Le port B est configuré en mode entrée (le pic reçoit des informations d'un système extérieur via ce port : capteur, autre pic, etc...)

Imaginons qu'on ait besoin que de 4 bits sur les 8 disponibles pour recevoir une information, et qu'on ait besoin que de 4 bits pour envoyer des données ; au lieu de «gâcher» 2 ports (1 en entrée, 1 en sortie), on peut utiliser la moitié du port B en entrée et l'autre moitié en sortie : il est alors plus lisible d'écrire la valeur en binaire :
TRISB = 0b11110000; //Les pattes 7, 6, 5 et 4 du port B sont configurées en mode entrée (0b11110000) et les pattes 3, 2, 1 et 0 sont configurées en mode sortie (0b11110000)

Rem : Au dessus, au lieu d'écrire TRISB = 0 on pouvait donc écrire TRISB = 0b00000000.

PORTB

Image IPBImaginons qu'on ait configuré le port B en sortie, comment affecter une valeur à ce port ? (valeur qui sera interprété par exemple par le moteur d'une roue : avancer, reculer, vitesse…)

Il faut attribuer une valeur à PORTB:
PORTB = 0b01111111; //La patte 7 du port B prend la valeur 0 (une DEL qui s'éteint...) alors que les pattes 6, 5, 4, 3, 2, 1 et 0 prennent la valeur 1 (des DEL qui s'allument...)

Bien sûr, si on écrit PORTB = 1; tous les bits du port B prennent la valeur 1; et si on écrit PORTB = 0; tous les bits du port B prennent la valeur 0.

Image IPBEt physiquement, qu'est-ce qui se passe ?

Physiquement, si un bit d'un port est sur 1, il envoie une tension seuil 5 Volts à la patte correspondante (voir alors la Datasheet) et s'il est sur 0, il envoie du 0 Volt ; logiquement vous avez branché un fil, imaginons que ce fil soit relié à un moteur, ce moteur modifiera son comportement selon qu'il reçoit du 5 Volts ou du 0 Volt.

Image IPBOui, d'accord, mais moi, j'ai configuré la moitié de mon port en entrée et l'autre moitié en sortie, et bien sûr il ne faut pas modifier les valeurs d'entrées, comment envoyer quelque chose en sortie proprement ?

Il faut alors configurer chaque bit de sortie un par un. Pour accéder à un bit précisément, il faut utiliser : PORTB.Fnumbit
Exemple :
PORTB.F0 = 0; //Attribue 0 au bit 0 du port B

Image IPBEt si mes ports sont en entrée ? Comment je fais pour savoir ce que j'ai reçu ?

Bien évidemment, si le port B est en entrée, on ne va pas attribuer des valeurs aux bits de ce port (risque de conflits), mais lire les valeurs qu'il a pris. On utilise alors des tests logiques.
Ex :
Code : C

 
if (PORTB.F0==1) //si je lis 1 sur le bit 0 du port B
{
PORTC.F0=0; // alors, j'envoie 0 sur le bit 1 du port C (par ex, je demande au moteur de freiner (très vulgarisé))
}
else //sinon, si je lis 0 sur le bit 0 du port B
{
PORTC.F0=1; // alors, j'envoie 0 sur le bit 1 du port C (par ex, je demande au moteur d'accélérer (très vulgarisé))
}
DELAY_MS

DELAY_MS(1000); //Fait une pause de 1000ms = 1s - ATTENTION A BIEN CRÉER LE PROJET COMME J'AI DIT (en particulier pour la valeur du timer à 100)

L'opérateur ~

PORTB = ~PORTB; //Inverse la valeur de chaque bit de PORTB (0 --> 1 et 1 --> 0) exemple : 01100011 --> 10011100 (le "~" se fait en faisant "Alt Gr + 2" puis "espace" sous azerty)

Ces codes peuvent être utilisés n'importe où dans le programme.

Certains conseils tu suivras

Maintenant, pour alléger votre code, vous pouvez utiliser des define, comme en C, à mettre avant le main :

#define sortie PORTB //A mettre avant le main... Il faudra mettre "sortie = 0;" dans le main pour avoir effectivement PORTB en sortie

Il y a quelque chose de remarquable avec MicroC... Vous pouvez non seulement créer des variables dans le main... mais aussi en dehors de n'importa laquelle de vos accolades !!! C'est pourquoi je vous conseille fortement de déclarer toutes vos variables en "globales", au début de vos programmes de pic.

Des exercices tu feras

Bon, c'est pas tout ça, mais vous ne bossez pas beaucoup... Allez, à vous de coder ! Un sujet ? Ok, pas de problème, voici une question à laquelle vous allez répondre :

Image IPBComment faire clignoter toutes les DEL du plateau alors ?

Image IPBRéponse possible :

Code : C
 
#define sortie TRISB
void main (void)// N'OUBLIEZ PAS LE SECOND "VOID" !!!
{
sortie = 0;
PORTB = 0;
while(1)
{
delay_ms(1000);
PORTB = ~PORTB;
}
}
Image IPBMais on fait comment pour que les dels clignotent ? Parce que le programme il est joli, mais je veux que les leds clignotent, moi !!

Image IPBAlors, déjà, il faut que vous ayez connecté votre pic à votre pc, qu'il soit allumé (moi j'ai un bouton on/off) et que votre pc le reconnaisse. Ensuite, une fois votre programme écrit, faites "Ctrl + F11" pour compiler ET flasher le pic. Si vous ne voulez que le compiler, faites "Ctrl + F5" et juste pour le flasher, faites "F11".

Sinon, vous pouvez toujours simuler le projet, et c'est le thème de la partie suivante.

Le simulateur

Avant de tester directement votre programme sur le pic, vous pouvez aussi le simuler sur votre PC... et c'est d'ailleurs la seule méthode qu'ont ceux qui n'ont pas de kit de développement pour vérifier si leur programme pourrait marcher...

Le simulateur de MicroC

Pour utiliser ce simulateur, sélectionnez d'abord votre simulateur. Ici allez dans "Debugger --> Select Debugger --> Software Pic Simulator" :

Image IPB

Puis cliquez sur "Run --> Start Debugger". Vous arrivez sur cette page :

Image IPB

Vous avez plusieurs boutons. Dans l'ordre :
Image IPBStart Debugger (F9) : permet de placer le curseur au début de votre programme
Image IPB Run/Pause Debugger (F6) : permet de remettre en marche ou de mettre en pause votre programme
Image IPB Stop Debugger (Ctrl + F2) : permet d'arrêter votre programme
Image IPBStep Over (F8) : permet de passer à l'étape suivante de votre programme. Ce bouton est essentiel pour voir évoluer votre programme (mais d'abord, il faut rajouter vos variables, ce que nous allons faire avec un autre bouton plus loin)
Image IPB Step Out (Ctrl + F8) : permet d'exécuter votre programme en entier
Image IPB Run To Cursor (F4) : permet d'exécuter votre programme jusqu'à l'endroit où vous aviez placé le curseur
Image IPB Step Into (F7) : euh... à tester, je ne sais pas
Image IPB Jump To High Priority Interrupt (F2) : permet d'aller à votre interruption principale (j'expliquerai plus tard ce que sont les interruptions)

Puis, les boutons qui vous permettent de placer et d'éditer vos variables dans la fenêtre d'état du dessous :
Image IPB Permet d'ajouter une variable particulière dans la liste de variables à "simuler", après l'avoir sélectionnée dans le menu déroulant juste en dessous
Image IPB Permet de supprimer une variable de simulation particulière que vous avez sélectionné dans la liste
Image IPB Permet de rentrer dans les propriétés d'une variable particulière que vous avez sélectionné dans la liste pour en changer sa valeur en temps réel par exemple (vous pouvez aussi double-cliquer sur la variable pour avoir ces propriétés aussi)
Image IPBPermet d'ajouter toutes les variables dans la liste de simulation
Image IPB Permet de supprimer toutes les variables de la liste de simulation

Pour votre première simulation (l'exemple écrit dans le premier paragraphe), je vous conseille pour ne pas vous embêter de cliquer sur Add All, puis d'appuyer une seule fois sur "F9" (ou cliquez sur Start Debugger). Puis pour voir votre programme avancer, appuyer sur "F8" (ou cliquez sur "Step Over") à plusieurs reprises. Vous allez ainsi pouvoir voir votre curseur se déplacer dans votre fenêtre de code, et voir l'état des variables changer.

<1> Au départ (F9), votre curseur se place sur "sortie = 0;". (je vous rappelle que sortie est une variable se référant au TRISB et que la valeur qui lui est affectée - 0 - permet de configurer tout le port B en sortie).

Image IPB


Pour pouvoir exécuter la ligne sélectionnée, appuyez une fois sur (F8). La valeur n'est donc pas modifié puisque de base les pics sont configurés en sortie donc la ligne correspondant à TRISB reste à 0 (dans la colonne "Value").


<2> Ensuite, votre curseur est placé sur "PORTB = 0;".

Image IPB

De même, appuyez sur (F8) pour exécuter cette ligne et la valeur du port B ne change pas puisque de base il vaut 0.

<3> Ensuite, votre curseur est placé sur "delay_ms(1000);". Remarquez en bas au milieu de la fenêtre que la valeur du temps qui s'est écoulé est : "Time = 2.00 Us" (deux micro-secondes).

Image IPB

Ainsi, en appuyant sur (F8), vous exécutez cette ligne et du coup on obtient : "Timer = 1003.39 Us"... Mais d'où sort ce 1.39 Us de trop ?!? Rhhaa là-là, sachez que le pic prend du temps pour traiter les ordres que vous lui donnez, et ça, microC les simule aussi ^^

<4>Donc votre curseur est maintenant sur la ligne : "PORTB = ~PORTB;" :

Image IPB

Appuyez maintenant sur (F8) : la valeur de PORTB passe à 255 d'un seul coup (!!!) :

Image IPB

Image IPBMais pourquoi ça fait ça ?

Image IPBJe vous rappelle que le tild "~" permet de changer la valeur de TOUTES les pattes du pic. Donc tous les 0 passent à 1 et réciproquement. Ici PORTB=0 au départ. Donc on a bien zéro. Mais les valeurs affichées sont en décimal, et non en binaire ! Donc ça n'affiche pas 11111111, mais sa traduction en décimal, c'est à dire... 255 ! Mais si vous voulez avoir sa valeur en binaire, double cliquez sur la variable et sélectionnez "décimal" ^^

Voilà, maintenant, vous avez compris la simulation d'un projet ! Vous n'avez plus qu'à appliquer cette méthode quand vous voulez !

C'est intéressant tout ça, mais... je ne suis pas sûr que vous compreniez ce que vous faites... d'ailleurs si vous n'avez pas utilisé exactement les mêmes données que moi, ça NE MARCHE PAS, et j'ai envie de dire que... c'est normal. Mais ne vous inquiétez pas ! Il suffit juste d'adapter votre code à VOTRE pic. Mais pour cela, il faut que vous arrivez jusqu'à la partie "La structure d'une datasheet" en me faisant confiance jusque là... Pour l'instant, je vais juste vous prouver que tous les codes que vous avez utilisé se trouvent dans la datasheet, et c'est l'objet de la prochaine partie.

Explications

Voici quelques explications intéressantes qui vont vous permettre de faire une petite pause...

Un peu de vocabulaire sur ce qu'on vient de faire

On a utilisé plein de codes propres au pic. Ces codes se trouvent dans la datasheet (je rappelle qu'une datasheet est un fichier qui décrit votre composant, et que vous avez téléchargé...).

Ces codes sont reconnus sous la dénomination de "registre" ("register" en anglais). Ils sont reconnus par le pic, et donc par tous les logiciels de programmation de pic (normalement...). Voici à quoi ça ressemble chez moi :

Image IPB

Pour trouver cette page chez vous, faites une recherche de mot ("Ctrl + f"), et tapez "register file map". Appuyez sur entrée et vérifiez bien que vous êtes sur la page correspondant à votre pic. Pour moi, il y a marqué, au centre en haut : PIC16F876A/877A (seul ce qu'il y a marqué en gras m'intéresse). Il y a marqué aussi, en haut à droite : PIC16F87XA. Le "X" signifie que n'importe quel nombre peut-être mis à cette place.

En cherchant bien dans ce tableau, vous remarquerez que vous connaissez déjà PORTA, PORTB, PORTC, PORTD, PORTE (au début de la première colonne) et TRISA, TRISB, TRISC, TRISD, TRISE (deuxième colonne). Et pour l'instant, c'est tout !

Mais, je ne vois pas delay_ms !

L'autre code que je vous ai dit n'est pas propre au pic, (delay_ms) mais au logiciel microC.

Pour le retrouver, revenez sur microC et allez dans l'onglet Qhelp à gauche de la fenêtre (si vous n'avez pas ces onglets, allez dans "View --> Code explorer") :

Image IPB

Si vous êtes arrivé jusqu'ici en me faisant confiance, bravo ! Si vous êtes arrivé jusqu'ici en vous entraînant ne serait-ce qu'avec le pic que j'utilise, et le simulateur, c'est mieux ! L'idéal étant bien évidemment ceux qui ont un kit de développement qui marche avec le pic que j'utilise pour mes explications... Maintenant, faites une pause, parce que ce qui suit risque d'en décourager plus d'un... seulement c'est la partie suivante qui vous rendra définitivement indépendant dans ce monde impitoyable des pic




Troisième étape : les interruptions et... la datasheet


Les interruptions

Alors nous allons maintenant nous attaquer à un gros morceau de l'utilisation du pic : les interruptions !

Sous ce nom pas si barbare que ça se cache une notion SIMPLE.

En fait, votre robot va évoluer en fonction de ce qu'il se passe autour de lui. L'exemple le plus simple est si jamais il rencontre un obstacle : pour détecter un contact avec l'extérieur, vous pouvez placer des contacteurs, ou encore appelés "Microrupteurs". En réalité, c'est juste une lame qui lorsque on appuie dessus fait passer le courant par une broche, sinon il passe par une autre.

Dès que le courant passera par l'une de ces broches, le pic va l'interpréter comme un "1", et le programme s'arrêtera : d'où le nom d'interruption. En réalité, pendant cette interruption, il effectuera certaines tâches qui sont prévues pour cette interruption (par exemple un robot adverse qui vient nous pousser Grrrr....)

Suivez bien ce qui va suivre : ça va vous permettre de comprendre entièrement la structure d'une datasheet ! Et si vous comprenez entièrement une datasheet, vous n'avez plus besoin de ce tutoriel Image IPB.

Image IPBLe travail qui suit, est vraiment difficile... Faites le à tête reposée, en étant motivé pour faire cette partie et la suivante d'un trait, c'est le meilleur pour votre compréhension finale.

Nous allons commencer par repérer la page qui va nous intéresser dans la datasheet pour gérer les interruptions dans le PORTB :

Image IPB

Pour trouver cette page, j'ai lancé une recherche (Ctrl + f) et j'ai lancé la recherche pour "interrupt" jusqu'à arriver à une page ayant la structure précédente : les deux encadrés rouges permettent de repérer la structure. D'abord le nom du registre décrit sur cette page, puis - sachant qu'un registre est formé de huit bit - la description des huit bit (7 à 0) dans l'ordre. Je ne suis pas arrivé sur la page ci-dessus de suite, mais sur une autre qui ne m'intéressait pas. Pour trouver celle du dessus, j'ai regardé dans le texte de description si la page parle des interruptions dans un PORT. Le second que j'ai trouvé concernait le PORT B.

Sur cette page, INTCON est le nom du registre. Ce registre sert (comme c'est marqué en anglais en haut de la page...) à modifier la valeur des bits de type "ENABLE" et "FLAGS" des dépassements du timer0 (dépassements : en gros la valeur du timer0 a dépassé une valeur limite définie par défaut, et c'est ce qui est considérée comme interruptions pour le timer0... bon de toutes façons, on reverra la gestion du temps plus tard) ; ce registre sert aussi à modifier les valeurs des bits de type "ENABLE" et "FLAGS" des interruptions (provenant de l'extérieur) au niveau du PORTB du pic(et ça, ça nous intéresse au plus haut point ^^)

=> Les bits de type "ENABLE" permet d'AUTORISER la réalisation de certaines actions. Ici on cherche à autoriser les interruptions dans le PORTB. Cherchez à quel bit il correspond et notez-le (notez les tous s'il y en a plusieurs : réponse plus loin).

=> Les bits de type "FLAG" qui permettent de SAVOIR S'IL Y A EU UN CHANGEMENT QUELCONQUE DANS TOUT LE PORT. Ici, on va vouloir savoir si le PORTB a changé d'état ou non. Cherchez le ou les bits qui permettent de savoir si le PORTB a changé d'état ou non.

Solution dans le chapitre suivant...

La structure d'une datasheet

Voici la réponse aux recherches effectuées dans le précédent chapitre...
La page sur laquelle vous êtes arrivés est en fait accessible via le plan de la datasheet qui est affichée à gauche (ici, on regarde les interruptions : donc cherchez un chapitre qui parle d'interruption et cliquez dessus pour revenir sur une page comme celle ci-dessus. Si vous ne tombez pas sur la même page, cherchez dans les pages suivantes)

Une fois que vous avez vu que c'est accessible via le menu de gauche, vous remarquez les différents autres chapitres et sous chapitres qui existent. Essayez de comprendre un peu leur structure, et lisez rapidement leurs textes descriptifs pour savoir de quoi ils parlent. Vous aurez ainsi un aperçu de ce que vous pouvez faire avec votre pic.

J'ai parlé de bits de type "ENABLE" et "FLAGS". Sachez que les bits ENABLE doivent être mis à 1 pour pouvoir utiliser les fonctions qui leurs correspondent (et qui sont décris dans le texte descriptif en anglais, ainsi que sur le schéma de votre pic - qui se trouve au tout début, si vous vous rappelez bien). Les bits "FLAGS" permettent de connaître l'état de certaines pin ou bit d'un ou de plusieurs registres de votre pic. En gros, cela permet de savoir qu'est-ce qui a changé.

Il faut donc que vous réinitialisiez vos bits "ENABLE" et "FLAGS" après chaque changement !

Maintenant, vous pouvez travailler un peu plus tout seul !




D'autres outils du pic


Les timers

Je manque de temps pour terminer ce tutoriel. Je vais donner des axes d'études pour que vous puissiez continuer un peu seul. Voici la première aide pour utiliser les timers...
Enfin, pour travailler avec les interruptions, il faut que vous utilisiez la structure suivante, en dehors du main :

Code : C

void interrupt(void)
{
// votre code qui s'effectuera lors d'une interruption
}


Mettez le moins de choses possible dans la structure "interrupt". Elle ne doit vous permettre que :
  • de savoir si quelque chose a changé au niveau des entrées
  • d'enregistrer ces changements dans une variable globale (qui est donc définie au tout début du programme, et en dehors du main, via la commande :
Code : C

double ma_variable ma_valeur;


* et de réinitialiser vos registres "ENABLE" (que vous utilisez) à 1 et "FLAGS" à 0

Il ne faut surtout pas faire de calcul ou de traitement complexe (if for etc...) dans une interruption, sinon ça va "ramer" et ça risque surtout de planter.

Dans "Interrupt", il ne faut pas non plus utiliser de fonctions que vous utilisez aussi dans le main ! Cela est perçu comme une "redondance". En effet, imaginez que vous essayez d'utiliser la fonction cos dans le main, et que pendant que le pic fait le calcul, il y a une interruption... et que pendant cette interruption, vous essayez aussi de faire la fonction cos... eh bien, sachant que la fonction est programmée à "un seul endroit", vos variables utilisées dans l"interrupt" vont ecraser celles du main... du coup, plantage.

Pensez à aller voir la datasheet et google pour compléter vos connaissances sur le timer !

Se répérer dans un plan

Pour vous repérer dans un plan, vous devrez mettre des capteurs au niveau de vos roues, et ces capteurs peuvent être des encodeurs optiques ou "roues codeuses"...

Si vous avez compris tout ce qui précède, déjà, vous pouvez vous débrouiller - avec un peu de logique et de recherche - pour utiliser
* des contacteurs (des interrupteurs)
* des roues codeuses... en fait, le signal d'UNE SEULE roue codeuse est composée de deux bits en sortie (des interrupteurs qui sont activés puis désactivés) qui peuvent chacun avoir deux valeurs. Seulement, leur séquence est bien définie :

110011001100 : --__--__--__

011001100110 : _--__--__--_

A gauche, c'est la description de leurs états en séquence de 1 et de 0, et à droite, un "semblant de chronographe" qui leur correspond. Vous pouvez remarquer que leurs signaux sont identiques, à ceci près qu'ils sont décalés d'1/4 de période. Cela permet de savoir dans quel SENS la roue tourne ! en effet, si vous "lisez" la séquence dans le sens inverse, le signal n'est pas le même ! Il faut pouvoir interpréter cela sur un pic, grâce aux interruptions qui se déclenchent sur les front montants de l'un des bits seulement. Pour plus de détails sur les roues codeuses, voici la définition que j'ai rédigée sur le dicobot concernant les roues codeuses :

Ce composant est un capteur qui envoie des impulsions au fur et à mesure que son axe tourne. En clair, il peut-être utilisé comme capteur d'angle, indispensable si on veut savoir précisément où son robot se trouve.

Le signal envoyé peut avoir un codage dit "GRAY" ou alors en "QUADRATURE DE PHASE".
Ces roues codeuses possèdent deux fils d'alimentation (5V et la masse en général), plus d'autres fils qui dépendent du type de codage... Dans chaque cas, le codage représente le signal envoyé au fur et à mesure que l'axe tourne (chaque ligne correspond à un angle différent sur la roue codeuse), sur chaque fil (chaque colonne correspond à un fil différent sur la roue codeuse) : le 1 correspond au 5V utilisé par un pic par exemple, ou le 24V utilisé pour certaines certaines cartes d'acquisitions, et le 0 représente le 0V.

Roue codeuse à codage GRAY :

Ces roues codeuses possèdent plusieurs autres fils (au moins 3 de plus). Je vais détailler le signal envoyé par des roues codeuses 4 bits (donc avec 4 fils de plus, soit 6 fils au total) sur deux colonnes (lire chaque ligne de la colonne de gauche de haut en bas, puis celle de droite) :
0000|----|1100
0001|----|1101
0011|----|1111
0010|----|1110
0110|----|1010
0111|----|1011
0101|----|1001
0100|----|1000

Le signal ainsi envoyé se répète en recommençant à la première ligne une fois que la roue a fait un tour complet. On peut donc connaître facilement à tout instant l'angle actuel de la roue.

Avantage : angle facile à obtenir
Inconvénient : il y a beaucoup de fil, ce qui limite l'utilisation du pic, et ce genre de codeur coûte plus cher que celles à codage en quadrature de phase

Roue codeuse à codage en QUADRATURE DE PHASE

Ces roues codeuses possèdent deux autres fils. Voici un schéma du code reçu (signal en quadrature de phase) au cours du temps :

Image IPB


On remarque que le signal est très simple, et qu'il se répète indéfiniment. Mais attention cependant, une période de ce signal ne correspond pas à un tour complet, mais à seulement à 1/n ème de tour de la roue ! Plus "n" est grand, plus la roue codeuse est précise !

Vous pouvez remarquer que les deux signaux sont identiques, à ceci près qu'ils sont décalés d'1/4 de période. Cela permet de savoir dans quel SENS la roue tourne ! En effet, si vous "lisez" la séquence dans le sens inverse, le signal n'est pas le même !

Avantage : seuls deux fils sort de cette roue qui coûte moins cher qu'une roue à codage gray

Inconvénient : si vous prenez une roue trop précise, et que votre axe tourne trop vite... la fréquence d'envoi d'une période risque d'être trop importante pour un pic... Mais en gros, une précision de n = 50 pas par tour est facilement utilisable. De plus, ce n'est pas un codage absolu en angle ! En effet, le code se répète tous les 1/n tours... en fait, vous allez pouvoir connaître de combien a tourné votre axe par rapport à sa position antérieure.

Image IPBComment le codage est réalisé dans ces roues ?

C'est tout simple : un disque avec des trous, puis un laser et un capteur de lumière de l'autre côté du disque et le tour est joué : c'est ce capteur de lumière qui envoie "1" lorsque la lumière du laser traverse le trou et "0" lorsque la lumière est arrêté par le disque.

ATTENTION : la description que j'ai donnée pour les roues codeuses correspond à une description de roues codeuses avec deux signaux en codage binaire en "quadrature de phase" - comme on dit dans le jargon. Il existe d'autres types de roues codeuses, avec plus de bits, et dont le codage est dit "GRAY". Il en existe d'autres...

ATTENTION 2 : le signal des roues codeuses mécaniques est particulièrement merdique... Il faudra donc penser à utiliser des condensateurs pour affiner la courbe que vous pourrez obtenir avec ces roues lorsqu'elles tourneront, voire même utiliser un montage d'hystérésis pour ne prendre que les fronts montants et descendants aux valeurs que vous définirez pour obtenir des signaux carrés vraiment "jolis" et utilisables par un pic

* des moteurs à courant continu

* des moteurs pas à pas

Je donne quelques explications sur l'utilisation de ces deux moteurs dans les deux derniers chapitres.
Vous pourrez trouver plein d'autres capteurs que les roues codeuses pour vous repérer... Des pistes seront données en conclusion finale.

PWM : contrôle moteurs

PWM = Pulse Width Modulation ou Signal Modulé en Fréquence... C'est grâce à cette fonction du PIC que vous pourrez contrôler la vitesse d'un moteur à courant continu par exemple !
PWM = Pulse Width Modulation...

Bon en gros c'est la manière de fournir le courant continu au moteur à courant continu... En réalité, si on envoie une tension et un courant plus ou moins puissant dans le moteur, le moteur va logiquement plus ou moins vite. Du coup, comme c'est difficile d'envoyer de tels signaux, on utilise des composants qui font ça à notre place, et ces composants nécessitent un signal dit "carré"...

Signal carré

Ce signal possède deux état : un dit "HAUT" et l'autre dit "BAS". On dit aussi état 1 ou 0 (1 pour la tension maximale et 0 pour 0V). Ce que fait le composant dont je vous ai parlé, c'est de transformer ce signal en un signal "moyen". Si la moitié du temps il a du 5V et l'autre moitié il a du 0V, il enverra alors une tension moyenne de 2,5V... Si par contre 80% du temps il a 5V et les 20% restants il a 0, il sortira du 4V moyen... Vous vous apperevrez alors que votre moteur ira plus vite !

Le pourcentage représentant la fréquence où la tension est à l'état haut est appelé "Rapport cyclique" et comporte généralement la lettre "alpha".

Vous pouvez essayer d'utiliser des moteurs à courant continu (en utilisant un signal PWM) en passant par un circuit intermédiaire qui va transformer le rapport cyclique de votre PWM en tension continue à puissance nominale (je vous conseille les LM621).

Voici un code que j'ai écris et qui fonctionne (à condition de faire le montage qui correspond...) :

Un robot avec deux roues motrices à courant continu, contrôlés à vitesse maximale ou nulle ou négative via des interrupteurs à 3 positions (la mise en marche d'une courroie et d'une porte à l'arrière du robot étaient aussi commandés via deux autres interrupteurs)

Code : C
 
// --------------------------------------------
// Liste des ports utilisés pour gérer le robot
// --------------------------------------------

// Vitesse du moteur de la roue Gauche (VG) et Vitesse du moteur de la roue Droite (VD) [VITESSE ==> FREQUENCE] <=> à gérer avec le PWM et la fréquence d'envoi des données
#define VG CCPR1L // 1 bit
#define VD CCPR2L // 1 bit
#define SENSG1 PORTC.F3 // 1 bit : 1 si vers l'avant 0 vers l'arrière sauf si SENSG1 = SENSG2 ==> STOP
#define SENSG2 PORTC.F0 // 1 bit : 1 si vers l'arrière 0 vers l'avant sauf si SENSG1 = SENSG2 ==> STOP
#define SENSD1 PORTD.F0 // 1 bit : 1 si vers l'avant 0 vers l'arrière sauf si SENSG1 = SENSG2 ==> STOP
#define SENSD2 PORTD.F1 // 1 bit : 1 si vers l'arrière 0 vers l'avant sauf si SENSG1 = SENSG2 ==> STOP
// Télécommande : ordonne l'avancée et le recul des roues gauche et droite
#define ARG PORTD.F6
#define RRG PORTD.F7
#define ARD PORTD.F4
#define RRD PORTD.F5

// -------------------------
// Définition des constantes
// -------------------------
double PI = 3.14159265;
double VGMAX = 30;
double VDMAX = 30;
// double K = 0.001396; // = 2 * PI * 80mm / ( 15 * 24 ) CONSTANTE de réduction roue codeuse

// --------------------------
// Définition des variables :
// --------------------------
double t;

//==============================================================================
//==============================================================================
//==============================================================================

// Fonction qui permet de gérer le temps
// Nécessite :
void Temp(void)
{
if (INTCON.F2) // Gestion du temps : [0 ==> 100000] temppetit ==> x100000 ==> [0 ==> 100000] tempmoyen ==> x100000 ==> [0 ==> taille(double)] tempgros
{
t = t + 1;
TMR0L = 0;
}
}

//==============================================================================

// Fonction qui permet de gérer les interruptions
// Nécessite :
void interrupt(void)
{
Temp();
INTCON = 0b10100000;
}

//==============================================================================
//==============================================================================
//==============================================================================

// ===================
// Programme principal
// ===================

void main(void)
{
// -----------------------------
// Liste des variables utilisées
// -----------------------------

// ---------------------------------------------------------------------
// Définition des ports pour les interruptions sur le PORTB et le timer0
// ---------------------------------------------------------------------
T0CON = 0b10000100; // Utiliser le TMR0 en 16 bits et prescaler de TMR0 initialisé à 1/16
TMR0L = 0;
//TMR0L = 0b00011110; // Les interruptions s'effectueront toutes les : 1 s (si on est sur 16 bits)
//TMR0H = 0b00000000; // Uniquement sur 16 bits
INTCON = 0b10100000; // Autoriser les interruptions, celles de TMRO
ADCON1 = 0b00001111; // Utiliser les 4 premiers bits du port B en mode analogic [= analogique en anglais] uniquement (et non pas en digital = numérique en anglais)

// ---------------------------------------------------------------------
// Configuration du PWM à 4 kHz (hmmm plus en fait) Vitesse maximale 125
// ---------------------------------------------------------------------
PR2 = 0b00111111 ;
T2CON = 0b00000101 ;
CCP1CON = 0b00001100 ;
CCP2CON = 0b00111100 ;

// ---------------------
// Initialisation du pic
// ---------------------
TRISC = 0; // sortie
TRISD = 0b11110000; // 4 en sortie et 4 en entrée
PORTC = 0;
PORTD = 0;
VG = 0;
VD = 0;

// -----------------
// Boucle principale
// -----------------

while(1)
{
if (ARG)
{
VG = VGMAX; SENSG1 = 1; SENSG2 = 0;
if (ARD)
{
VD = VDMAX; SENSD1 = 1; SENSD2 = 0;
}
else if (RRD)
{
VD = VDMAX/2; SENSD1 = 0; SENSD2 = 1;
}
else
{
VD = 0; SENSD1 = 0; SENSD2 = 0;
}
}
else if (RRG)
{
VG = VGMAX/2; SENSG1 = 0; SENSG2 = 1;
if (ARD)
{
VD = VDMAX; SENSD1 = 1; SENSD2 = 0;
}
else if (RRD)
{
VD = VDMAX/2; SENSD1 = 0; SENSD2 = 1;
}
else
{
VD = 0; SENSD1 = 0; SENSD2 = 0;
}
}
else
{
VG = 0; SENSG1 = 0; SENSG2 = 0;
if (ARD)
{
VD = VDMAX; SENSD1 = 1; SENSD2 = 0;
}
else if (RRD)
{
VD = VDMAX/2; SENSD1 = 0; SENSD2 = 1;
}
else
{
VD = 0; SENSD1 = 0; SENSD2 = 0;
}
}
}
}

Pour ce dernier robot, j'ai fait aussi le schéma électrique

Avec votre pic, vous devriez pouvoir créer un ou plusieurs signaux PWM... renseignez vous avec la datasheet !

Moteurs pas à pas

Voici un exemple de code de contrôle d'un moteur pas à pas. Vous trouverez une explication sur certains moteurs ici.
Moteur pas à pas qui tourne en même temps que tourne une roue codeuse :

Code : C
 
// --------------------------------------------
// Liste des ports utilisés pour gérer le robot
// --------------------------------------------
// CONTacteurs
#define CONT PORTB.F2
// Roues codeuses gauche et droite
#define RCG1 PORTB.F0
#define RCG2 PORTB.F3
#define RCD1 PORTB.F1
#define RCD2 PORTB.F4

// Vitesse du moteur de la roue Gauche (VG) et Vitesse du moteur de la roue Droite (VD) [VITESSE ==> FREQUENCE] <=> à gérer avec le PWM et la fréquence d'envoi des données
#define VG CCPR1L // 1 bit
#define VD CCPR2L // 1 bit
#define SENSG1 PORTD.F0 // 1 bit : 1 si vers l'avant 0 vers l'arrière sauf si SENSG1 = SENSG2 ==> STOP
#define SENSG2 PORTD.F1 // 1 bit : 1 si vers l'arrière 0 vers l'avant sauf si SENSG1 = SENSG2 ==> STOP
#define SENSD1 PORTD.F2 // 1 bit : 1 si vers l'avant 0 vers l'arrière sauf si SENSG1 = SENSG2 ==> STOP
#define SENSD2 PORTD.F3 // 1 bit : 1 si vers l'arrière 0 vers l'avant sauf si SENSG1 = SENSG2 ==> STOP

// Vitesse de la Courroie (VC) avant : [VITESSE ==> FREQUENCE] <=> à gérer avec la fréquence d'envoi des données
#define VC PORTC.F4 // 1 bit
#define SENSC1 PORTD.F4 // 1 bit
#define SENSC2 PORTD.F5 // 1 bit
// Vitesse de la Porte (VP) arrière : [VITESSE ==> FREQUENCE] <=> à gérer avec la fréquence d'envoi des données
#define VP PORTC.F6 // 1 bit
#define SENSP1 PORTD.F6 // 1 bit
#define SENSP2 PORTD.F7 // 1 bit



// --------------------------
// Définition des objectifs :
// --------------------------

// -------------------------
// Définition des constantes
// -------------------------


typedef enum Sens {AVANT,ARRIERE} Sens;

// --------------------------
// Définition des variables :
// --------------------------
char t;
Sens SRCG; // Sens Roue Codeuse Gauche
char NbPasCG; // Nombre de pas de roue codeuse gauche



//==============================================================================
//==============================================================================
//==============================================================================



// *****************************
// Liste des fonctions utilisées
// *****************************


//==============================================================================



//==============================================================================
//==============================================================================
//==============================================================================


// Fonction qui permet de gérer le temps
// Nécessite :
void Temp(void)
{
//if (INTCON.F2) // Gestion du temps : [0 ==> 100000] temppetit ==> x100000 ==> [0 ==> 100000] tempmoyen ==> x100000 ==> [0 ==> taille(double)] tempgros
{
t = t + 1;
//TMR0L = 0;
}
}



//==============================================================================


// Fonction qui permet de changer l'état du PORTD à chaque fois qu'il y a une interruption
// Nécessite :
void CodeurG(void)
{
if (RCG2 == 1)
{
SRCG = AVANT;
NbPasCG++;
}
else
{
SRCG = ARRIERE;
NbPasCG--;
}
}



//==============================================================================


// Fonction qui permet de gérer les interruptions
// Nécessite : Temp()
void interrupt(void)
{
if (INTCON.F2 == 1)
{
Temp();
INTCON.F2 = 0;
}
if (INTCON.F1 == 1)
{
CodeurG();
INTCON.F0 = 0;
}

INTCON = 0b10110000; // Réinitialise les options d'interruptions
}


//==============================================================================
//==============================================================================
//==============================================================================


// ===================
// Programme principal
// ===================

void main(void)
{
// -----------------------------
// Liste des variables utilisées
// -----------------------------


// ---------------------------------------------------------------------
// Définition des ports pour les interruptions sur le PORTB et le timer0
// ---------------------------------------------------------------------
T0CON = 0b10000100; // Utiliser le TMR0 en 16 bits et prescaler de TMR0 initialisé à 1/16
//TMR0L = 0b00011110; // Les interruptions s'effectueront toutes les : 1 s (si on est sur 16 bits)
//TMR0H = 0b00000000; // Uniquement sur 16 bits
INTCON = 0b10110000; // Autoriser les interruptions, celles de TMRO et INT0 (B.0)
ADCON1 = 0b00001111; // Utiliser les 4 premiers bits du port B en mode analogic [= analogique en anglais] uniquement (et non pas en digital = numérique en anglais)

/*
// ---------------------------------------------------------------------
// Configuration du PWM à 4 kHz (hmmm plus en fait) Vitesse maximale 125
// ---------------------------------------------------------------------
PR2 = 0b00111111 ;
T2CON = 0b00000101 ;
CCP1CON = 0b00001100 ;
CCP2CON = 0b00111100 ;
*/

// ---------------------
// Initialisation du pic
// ---------------------
TRISA = 0;
TRISB = 0b11111111;
TRISC = 0;
TRISD = 0;
TRISE = 0;
PORTA = 0;
PORTB = 0;
PORTC = 0;
PORTD = 0;
PORTE = 0;
t = 0;

// ************************
// DEFINITION DES OBJECTIFS
// ************************

while(1)
{
PORTD = t;
PORTC = NbPasCG;
if (SRCG == AVANT)
{
PORTA.F4 = 0;
}
else
{
PORTA.F4 = 1;
}
}
}



Vitesse du Moteur pas à pas contrôlé par la roue codeuse

Code : C

// Roues codeuses gauche et droite
#define RCG1 PORTB.F0
#define RCG2 PORTB.F3
#define RCD1 PORTB.F1
#define RCD2 PORTB.F4

typedef enum Sens {AVANT,ARRIERE} Sens;

char t;
Sens SRCG; // Sens Roue Codeuse Gauche
char NbPasCG; // Nombre de pas de roue codeuse gauche

int pas;


// Fonction qui permet de gérer le temps
// Nécessite :
void Temp(void)
{
//if (INTCON.F2) // Gestion du temps : [0 ==> 100000] temppetit ==> x100000 ==> [0 ==> 100000] tempmoyen ==> x100000 ==> [0 ==> taille(double)] tempgros
{
t = t + 1;
//TMR0L = 0;
}
}



//==============================================================================


// Fonction qui permet de changer l'état du PORTD à chaque fois qu'il y a une interruption
// Nécessite :
void CodeurG(void)
{
if (RCG2 == 1)
{
SRCG = AVANT;
NbPasCG++;
}
else
{
SRCG = ARRIERE;
NbPasCG--;
}
}



//==============================================================================


// Fonction qui permet de gérer les interruptions
// Nécessite : Temp()
void interrupt(void)
{
if (INTCON.F2 == 1)
{
Temp();
INTCON.F2 = 0;
}
if (INTCON.F1 == 1)
{
CodeurG();
INTCON.F0 = 0;
}

INTCON = 0b10110000; // Réinitialise les options d'interruptions
}


void wait_ms(int x)
{
int i;
for(i=0;i<=x;i++)
{
delay_ms(1);
}
}


void majEtat(void)
{
int etat = pas%4;
if (etat<0) etat += 4;
if ( etat == 0 )
PORTD = 0b00101000;
else if ( etat == 1 )
PORTD = 0b00000101;
else if ( etat == 2 )
PORTD = 0b00000011;
else // etat = 4
PORTD = 0b00011000;
}


void main (void)
{
int x, Vmax, Vmin, Da, Dc, Df, SAVE, V, S; // Distance de : Acceleration, constante, freinage

// ---------------------------------------------------------------------
// Définition des ports pour les interruptions sur le PORTB et le timer0
// ---------------------------------------------------------------------
T0CON = 0b10000100; // Utiliser le TMR0 en 16 bits et prescaler de TMR0 initialisé à 1/16
//TMR0L = 0b00011110; // Les interruptions s'effectueront toutes les : 1 s (si on est sur 16 bits)
//TMR0H = 0b00000000; // Uniquement sur 16 bits
INTCON = 0b10110000; // Autoriser les interruptions, celles de TMRO et INT0 (B.0)
ADCON1 = 0b00001111; // Utiliser les 4 premiers bits du port B en mode analogic [= analogique en anglais] uniquement (et non pas en digital = numérique en anglais)

/*
// ---------------------------------------------------------------------
// Configuration du PWM à 4 kHz (hmmm plus en fait) Vitesse maximale 125
// ---------------------------------------------------------------------
PR2 = 0b00111111 ;
T2CON = 0b00000101 ;
CCP1CON = 0b00001100 ;
CCP2CON = 0b00111100 ;
*/

// ---------------------
// Initialisation du pic
// ---------------------
TRISA = 0;
TRISB = 0b11111111;
TRISC = 0;
TRISD = 0;
TRISE = 0;
PORTA = 0;
PORTB = 0;
PORTC = 0;
PORTD = 0;
PORTE = 0;
t = 0;
pas = 0;
Vmax = 5;
V = 30;
Vmin = 80;
Da = 100;
Df = 100;
Dc = 200;
SAVE = NbPasCG;
S = 1;

while(1)
{
if (S == 1)
{
if(NbPasCG > SAVE)
{
if(V>Vmax)
{
V--;
}
}
else if (NbPasCG < SAVE)
{
if(V<Vmin)
{
V++;
}
else
{
S = -1;
V = Vmin-1;
}
}
pas++;
}
else
{
if(NbPasCG < SAVE)
{
if(V>Vmax)
{
V--;
}
}
else if (NbPasCG > SAVE)
{
if(V<Vmin)
{
V++;
}
else
{
S = 1;
V = Vmin-1;
}
}
pas--;
}
SAVE = NbPasCG;
wait_ms(V);
majEtat();
}
}
Avec un peu de recherche sur la datasheet et en pensant au composant LM621, vous devriez arriver à vos fins avec un peu de recherche sur le net (je manque vraiment de temps pour terminer convenablement le tutoriel).

Par manque cruel de temps, ce tutoriel a été littéralement "bâclé" sur la fin. Vous avez néanmoins suffisamment de bagage pour pouvoir faire vos recherches un peu seul...

Vous pouvez par la suite essayer de vous intéresser aux réseaux I2C qui permettent à plusieurs pic de communiquer entre eux de manière assez "facile" (vous n'avez pas à programmer vous-même le protocole de communication) ou encore les Conversion Analogique Numérique et inversement (CNA/CAN). Vous pouvez également essayer d'utiliser les entrées/sorties analogique (au lieu du tout ou rien) qui permettront de recevoir un signal en provenance d'un capteur de distance par exemple... Ce sont autant de pistes pour vous aider à continuer à vous améliorer.

Sur ce, j'espère que ce tutoriel vous aura quand même beaucoup aidé, et si certains sont motivés pour re-rédiger ce tutoriel en tout ou partie, il est totalement libre, je demande juste à ce qu'il le reste.