Lundi 04 Aout 2025
RobotICAM
Coupe 2006
Notre Robot
Support Elec
Support Info
Support Meca

Electronique programmable sur C18

by Edouard Limouse



L’électronique programmable a pour finalité l’analyse et la génération des signaux nécessaires à la mise en mouvement des systèmes du robot. Le rôle de l’électronicien informaticien est de parvenir à son but, en utilisant un code le plus simple et le plus efficace.
Pour le Roboticam 2006, nous avons choisi d’utiliser un PIC 18F452 car possédant de nombreuses entrées/sorties et autres fonctions (avec quartz de 4MHz). Cependant, il est préférable d’utiliser un PIC possédant son propre oscillateur interne. Ainsi, plus de problèmes de branchement de quartz ou d’oscillateur !
Nous avons programmé en langage C18 (un dérivé du C), sous MPLab de Microchip.

Afin d’être performant lors de la programmation, il est indispensable voire incontournable de connaître la datasheet de la puce. De plus, il est intéressant de jeter un oeil aux différentes bibliothèques mises à disposition par C18. Par exemple, vous avez les bibliothèques incontournables tel que timer.h pour avoir des délais, compare.h pour générer des signaux carrées ou usart.h pour gérer la communication série... (Utiliser #include <la_biblio.h> )

Tout d’abord, je recommande de programmer de nombreuses procédures, petites et simples, qu’il est indispensable de tester et re-tester. La première à réaliser est biensûr l’initialisation du PIC, c'est-à-dire configurer tous les registres nécessaires à ce que l’on souhaite faire. Cela est certainement la partie la plus difficile du travail. N’oublier pas votre indispensable datasheet, ainsi que les bibliothèques qui peuvent vous faciliter ce travail. Biensûr, vous pouvez aussi configurer ces registres manuellement.
Par exemple, pour faire des acquisitions (utilisation du CAN ... convertisseur analogique/numérique ...sur le PortA) il faut mettre à 1 (en entrée) les bits voulus du PortA : c’est la configuration de TRISA. Ensuite, il faut régler ADCON0 et ADCON1 comme souhaité. Cela suffit, pour utiliser le CAN.
Par la suite, il faudra intégrer tous ces morceaux de code au chef d’œuvre que vous allez concocter. ;) Je vous recommande de penser à l’architecture du code... ça à l’air bête mais cela m’a coûté deux semaines de travail pour aucun résultat. L’erreur était un code trop conséquent au niveau des interruptions, et le processeur ne pouvait suivre le rythme ! J’ai donc repassé ce code au niveau du main() ; (la procédure principale). Essayez aussi de mettre au maximum de variables en locales et commentez le code !

Après cette petite introduction, je vais vous expliquer les grandes lignes du fonctionnement des microcontrôleurs PIC avec un maximum d’exemples de code que vous pourrez récupérer, si vous utilisez toujours C18.


Les interruptions : le microcontrôleur arrête se qu’il est en train d’effectuer afin d’exécuter un code d’interruption. Elles sont particulièrement intéressantes pour capter ou générer un signal. Sur le PIC 18F452, elles de deux niveaux : bas ou haut. Le niveau haut aura le dessus sur le bas. Pour les mettre en place, il est indispensable de les déclarer en haut du code : « void le_nom_de_l’inté () ; » . Puis il faut indiquer sa position: le vecteur d’interruption haute se situe à l’adresse 0x08. Je vous conseil de repiquer le code suivant tel quel :

//-----------------------------------------------------------------------------------------------
//      VECTEUR D'INTERRUPTION HAUTE
//-----------------------------------------------------------------------------------------------
#pragma code InterruptVectorHigh = 0x08
void
InterruptVectorHigh (void)
{
  _asm
    goto InterruptHandlerHigh //va a la fct interrupt
  _endasm
}
//-----------------------------------------------------------------------------------------------
//      INTERRUPTION
//-----------------------------------------------------------------------------------------------
#pragma code
#pragma interrupt InterruptHandlerHigh
void InterruptHandlerHigh ()
{
        if (flag_de_linterruption_est_levé)                    //test du flag
    {  
        « Code de linterruption »                           
    }
}

