Leçons de niveau 15

Bico64

Une page de Wikiversité.
Sauter à la navigation Sauter à la recherche



Bico64 dessus.jpg

Le Bico64 est un petit circuit à souder soit même commercialisé par Didel. Il est vendu avec le WellBot mais connaissant Didel, ce doit être possible d'obtenir ce module seul si une application / enseignement est en vue.

L'avantage de commencer avec un tel module est que le résultat est très visuel, donc accessible aux plus jeunes programmeurs.

L'inconvénient est qu’il nécessite tout de même un programmeur PicKit 2 (aussi vendu par Didel). Pour ceux qui cherchent le démarrage le plus simple pour apprendre à débuter en Hard et en soft, il faut se tourner vers les Kidules toujours de Didel qui permettent d’avoir un environnement de dev Pinguino[1] et que l’on peut télécharger directement via U.S.B. (qui sert aussi d'alim).

Le Bico64 est livré avec quelques exemples en assembleurs CALM, mais c’est trop complexe pour un tout jeune débutant (mon fils par exemple). Du coup tout déçu de ne pas pouvoir "customiser" son petit robot, je me suis attaqué à rendre ceci plus accessible.

Ce site me sert surtout à moi pour documenter la marche à suivre autant que faire ce peut et tant mieux si cela en aide l'un ou l'autre à démarrer.

Hardware[modifier | modifier le wikicode]

Montage du Bico64[modifier | modifier le wikicode]

On se réfèrera à la notice de montage du Bico64

Le processeur est un PIC16f884, dont on trouve le databook ici [2]

Ajout d'un connecteur pour le programmer[modifier | modifier le wikicode]

Bico64 dessous.jpg
Bico64 avec PICkit 2.jpg

à la base le circuit a été prévu avec un petit connecteur 5 pôles pour le programmer. mais ce petit connecteur s'il est monté rentre en conflit avec le robot WellBot. J’ai donc préféré ajouter une barrette de pins qui est directement compatible avec le PicKit 2. Le pinning est différent et on peut voir sur l'image ci-contre comment câbler le tout. Il y a 6 pins sur le pickit 2 mais la dernière n’est pas utilisée. Vous pouvez agrandir l'image pour bien voir les no de pins et le câblage.

On peut donc facilement connecter le PICkit 2 avec le Bico64 pour le programmer.

Comprendre le cycle de développement[modifier | modifier le wikicode]

Pour programmer un petit processeur il faut plusieurs étapes que l’on va devoir répéter à chaque modifications.

Processus compilation.jpg

Tout d’abord, nous allons écrire un programme dans un langage informatique relativement indépendant du processeur utilisé. Dans notre cas, nous allons utiliser le C qui est un langage assez vieux, pas forcément génial, mais très utilisé. Le processus de compilation est le suivants:

éditer le source[modifier | modifier le wikicode]

Il faut si possible un éditeur qui soit bien fait pour le source, avec coloration syntaxique. J'utilise Context qui est gratuit et qui a tout ce qu’ils faut, y compris de quoi lancer la compilation et montrer où se trouvent les erreurs. Cette étape est évidemment celle qui prend le plus de temps au programmeur et là où il va aussi passer le plus de temps à ce dire "mais pourquoi ça ne marche pas?". On verra plus loin des Bico64#Exemples de programmes.

En C on peut écrire dans un fichier .c

 Position = Position + Vitesse;;

compiler le source[modifier | modifier le wikicode]

Comme le langage C est indépendant d'un processeur, la première chose à faire est de traduire tout cela dans un autre langage qui est lui dépendant du processeur: l'assembleur. L'assembleur est un langage où chaque ligne est une instruction du processeur. Toutefois, c’est encore un langage lisible par un humain (entrainé) où on peut encore nommer les routines et les variables, ce qui fait que l’on n'a pas besoin de mémoriser les codes des instruction ou de faire de savant calcul pour savoir à quel endroit se trouve quelle routine. Techniquement parlant, le compilateur pourrait passer directement à la génération de code, mais c’est plus facile pour ceux qui écrivent le compilateur de traduire en assembleur puis de laisser l'assembleur traduire en code machine.

Le compilateur utilisé est SDCC qui est un compilateur Open Source supportant les PIC

À la sortie du compilateur on aura un fichier .asm qui peut ressembler à cela

;      .line 87; "test02.c" Position = Position + Vitesse;
       BANKSEL r0x101B
       MOVF    r0x101B,W
       ADDWF   r0x101A,F

À ce stade, il est inutile de comprendre ce que chaque ligne veut dire, mais on remarque qu’il met une ligne de commentaire (commence par un ;) en montrant ce qu’il veut traduire puis il met les instructions processeurs nécessaires à faire cela.

