143 371
modifications
m (Robot : Remplacement de texte automatisé (-resp\. +respectivement)) |
m (Robot : remplacement de texte automatisé (-(<|</)source([ \t>]) +\1syntaxhighlight\2)) |
||
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) :
<
//#include <pic1684.h>
#include <htc.h> //A changer si autre compilateur
T0IF = 0; // acquittement interruption
}
</syntaxhighlight>
Remarquez comment est écrit une interruption avec ce compilateur.
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}}}}.
<
unsigned cnt;
void interrupt() {
} while(1);
}
</syntaxhighlight>
Quelle est la fréquence de clignotement des LEDs reliées au '''PORTB''' ?
{{Solution|contenu=
1°) Pas grand chose de changé :
<
void interrupt decalage(void) {
nb++;
}
}
</syntaxhighlight>
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}}}}.
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 :
<
// langage C
if (!(nb & 0x0F)) // idem à if (!(nb % 16)) mais plus rapide
</syntaxhighlight>
4°) Décalage tout simple d'une LED vers les poids forts.
6°)
<
#include <pic1684.h>
//#include <htc.h> serait-il mieux ?
T0IF = 0; // acquittement interruption
}
</syntaxhighlight>
}}
2°) réaliser une fonction responsable du transcodage :
<
unsigned char Display(unsigned char no) {
unsigned char Pattern;
unsigned char SEGMENT[] = {0x3F,....
</syntaxhighlight>
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);")
* etc etc
Soit en final :
<
unsigned char SEGMENT[] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
</syntaxhighlight>
2°)
<
unsigned char Display(unsigned char no) {
unsigned char Pattern;
return Pattern;
}
</syntaxhighlight>
ou encore
<
unsigned char Display(unsigned char no) {
//unsigned char Pattern;
return SEGMENT[no];
}
</syntaxhighlight>
3°) Pour bien faire, le comptage doit se faire en BCD. Cela peut se faire avec :
<
nb++;
// gérer le problème des unités
// gérer le problème des dizaines
if ((((nb &0xF0) > 0x90) nb = 0;
</syntaxhighlight>
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.
<
//****** Mikro C ********
unsigned char nb,mux;
}
}
</syntaxhighlight>
4°)
<
void interrupt(void) {
TMR0 = 100;
INTCON.T0IF = 0; // clear TMR0IF
}
</syntaxhighlight>
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 :
<
void interrupt(void) {
TMR0 = 100;
}
ce qui est bien plus efficace pour un code d'interruption.
</syntaxhighlight>
}}
|