Enfin, dans la procédure, il va falloir tester les différents flags ou drapeaux d’interruption pour connaître le type de cette dernière. En effet, les interruptions peuvent provenir de nombreux horizons (voir datasheet). Par exemple, il y a celles provoquées par le débordement d’un timer, celles de la fonction compare ou capture, celles des interruptions extérieures....
Toutefois, il faut se demander si l’interruption est utile ! Si vous souhaitez utiliser des rupteurs, il n’est pas nécessaire d’en utiliser puisque le temps de réponse de l’interrupteur mécanique est grand comparé à celui du microprocesseur. Une simple condition dans le main() suffit.


Les timers : ils permettent d’horloger votre système. Si vous avez besoin d’un compteur, c’est sur eux qu’il faut compter ! Pour les configurer, il faut utiliser les registres TxCON (x est le n° du timer : il y en a quatre sur le 18F452). Le prescaler sert à incrémenter le timer tous les 1,2,8,16.... cycles de quartz. Son choix dépend de la durée de votre application. Par exemple, pour un quartz de 4MHz, un timer de 8bits et un prescaler de 64, vous atteignez les 256 valeurs en 16ms.
Il est possible de récupérer la valeur contenue dans le timer en utilisant la commande TMRxL (8bits de poids faibles) et TMRxH(8bits de poids forts, si il y a).


