« Utiliser les PIC 16F et 18F/Exercices/Interruption timer0 en langage C » : différence entre les versions

Contenu supprimé Contenu ajouté
m Robot : Remplacement de texte automatisé (-resp\. +respectivement)
m Robot : remplacement de texte automatisé (-(<|</)source([ \t>]) +\1syntaxhighlight\2)
 
Ligne 12 :
 
Un [[w:PIC_16F84_de_Microchip|PIC16F84]] est enfoui dans un [[w:FPGA|FPGA]]. Sa seule particularité est de fonctionner à {{Unité|50|{{abréviation|Mhz|mégahertz}}}} contre 10 (respectivement {{Unité|20|{{abréviation|Mhz|mégahertz}}}}) de fréquence maximale d'horloge pour les PIC 16F84 (respectivement 16F84A). Il exécute le programme suivant (écrit avec le compilateur Hitech C) :
<sourcesyntaxhighlight lang="c">
//#include <pic1684.h>
#include <htc.h> //A changer si autre compilateur
Ligne 39 :
T0IF = 0; // acquittement interruption
}
</syntaxhighlight>
</source>
Remarquez comment est écrit une interruption avec ce compilateur.
 
Ligne 53 :
 
5°) Le programme suivant est donné comme exemple du compilateur MikroC et tourne dans un PIC 16F84 qui a un quartz de {{Unité|4|{{abréviation|Mhz|mégahertz}}}}.
<sourcesyntaxhighlight lang="c">
unsigned cnt;
void interrupt() {
Ligne 82 :
} while(1);
}
</syntaxhighlight>
</source>
Quelle est la fréquence de clignotement des LEDs reliées au '''PORTB''' ?
 
Ligne 89 :
{{Solution|contenu=
1°) Pas grand chose de changé :
<sourcesyntaxhighlight lang="c">
void interrupt decalage(void) {
nb++;
Ligne 111 :
}
}
</syntaxhighlight>
</source>
2°) Je l'ai réalisé dans un {{Abréviation|FPGA|Field Programmable Gate Array|en}} et à vue de nez la fréquence est entre 5 et {{Unité|10|{{abréviation|Hz|hertz}}}}.
 
Ligne 121 :
 
Comme la division se fait par 16 qui est une puissance de deux, on peut utiliser un masque pour faire ce calcul bien plus rapidement :
<sourcesyntaxhighlight lang="c">
// langage C
if (!(nb & 0x0F)) // idem à if (!(nb % 16)) mais plus rapide
</syntaxhighlight>
</source>
4°) Décalage tout simple d'une LED vers les poids forts.
 
Ligne 136 :
 
6°)
<sourcesyntaxhighlight lang="c">
#include <pic1684.h>
//#include <htc.h> serait-il mieux ?
Ligne 163 :
T0IF = 0; // acquittement interruption
}
</syntaxhighlight>
</source>
}}
Ligne 175 :
 
2°) réaliser une fonction responsable du transcodage :
<sourcesyntaxhighlight lang="c">
unsigned char Display(unsigned char no) {
unsigned char Pattern;
unsigned char SEGMENT[] = {0x3F,....
</syntaxhighlight>
</source>
3°) Réaliser le programme main() responsable de l'initialisation de l'interruption qui doit avoir lieu toutes les 10ms (avec un quartz de {{Unité|4|{{abréviation|Mhz|mégahertz}}}}) et qui compte de 00 à 99 toutes les secondes environ (avec un "Delay_ms(1000);")
 
Ligne 190 :
* etc etc
Soit en final :
<sourcesyntaxhighlight lang="c">
unsigned char SEGMENT[] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
</syntaxhighlight>
</source>
2°)
<sourcesyntaxhighlight lang="c">
unsigned char Display(unsigned char no) {
unsigned char Pattern;
Ligne 201 :
return Pattern;
}
</syntaxhighlight>
</source>
ou encore
<sourcesyntaxhighlight lang="c">
unsigned char Display(unsigned char no) {
//unsigned char Pattern;
Ligne 209 :
return SEGMENT[no];
}
</syntaxhighlight>
</source>
3°) Pour bien faire, le comptage doit se faire en BCD. Cela peut se faire avec :
<sourcesyntaxhighlight lang="c">
nb++;
// gérer le problème des unités
Ligne 217 :
// gérer le problème des dizaines
if ((((nb &0xF0) > 0x90) nb = 0;
</syntaxhighlight>
</source>
Les compilateurs C compilent cela certainement de manière peu optimisée. Il faut savoir qu’il existe un bit "half carry" dans le registre '''Status''' qui permet certainement d'optimiser, mais nous laissons tomber ce genre de détail.
 
Pour la période de l'interruption, on part de la fréquence quartz divisée par 4 soit : {{Unité|1|{{abréviation|Mhz|mégahertz}}}} qu’il faut diviser par {{formatnum:10000}} pour avoir une période d'overflow de 10 ms. Le timer gère une division par 256 qu'on peut ramener à 250 en l'initialisant à 6 mais il nous reste à réaliser une division par 40 qui n’est pas une puissance de 2. On va prendre une division par 64 et 10000 / 64 = 156,25 donc notre timer0 sera initialisé à 256-156 = 100.
<sourcesyntaxhighlight lang="c">
//****** Mikro C ********
unsigned char nb,mux;
Ligne 242 :
}
}
</syntaxhighlight>
</source>
4°)
<sourcesyntaxhighlight lang="c">
void interrupt(void) {
TMR0 = 100;
Ligne 255 :
INTCON.T0IF = 0; // clear TMR0IF
}
</syntaxhighlight>
</source>
Cette façon de faire (division par 10 et reste de la division par 10) est utile si nb n’est pas en BCD, or nous avons présenté dans le main une incrémentation qui veille à laisser nb en BCD ! On peut donc renplacer cette interruption par :
<sourcesyntaxhighlight lang="c">
void interrupt(void) {
TMR0 = 100;
Ligne 269 :
}
ce qui est bien plus efficace pour un code d'interruption.
</syntaxhighlight>
</source>
}}