assembler[modifier | modifier le wikicode]

Ce programme prend le fichier assembleur et le traduit directement en code machine, ce qui est facile puisque le langage assembleur est directement le reflet des codes qui peuvent être compris par le processeur. En même temps, l'assembleur traduit des "labels" (= des noms donnés par le programmeur) en adresses dans le but d’éviter des calculs fastidieux pour le programmeur. Bien que l’on utilise souvent un langage comme le C, on peut tout à fait aussi programmer en assembleur.

À la sortie de l'assembleur, on aura un fichier .o ce fichier n’est pas fait pour être lu par un humain.

Il y a aussi un fichier .lst: il n'est fait que pour un humain pour bien comprendre comment l'assembleur a fait la traduction en code machine

                                ;.line	87; "test02.c"	Position = Position + Vitesse;
000012 1283     bcf   0x3, 0x5  BANKSEL r0x101B
000013 1303     bcf   0x3, 0x6            
000014 083b     movf  0x3b, w   MOVF    r0x101B,W
000015 07ba     addwf 0x3a, f   ADDWF   r0x101A,F

linker[modifier | modifier le wikicode]

(édition de liens en français): si on a plusieurs morceaux d'assembleurs qui ont été traduits en code machine (des .o), il faut encore les mettre ensemble et les reconnecter si nécessaire. De plus, il faut regarder où mettre ces différents morceaux en mémoire, ce qui peut changer suivant le schéma électronique réalisé et l’utilisation qui est faite du processeur.

À ce stade, on obtient un gros tas de bytes qui n'ont plus qu’à être chargé en mémoire. Ce gros tas de bytes se trouve dans un fichier "hexa" avec l'extension .hex

:020000040000FA
:1000000000008A110A12AD28053083120313BA00CA
:100010001D2083120313BB012030FE000030FF00BF
:1000200000302520831203133B08BA07BB0A3A08A5
:100030008312031387000C2808008316031386011C
:1000400087018801FF308500080083120313B20086
:100050007F08B1007E08B000FE30B300B40110305C

Charger le code[modifier | modifier le wikicode]

On va charger le code dans le processeur à l'aide d'un programmateur: cet outil est complètement différent d'un fabricant de processeur à l'autre et permet de mettre en mémoire le programme. Dans notre cas, il s'agit du PICkit 2 qui permet de programmer la majorité des processeurs PIC.


Toutes ces étapes doivent être refaites à chaque fois que l’on modifie le programme (donc souvent, car cela ne marche pas souvent du premier coup!). Il est donc important de bien automatiser toutes ces étapes pour qu'on ait le minimum de manipulation à chaque cycle.

  • Dans le cas de SDCC, il a déjà prévu de compiler, assembler, linker de manière automatique
  • Le PICkit2 a un programme qui permet de lui dire de regarder lorsque le fichier

Installer l'environnement de développement[modifier | modifier le wikicode]

Installer le soft pour le PICkit 2[modifier | modifier le wikicode]

Le soft est en principe livré avec le PICkit, mais on peu télécharger la dernière version chez microchip Une fois le soft installé, vous pouvez brancher le PICkit2 sur U.S.B. et encore le Bico64 au PICkit.

En lançant ce soft vous devez voir la détection du processeur (ici 16F884) et en pressant le bouton read vous pouvez lire le contenu de la mémoire. Si tout cela fonctionne, la fin de notre cycle de développement fonctionne.

Environnement C Open Source SDCC[modifier | modifier le wikicode]

L'environnement SDCC est un compilateur C Open Source qui supporte la famille des PIC (même si encore en construction). Ce compilateur compile du langage C en assembleur qui doit lui-même être assemblé.

Environnement GPUTILS[modifier | modifier le wikicode]

Pour l'assemblage et le linkage j'utilise l'assembleur Open Source livré dans le paquet GPUTILS

Installation de l'éditeur ConTEXT[modifier | modifier le wikicode]

Télécharger l'éditeur ConTEXT à l'adresse suivante [3]