Le CAN : associe une valeur numérique à une tension continue. Pour la configuration, voir plus haut. Il faut aussi réfléchir au nombre d’entrées analogiques nécessaires ainsi qu’aux nombres de références de tension pour bien configurer les registres ADCON0 et 1. Si par exemple, vous avez besoin de 3 entrées analogiques pour 0 référence (c'est-à-dire tension entre 0 et 5V), vous nécessitez  la configuration suivante (Cf. page 182 de la datasheet) : C/R = 3/0 ; cela correspond aux entrées analogiques 0,1 et 3. Et pour la configuration du registre ADCON1 vous devez implémenter 0100 aux bits 3 à 0.
Cette valeur peut être récupérée en utilisant le registre ADRESH (si on l’a, au préalable, configuré pour récupérer les valeurs hautes)
Vous pouvez utiliser cette fonction pour obtenir la valeur numérisée.
//-----------------------------------------------------------------------------------------------
//              FONCTION D ACQUISITION
//-----------------------------------------------------------------------------------------------
unsigned char Acquisition (void)
        {
        ADCON0bits.GO = 1;      //lancement de l'acquisition
        while(ADCON0bits.GO);//on ne fait rien, on attend la fin de l'acqui :-)
        return ADRESH; 
        }

Si vous avez un signal provenant d’une photodiode et d’un laser, il n’est pas forcement obligatoire d’utiliser un CAN. Si le laser est coupé, la tension aux bornes de la photodiode est supérieure à 2,5V et si le laser ne l’est pas, elle est inférieure à 2,5V. Dans ce cas, il suffit de brancher la photodiode directement sur une entrée numérique.


La communication série (USART): sert à communiquer entre différents PIC ou avec une carte mère. Il faut au préalable configurer l’ouverture des ports RX et TX, la vitesse de communication... Elle est pour ma part, la chose la plus difficile à réaliser, surtout si vous communiquer vers une carte mère.
Vous avez ci-dessous un exemple de configuration avec la réception mise en interruption (il est nécessaire d’avoir déclaré la librairie usart.h en entête) :


//Initialisation du port série à 19200baud - interruption du RX (réception)
        OpenUSART(USART_TX_INT_OFF &
                        USART_RX_INT_ON &
                USART_ASYNCH_MODE &
                USART_EIGHT_BIT &
                        USART_BRGH_HIGH, 12);
        IPR1bits.RCIP = 1; // interruption du RX haute


Si vous voulez envoyer de linformation via le port série, vous pouvez utiliser le code suivant :


//-----------------------------------------------------------------------------------------------
//      ENVOIE VIA COM SERIE
//-----------------------------------------------------------------------------------------------
void putsUSART_rom(char *data) // Envoi d'une chaîne de caractère sur série
{
  do
  {
    while (BusyUSART());
    putcUSART(*data);
  } while (*data++);
}

Le buffer, qui est un tableau tampon, doit être au préalablement définit en entête. Il est aussi possible d’utiliser des bibliothèques de fonctions pour le traitement de chaînes de texte tel que : <stdio.h> pour sprintf…
Attention à la fréquence du  quartz ou de l’oscillateur pour la vitesse de communication.
Si vous avez plusieurs PIC communiquant sur la même piste, vous pouvez utilisez l’astuce d’ouvrir et de fermer le port TX. En les faisant parler les uns à la suite des autres,  vous n’abîmerez pas le PIC et vous pourrez obtenir une communication propre.
 
Vous avez aussi la possibilité d’utiliser les fonctions compare / captures. Capture sert à récupérer les valeurs de temps d’un changement d’état sur une patte du PIC. Ainsi vous pouvez traiter différents signaux carrés. La fonction PWM sert à générer des signaux PWM avec un cycle de commande (duty cycle) variable. Maintenant à vous d’explorer les nombreuses possibilités du microcontrôleur car je vous rappelle que je ne vous ai expliqué que la base !

Contrôler un servo-moteur : Un servo-moteur est un petit moteur asservi de modélisme. Pour le brancher, il vous faut du 5V, la masse, et un fil de commande qui arrive tout droit du PIC.  Le signal de commande est quasi un PWM. Il vous faut générer une impulsion (temps haut) de 1ms à 2ms toutes les 16 à 20ms (cette valeur temps haut + temps bas doit rester constante). Le temps haut est le duty cycle ; c’est lui qui va donner une valeur d’angle au servo.
Pour générer ce signal, il y a de nombreuses méthodes : la fonction compare, le PWM (peut-être la plus appropriée), l’utilisation des timers…
Pour ma part, cette année j’ai commandé facilement jusqu’à 8 servo-moteurs en utilisant le débordement du timer 0. Je l’ai configuré de telle manière qu’il débarde normalement au bout de 16ms. Manuellement, j’ai ensuite touché au timer pour qu’il déborde parfois au bout de 1.5ms (si je veux le point neutre) ou parfois au bout de 16-1.5 = 14.5ms.
Cette méthode n’est peut-être pas la meilleure car on touche au timer (perte d’un cycle) mais elle fonctionne!

        Cette année 2006, nous avons eu besoin d’un système de barillet qui puisse tourner à 360°. J’ai alors utilisé un servo-moteur hybridé par mes soins car tous les servos vont de 0 à 180° ! L’opération est simple, il suffit de l’ouvrir, limer la buté en plastique sur le réducteur puis dessouder le potentiomètre de l’asservissement pour le remplacer par un pont diviseur de tension (deux résistances de 2.5kO). Maintenant, vous obtenez un simple moto-réducteur avec une commande identique que le servo-moteur. Je l’ai alors utilisé un position marche/arrêt ; Je l’arrêtais lorsque le nombre de pâle voulu coupait un laser prévus à cet effet. Le seul inconvénient est que l’asservissement à été supprimé mais le système marchais sans !


La boussole (CMPSO3) : Elle est simple à brancher : le 5V, la masse et en sortie le PWM (Pin4) qui est directement envoyé sur le PIC. Le signal à traiter est un signal carré compris entre 1ms (0°) et 39.99ms (360°). Pour cela, il faut que vous utilisiez la fonction capture. Vous avez ci-dessous, un exemple de code d’initialisation pour la configuration des captures :

// Initialisation de la boussole
//Init CCP1
        CCP1CON = 0b00000101; //capture mode every rising edge
        PIE1bits.CCP1IE = 1;  //Enable the CCP1 interrupt
        IPR1bits.CCP1IP = 1;  //High Priority for CCP1
        T3CONbits.T3CCP1 = 0; //Timer 1 is the clock source for
//      T3CONbits.T3CCP2 = 0; //CCP module
//Init Timer1 in two 8 bits registers, Internal clock, Prescale Value 1:8
        T1CON = 0b00110001;   
       
Pensez à mettre la patte CCP1 du port C en entrée. Et n’oubliez pas de re-calibrer la boussole si vous trouvez qu’elle ne renvoie pas des valeurs linéaires. Attention, c’est une opération délicate ! Vous devez brancher le Pin 6 sur un bouton poussoir relié à la masse et appuyer dessus lorsque vous êtes sur le nord. L’opération est à répéter sur chaque point cardinal.

Bonne chance pour la suite !           

Copyright © 2006 RobotIcamToulouse