Après l'installation de l'éditeur, il faut le configurer pour que l’on puisse facilement lancer SDCC et que l’on puisse récupérer les erreurs et pouvoir facilement afficher la ligne qui pose le problème.

  • Allez dans le menu options puis Options d'environnement
  • Dans l'onglet Touches d'exécution pressez le bouton Ajouter
  • ConTEXT va demander pour quelle extension faut il ajouter ces touches d'exécution: introduire c car nous voulons que cette touche soit valide pour les programmes C.
  • ConTEXT affiche alors F9,F10,F11,F12: choisissons F12 comme touche pour compiler en cliquant sur le bouton F12.
  • Dans Exécuter mettre "C:\Program Files\SDCC\bin\sdcc.exe" %f (attention, sur la capture d'écran, on ne voit pas tout. Les " sont nécessaires vu que Program Files a un espace. (évidemment, si SDCC a été installé ailleurs, il faut mettre le chemin juste)
  • Dans Paramètres mettre -mpic14 -p16F887 -V --use-non-free -L"c:\program Files\SDCC\non-free\lib\pic14". On ne devrait pas avoir besoin du dernier paramètre -L"c:\program Files\SDCC\non-free\lib\pic14", car le fait de mettre --use-non-free devrait ajouter automatiquement ce chemin, mais il y a un petit bug dans la version actuellement utilisée et il ajoute seulement -L"c:\program Files\SDCC\non-free\lib\pic". Sera peut être corrigé dans le futur. (attention, la copie d'écran ci contre n’est pas correcte pour ce paramètre).

Structure de répertoires et modification du PATH[modifier | modifier le wikicode]

Une fois tout installé, on doit avoir la structure de répertoires suivantes:

  • C:\Program Files\
    • ConTEXT (dans lequel on trouve ConTEXT.exe)
      • Backup
      • Highliters
      • Template
    • gputils
      • bin (où l’on trouve GPASM et GPLINK)
      • doc
      • header
      • lkr (où l’on trouve le mappage mémoire des processeur: le mappage mémoire du 16f887 est ok pour notre Bico64)
    • PicKit 2 v2
      • ...
    • SDCC
      • bin (où l’on trouve SDCC.exe)
      • doc
      • include
        • pic14 (et d'autres, mais seul pic14 nous intéresse, car le 16f887 est de la famille des PIC 14 bits)
      • lib
        • pic14 (et d'autres, mais seul pic14 nous intéresse, car le 16f887 est de la famille des PIC 14 bits)
      • non-free
        • include
          • pic14 (les fichiers de description des processeurs dont le pic16f887.h qui est indispensable pour nous)
        • lib
          • pic14 (les fichiers de description des processeurs dont le pic16f887.lib qui est indispensable pour nous)
        • lib


Pour ne pas avoir besoin de spécifier en permanence où se trouvent SDCC, GPASM et GPLINK, il faut ajouter les chemins de recherches en cliquant sur le poste de travail bouton droit Propriétés et dans l'onglet Paramètres système avancés cliquer sur variables d'environnement.

En modifiant la variable Path, lui ajouter C:\Program Files\SDCC\bin;C:\Program Files\gputils\bin

Exemples de programmes[modifier | modifier le wikicode]

Ci dessous, quelques exemples de programmes qui vont en se complexifiant. Pour faciliter, vous pouvez copier le programme et le coller dans ConTEXT.

Bien que les programmes soient de plus en plus compliqués, pour un débutant débutant, il est peut être plus simple de copier le 2e programme et de ne modifier que la procédure loop()

Affichage d'une image fixe (AfficheImageFixe.c)[modifier | modifier le wikicode]

Comme premier petit programme voici de quoi afficher une image fixe.

Bico64 result AfficheImageFixe.jpg

À ce stade, vous aurez forcément plein de questions sur la syntaxe du C. Le mieux est de se référer à un des nombreux cours se trouvant sur le net

  //------------------------------------------------------------------------------------------
  // Programme de démonstration qui affiche une image sur le Bico64
  //------------------------------------------------------------------------------------------
  #define __16F887
  #include <pic16f887.h>
  //------------------------------------------------------------------------------------------
  // Configuration du PIC 16F884 selon Bico64
  //------------------------------------------------------------------------------------------
  __code __at _CONFIG1 unsigned int Config1 =
     _INTOSCIO  // I/O function on RA6/OSC2/CLKOUT pin, I/O function on RA7/OSC1/CLKIN
   & _WDT_OFF   // pas de Watch Dog
   & _PWRTE_ON  // on attend un peu au démarrage
   & _MCLRE_ON  // RE3/MCLR pin function is MCLR
   & _CP_OFF    // Program memory code protection is disabled
   & _CPD_OFF   // Data memory code protection is disabled
   & _BOR_OFF   // BOR Disabled
   & _IESO_OFF  // Internal/External Switchover mode is disabled
   & _FCMEN_OFF // Fail-Safe Clock Monitor is disabled
   & _LVP_OFF   // RB3 pin is digital I/O, HV on MCLR must be used for programming
   & _DEBUG_OFF;// In-Circuit Debugger disabled, RB6/ICSPCLK and RB7/ICSPDAT are general purpose I/O pins
  __code __at _CONFIG2 unsigned int Config2 =
     _WRT_OFF // No prog memmory write protection
   & _BOR21V;  // Brown-Out Reset at 2.1V

  typedef unsigned char byte;
 
  // on donne des noms significatifs aux PORTs utilisés
  #define PLIGNE PORTB
  #define PVERT  PORTC
  #define PROUGE PORTD
 
  //----------------------------------------------------------------------------------------
  void Setup(void) {
    // Initialisation
    TRISB = 0x00;       // PortB est en sortie
    TRISC = 0x00;       // PortC est en sortie
    TRISD = 0x00;       // PortD est en sortie
    TRISA = 0xFF;       // PortA est en entrée
  }

  byte image[16] = {
    //  Vert      Rouge          PLIGNE
    0b11111111,0b00000000,      // D0
    0b11111110,0b00000000,      // D1
    0b11111100,0b00000000,      // D2
    0b11111000,0b00000000,      // D3
    0b11110000,0b00000001,      // D4
    0b11100000,0b00000011,      // D5
    0b11000000,0b00000111,      // D6
    0b10000000,0b00001111,      // D7
  };

  void EffacerImage(void) {
    // efface l’ensemble de l'image
    short i;
    for (i=0;i<16;i++){
      image[i] = 0;
    }
  }

  //----------------------------------------------------------------------------------------
  void AfficherImage(byte temps) {
    // affiche l'image
    // le paramètre temps permet de régler le temps que va prendre cette procedure
    // en répétant n fois l'affichage. C'est un moyen primaire de faire aller
    // plus ou moins vite l’affichage dans les procédure qui appelle AfficherImage.
    // temps =1 ==> env 5ms pour afficher
    // L'image affichée se trouve dans le tableau mémoire "image"
     int i,n;
     byte ligne;
     byte *p;                       //p pointe sur le premier byte du tableau image
 
     for (n=0;n<temps;n++){
       p = &image[0];
       ligne = 0b11111110;          // dans Ligne, on aura la ligne active à 0; on décalera le 0 pour chaque ligne
       while (ligne != 0b11111111){ // tant qu’il reste un 0, on n'a pas terminé de balayer l'image
         PLIGNE = 0b11111111;       // pour éviter de voir des petits "phantomes" de la ligne précédente
                                    // on ne sélectionne aucune ligne
         PVERT  = *p++;             // on met les bits pour la couleur Rouge
         PROUGE = *p++;             // on met les bits pour la couleur Verte
         PLIGNE = ligne;            // on met la ligne (le bon bit à 0)
         ligne = (ligne << 1) +1 ;  // on décale le bit à 0 de un bit, comme cela met D0 à 0, on
                                    // force D0 à 1 pour n'avoir qu'un bit à 0 (ligne active)
         for (i=0;i<50;i++) {};     // on attend un peu pour avoir le temps de voir cette ligne
       }
     }
  }

  //-------------------------------------------------------------
  // La boucle: on ne fait qu'afficher l'image
  //-------------------------------------------------------------
  void Loop(void) {
    AfficherImage(1);
    image[0]++;      // on modifie l'image pour voir à quel vitesse va l'affichage
  }

  //-------------------------------------------------------------
  // Programme principal (là où le PIC va démarrer)
  //-------------------------------------------------------------
  void main(void) {
    Setup();
    while(1) {
      Loop();
    }
  }

Quelques explications:

  • la configuration du PIC: dans un premier temps inutile de comprendre: c’est comme cela qu’il faut le configurer pour le Bico64. Par contre pour les curieux (ou ceux qui veulent faire autre chose que le Bico64, on trouve les registres de config au § 14.1 et 14.2 du databook[4]. Cette section est indispensable, sans quoi le PIC sera configuré n’importe comment et risque de ne pas démarrer ou faire n’importe quoi.
  • Un programme c démarre toujours dans la procédure main: Celle-ci ne fait pas grand chose: elle appelle une fois Setup() puis elle appelle toujours la procédure Loop()
  • Setup configure les Ports du PIC pour lui dire ce qui est des entrées et ce qui est des sorties (un bit à 0 dans TRISx = sortie).
  • Loop ne fait que d'appeler AfficherImage qui fait le travail de scanner le tableau Image et de le mettre sur les leds

Affichage d'images variables[modifier | modifier le wikicode]

Le programme suivant permet de mettre plusieurs images et possèdes quelques effets comme des spirales. Ceci permet d’avoir un programme principal plus ludique puisqu'on peut enchainer plusieurs figures.

  //------------------------------------------------------------------------------------------
  // Programme de démonstration qui affiche une image sur le Bico64
  //------------------------------------------------------------------------------------------

 
  #define __16F887
  #include <pic16f887.h>
 
  //------------------------------------------------------------------------------------------
  // Configuration du PIC 16F884 selon Bico64
  //------------------------------------------------------------------------------------------
  __code __at _CONFIG1 unsigned int Config1 =
     _INTOSCIO  // I/O function on RA6/OSC2/CLKOUT pin, I/O function on RA7/OSC1/CLKIN
   & _WDT_OFF   // pas de Watch Dog
   & _PWRTE_ON  // on attend un peu au démarrage
   & _MCLRE_ON  // RE3/MCLR pin function is MCLR
   & _CP_OFF    // Program memory code protection is disabled
   & _CPD_OFF   // Data memory code protection is disabled
   & _BOR_OFF   // BOR Disabled
   & _IESO_OFF  // Internal/External Switchover mode is disabled
   & _FCMEN_OFF // Fail-Safe Clock Monitor is disabled
   & _LVP_OFF   // RB3 pin is digital I/O, HV on MCLR must be used for programming
   & _DEBUG_OFF;// In-Circuit Debugger disabled, RB6/ICSPCLK and RB7/ICSPDAT are general purpose I/O pins
 
  __code __at _CONFIG2 unsigned int Config2 =
     _WRT_OFF // No prog memmory write protection
   & _BOR21V;  // Brown-Out Reset at 2.1V

  //-------------------------------------------------------------
  // Initialisation
  //-------------------------------------------------------------
  // on donne des noms significatifs aux PORTs utilisés
  #define byte unsigned char
  #define PLIGNE PORTB
  #define PVERT  PORTC
  #define PROUGE PORTD

  void Setup(void) {
    TRISB = 0x00;       // PortB est en sortie
    TRISC = 0x00;       // PortC est en sortie
    TRISD = 0x00;       // PortD est en sortie
    TRISA = 0xFF;       // PortA est en entrée
  }

  byte image[16];

  __code byte coeur[16] = {
    //  Vert      Rouge          PLIGNE
    0b11111111,0b00000000,      // D0
    0b10011001,0b01100110,      // D1
    0b00000000,0b11111111,      // D2
    0b00000000,0b11111111,      // D3
    0b10000001,0b01111110,      // D4
    0b11000011,0b00111100,      // D5
    0b11100111,0b00011000,      // D6
    0b11111111,0b00000000,      // D7
  };
  __code byte pique[16] = {
    //  Vert      Rouge
    0b00011000,0b00011000,
    0b00111100,0b00111100,
    0b01111110,0b01111110,
    0b11111111,0b11111111,
    0b11111111,0b11111111,
    0b01011010,0b01011010,
    0b00011000,0b00011000,
    0b00111100,0b00111100,
  };
  __code byte rouge[16] = {
    //  Vert      Rouge
    0b00000000,0b11111111,
    0b00000000,0b11111111,
    0b00000000,0b11111111,
    0b00000000,0b11111111,
    0b00000000,0b11111111,
    0b00000000,0b11111111,
    0b00000000,0b11111111,
    0b00000000,0b11111111,
  };
  __code byte noir[16] = {
    //  Vert      Rouge
    0b00000000,0b00000000,
    0b00000000,0b00000000,
    0b00000000,0b00000000,
    0b00000000,0b00000000,
    0b00000000,0b00000000,
    0b00000000,0b00000000,
    0b00000000,0b00000000,
    0b00000000,0b00000000,
  };

  void CopierImage(byte *newImage){
    short i;
    for (i=0;i<16;i++){
      image[i] = *newImage;
      newImage++;
    }
  }

  void EffacerImage(void) {
    short i;
    for (i=0;i<16;i++){
      image[i] = 0;
    }
  }


  #define NOIR  0
  #define VERT  1
  #define ROUGE 2
  #define JAUNE 3

  void MettrePixel(short col,short ligne, byte couleur){
    byte BitCol = 0b00000001 << col;
 
    if (couleur & VERT) {
      image[ligne*2] = image[ligne*2] | BitCol;
    }
    else {
      image[ligne*2] = image[ligne*2] & ~BitCol;
    };
    if (couleur & ROUGE) {
      image[ligne*2+1] = image[ligne*2+1] | BitCol;
    }
    else {
      image[ligne*2+1] = image[ligne*2+1] & ~BitCol;
    }
  }

  void AfficherImage(byte temps) {
     int i,n;
     byte ligne;
     byte *p;                       //p pointe sur le premier byte du tableau image
 
     for (n=0;n<temps;n++){
       p = &image[0];
       ligne = 0b11111110;          // dans Ligne, on aura la ligne active à 0; on décalera le 0 pour chaque ligne
       while (ligne != 0b11111111){ // tant qu’il reste un 0, on n'a pas terminé de balayer l'image
         PLIGNE = 0b11111111;       // pour éviter de voir des petits "phantomes" de la ligne précédente
                                    // on ne sélectionne aucune ligne
         PVERT  = *p++;             // on met les bits pour la couleur Rouge
         PROUGE = *p++;             // on met les bits pour la couleur Verte
         PLIGNE = ligne;            // on met la ligne (le bon bit à 0)
         ligne = (ligne << 1) +1 ;  // on décale le bit à 0 de un bit, comme cela met D0 à 0, on
                                    // force D0 à 1 pour n'avoir qu'un bit à 0 (ligne active)
         for (i=0;i<50;i++) {};     // on attend un peu pour avoir le temps de voir cette ligne
       }
     }
  }


  void AfficherSpirale(byte couleur,byte temps){
  //-------------------------------------------------------------
  // On affiche une spirale qui tourne de manière anti-horaire de
  // l'exterieur vers l'intérieur. D'une couleur donnée
  //-------------------------------------------------------------
    short c=0,l=0;
    short rangee;
 
    for (rangee=0;rangee<=3;rangee++) {
      for (c=rangee;c<=7-rangee;c++){
        MettrePixel(c,l,couleur);
        AfficherImage(temps);
      }
      c--;
      for (l=rangee+1;l<=7-rangee;l++){
        MettrePixel(c,l,couleur);
        AfficherImage(temps);
      }
      l--;
      for (c=7-1-rangee;c>=rangee;c--){
        MettrePixel(c,l,couleur);
        AfficherImage(temps);
      }
      c++;
      for (l=7-1-rangee;l>=rangee+1;l--){
        MettrePixel(c,l,couleur);
        AfficherImage(temps);
      }
      l++;
    }
  }

  void AfficherBalayageGauche(byte couleur,byte temps){
  //-------------------------------------------------------------
  // On balaie de droite à gauche avec une couleur donnée
  //-------------------------------------------------------------
    short c=0,l=0;
    for (c=0;c<=7;c++){
      for (l=0;l<=7;l++){
         MettrePixel(c,l,couleur);
         AfficherImage(temps);
      }
    }
  }

  void AfficherBalayageDroite(byte couleur,byte temps){
  //-------------------------------------------------------------
  // On balaie de droite à gauche avec une couleur donnée
  //-------------------------------------------------------------
    short c=0,l=0;
    for (c=7;c>=0;c--){
      for (l=0;l<8;l++){
         MettrePixel(c,l,couleur);
         AfficherImage(temps);
      }
    }
  }

/*
=== Pour les débutants: commencez par modifier ce bout de programme  ===
.*/
  void Loop(void) {
  //-------------------------------------------------------------
  // La boucle principale:
  //-------------------------------------------------------------
    int i;
    byte l;
 
    EffacerImage();
    AfficherSpirale(VERT,20);
    AfficherSpirale(JAUNE,20);
    AfficherSpirale(ROUGE,20);
    
    for (i=10; i<10; i++){
      CopierImage(&noir[0]);
      AfficherImage(25);
      CopierImage(&rouge[0]);
      AfficherImage(25);
    }
 
    for (l=2;l<=16;l+=2){
      CopierImage(&coeur[l]);
      AfficherImage(20);
    }
    AfficherImage(100);
    for (i=0;i<5;i++){
      AfficherBalayageGauche(VERT,i);
      AfficherBalayageDroite(ROUGE,i);
    }
    AfficherSpirale(VERT,50);
    AfficherSpirale(ROUGE,10);
    AfficherSpirale(JAUNE,5);
    AfficherSpirale(NOIR,1);
  }

  //-------------------------------------------------------------
  // Programme principal (là où le PIC va démarrer)
  //-------------------------------------------------------------
  void main(void) {
    Setup();
    while(1) {
      Loop();
    }
  }

Affichage d'images variables, avec utilisation d'un timer[modifier | modifier le wikicode]

Ce programme ressemble au précédent, mais fait usage d'un timer

 //------------------------------------------------------------------------------------------
 // Programme de démonstration qui affiche une image sur le Bico64
 //------------------------------------------------------------------------------------------


 #define __16F887
 #include <pic16f887.h>

 //------------------------------------------------------------------------------------------
 // Configuration du PIC 16F884 selon Bico64
 //------------------------------------------------------------------------------------------
 __code __at _CONFIG1 unsigned int Config1 =
    _INTOSCIO  // I/O function on RA6/OSC2/CLKOUT pin, I/O function on RA7/OSC1/CLKIN
  & _WDT_OFF   // pas de Watch Dog
  & _PWRTE_ON  // on attend un peu au démarrage
  & _MCLRE_ON  // RE3/MCLR pin function is MCLR
  & _CP_OFF    // Program memory code protection is disabled
  & _CPD_OFF   // Data memory code protection is disabled
  & _BOR_OFF   // BOR Disabled
  & _IESO_OFF  // Internal/External Switchover mode is disabled
  & _FCMEN_OFF // Fail-Safe Clock Monitor is disabled
  & _LVP_OFF   // RB3 pin is digital I/O, HV on MCLR must be used for programming
  & _DEBUG_OFF;// In-Circuit Debugger disabled, RB6/ICSPCLK and RB7/ICSPDAT are general purpose I/O pins

 __code __at _CONFIG2 unsigned int Config2 =
    _WRT_OFF // No prog memmory write protection
  & _BOR21V;  // Brown-Out Reset at 2.1V

 //-------------------------------------------------------------
 // Initialisation
 //-------------------------------------------------------------
 // on donne des noms significatifs aux PORTs utilisés
 #define byte unsigned char
 #define PLIGNE PORTB
 #define PVERT  PORTC
 #define PROUGE PORTD

 void Setup(void) {
   TRISB = 0x00;       // PortB est en sortie
   TRISC = 0x00;       // PortC est en sortie
   TRISD = 0x00;       // PortD est en sortie
   TRISA = 0xFF;       // PortA est en entrée

   OPTION_REG = 0b11000000; //1   Pas de pull-up pour le portB,
                            //1   interrupt rising edge of INT
                            //0   Timer0 utilise l'internal instruction clock
                            //0   incrément low-to-high de T0CKI (innutile dans ce cas)
                            //0   Prescaler utilisé pour le timer0
                            //000 Prescaler divise par 2  (==> 8Mhz / 4 /2 = un incrément toutes les 1us
   TMR0 = 0;
   T0IF = 0;
 }

 byte image[16];

 __code byte coeur[16] = {
   //  Vert      Rouge          PLIGNE
   0b11111111,0b00000000,      // D0
   0b10011001,0b01100110,      // D1
   0b00000000,0b11111111,      // D2
   0b00000000,0b11111111,      // D3
   0b10000001,0b01111110,      // D4
   0b11000011,0b00111100,      // D5
   0b11100111,0b00011000,      // D6
   0b11111111,0b00000000,      // D7
 };
 __code byte pique[16] = {
   //  Vert      Rouge
   0b00011000,0b00011000,
   0b00111100,0b00111100,
   0b01111110,0b01111110,
   0b11111111,0b11111111,
   0b11111111,0b11111111,
   0b01011010,0b01011010,
   0b00011000,0b00011000,
   0b00111100,0b00111100,
 };
 __code byte rouge[16] = {
   //  Vert      Rouge
   0b00000000,0b11111111,
   0b00000000,0b11111111,
   0b00000000,0b11111111,
   0b00000000,0b11111111,
   0b00000000,0b11111111,
   0b00000000,0b11111111,
   0b00000000,0b11111111,
   0b00000000,0b11111111,
 };
 __code byte noir[16] = {
   //  Vert      Rouge
   0b00000000,0b00000000,
   0b00000000,0b00000000,
   0b00000000,0b00000000,
   0b00000000,0b00000000,
   0b00000000,0b00000000,
   0b00000000,0b00000000,
   0b00000000,0b00000000,
   0b00000000,0b00000000,
 };

 void CopierImage(byte *newImage){
   byte i;
   for (i=0;i<16;i++){
     image[i] = *newImage;
     newImage++;
   }
 }

 void EffacerImage(void) {
   byte i;
   for (i=0;i<16;i++){
     image[i] = 0;
   }
 }


 #define NOIR  0
 #define VERT  1
 #define ROUGE 2
 #define JAUNE 3

 void MettrePixel(byte col,byte ligne, byte couleur){
   byte BitCol = 0b00000001 << col;

   if (couleur & VERT) {
     image[ligne*2] = image[ligne*2] | BitCol;
   }
   else {
     image[ligne*2] = image[ligne*2] & ~BitCol;
   };
   if (couleur & ROUGE) {
     image[ligne*2+1] = image[ligne*2+1] | BitCol;
   }
   else {
     image[ligne*2+1] = image[ligne*2+1] & ~BitCol;
   }
 }

 void AfficherImage(int temps) {
 //-------------------------------------------------------------
 // On affiche l'image "temps" fois si temps vaut 1,
 // la procedure AfficherImage dure 1ms
 // donc si on écrit AfficherImage(1000) cela prendra 1s
 //-------------------------------------------------------------
    int n;
    byte ligne;
    byte *p;                       //p pointe sur le premier byte du tableau image

    for (n=0;n<temps;n+=2){
      p = &image[0];
      ligne = 0b11111110;          // dans Ligne, on aura la ligne active à 0; on décalera le 0 pour chaque ligne
      while (ligne != 0b11111111){ // tant qu’il reste un 0, on n'a pas terminé de balayer l'image
        while (T0IF==0){
        };          // attend que le timer0 soit arrivé au bout

        TMR0 = 6;                 // on remet le timer à 250us : -250 = 6 sur un byte; le compteur comptera de 6 à 256
        T0IF = 0;
        PLIGNE = 0b11111111;       // pour éviter de voir des petits "phantomes" de la ligne précédente
                                   // on ne sélectionne aucune ligne
        PVERT  = *p++;             // on met les bits pour la couleur Rouge
        PROUGE = *p++;             // on met les bits pour la couleur Verte
        PLIGNE = ligne;            // on met la ligne (le bon bit à 0)
        ligne = (ligne << 1) +1 ;  // on décale le bit à 0 de un bit, comme cela met D0 à 0, on
                                   // force D0 à 1 pour n'avoir qu'un bit à 0 (ligne active)
      }
    }
 }


 void AfficherSpirale(byte couleur,byte temps){
 //-------------------------------------------------------------
 // On affiche une spirale qui tourne de manière anti-horaire de
 // l'exterieur vers l'intérieur. D'une couleur donnée
 // Temps est le nombre de fois 1ms pour afficher un point:
 // comme il y a 64 Led, AffichierSpirale(100) met 640ms pour faire la spirale
 //-------------------------------------------------------------
   short c=0,l=0;
   byte rangee;

   for (rangee=0;rangee<=3;rangee++) {
     for (c=rangee;c<=7-rangee;c++){
       MettrePixel(c,l,couleur);
       AfficherImage(temps);
     }
     c--;
     for (l=rangee+1;l<=7-rangee;l++){
       MettrePixel(c,l,couleur);
       AfficherImage(temps);
     }
     l--;
     for (c=7-1-rangee;c>=rangee;c--){
       MettrePixel(c,l,couleur);
       AfficherImage(temps);
     }
     c++;
     for (l=7-1-rangee;l>=rangee+1;l--){
       MettrePixel(c,l,couleur);
       AfficherImage(temps);
     }
     l++;
   }
 }

 void AfficherBalayageGauche(byte couleur,byte temps){
 //-------------------------------------------------------------
 // On balaie de droite à gauche avec une couleur donnée
 // Temps est le nombre de fois 1ms pour afficher un point:
 // comme il y a 64 Led, AffichierSpirale(100) met 640ms pour faire le balayage
 //-------------------------------------------------------------
   short c=0,l=0;
   for (c=0;c<=7;c++){
     for (l=0;l<=7;l++){
        MettrePixel(c,l,couleur);
        AfficherImage(temps);
     }
   }
 }

 void AfficherBalayageDroite(byte couleur,byte temps){
 //-------------------------------------------------------------
 // On balaie de droite à gauche avec une couleur donnée
 // Temps est le nombre de fois 1ms pour afficher un point:
 // comme il y a 64 Led, AffichierSpirale(100) met 640ms pour faire le balayage
 //-------------------------------------------------------------
   short c=0,l=0;
   for (c=7;c>=0;c--){
     for (l=0;l<8;l++){
        MettrePixel(c,l,couleur);
        AfficherImage(temps);
     }
   }
 }

/*
Pour les débutants: commencez par modifier ce bout de programme
.*/
 void Loop(void) {
 //-------------------------------------------------------------
 // La boucle principale
 //-------------------------------------------------------------
   int i;
   byte l;

   EffacerImage();
   AfficherSpirale(VERT,1);
   AfficherSpirale(JAUNE,2);
   AfficherSpirale(ROUGE,3);
  
   for (i=0; i<10; i++){
     CopierImage(&noir[0]);
     AfficherImage(25);
     CopierImage(&rouge[0]);
     AfficherImage(25);
   }

   for (l=2;l<=16;l+=2){
     CopierImage(&coeur[l]);
     AfficherImage(20);
   }
   AfficherImage(100);
   for (i=0;i<5;i++){
     AfficherBalayageGauche(VERT,i);
     AfficherBalayageDroite(ROUGE,i);
   }
   AfficherSpirale(VERT,50);
   AfficherSpirale(ROUGE,10);
   AfficherSpirale(JAUNE,5);
   AfficherSpirale(NOIR,1);
 }

 //-------------------------------------------------------------
 // Programme principal (là où le PIC va démarrer)
 //-------------------------------------------------------------
 void main(void) {
   Setup();
   while(1) {
     Loop();
   }
 }

Liens utiles[modifier | modifier le wikicode]

Architecture des PICS [5]

Un livre Développement sur PIC avec SDCC de Jean-Pierre Mandon introduit bien l'environnement SDCC. C'est lui qui m'a donné l’idée d’utiliser Context comme éditeur. Par contre ses exemples sont fait pour un PIC 18Fxxxx

Du même auteur site pour faire ses premiers pas