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

Une page de Wikiversité, la communauté pédagogique libre.
Contenu supprimé Contenu ajouté
m Robot : Remplacement de texte automatisé (-qu'il +qu’il)
m Robot : Remplacement de texte automatisé (- n'est pas + n’est pas , - Aujourd'hui + Aujourd’hui , - d'euros + d’euros , - d'agir + d’agir , - l'apparence + l’apparence ); changements de type cosmétique
Ligne 116 : Ligne 116 :
N'oubliez pas la division par 16 qui est réalisée avec le if (!(nb % 16)) dans l'interruption.
N'oubliez pas la division par 16 qui est réalisée avec le if (!(nb % 16)) dans l'interruption.


<u>Calcul précis</u> : {{Unité|50|{{abréviation|Mhz|mégahertz}}}} / 4*(256*256*16) = {{Unité|11.92|{{abréviation|Hz|hertz}}}} (la division par 4 a toujours lieu).
<u>Calcul précis</u> : {{Unité|50|{{abréviation|Mhz|mégahertz}}}} / 4*(256*256*16) = {{Unité|11.92|{{abréviation|Hz|hertz}}}} (la division par 4 a toujours lieu).


3°) "if (!(nb % 16))" est une façon pas très efficace de calculer le reste de la division par 16. J'ignore la technique utilisé par le compilateur, mais ce calcul est forcément long puisqu’il n'y a pas d'instruction de division sur le 16F84.
3°) "if (!(nb % 16))" est une façon pas très efficace de calculer le reste de la division par 16. J'ignore la technique utilisé par le compilateur, mais ce calcul est forcément long puisqu’il n'y a pas d'instruction de division sur le 16F84.
Ligne 129 : Ligne 129 :
5°) OPTION_REG = 0x84; = 1000 0100 => poids faible = 4 => division par 2 puissance 5 = 32
5°) OPTION_REG = 0x84; = 1000 0100 => poids faible = 4 => division par 2 puissance 5 = 32


{{formatnum:4000000}} / 4*32*(256-96)*400 = {{Unité|0.48828|{{abréviation|Hz|hertz}}}} Soit pratiquement {{Unité|0.5|{{abréviation|Hz|hertz}}}}
{{formatnum:4000000}} / 4*32*(256-96)*400 = {{Unité|0.48828|{{abréviation|Hz|hertz}}}} Soit pratiquement {{Unité|0.5|{{abréviation|Hz|hertz}}}}


Un meilleur calcul serait :
Un meilleur calcul serait :


{{formatnum:4000000}} / 4*32*(256-94)*400 = {{Unité|0.482253086|{{abréviation|Hz|hertz}}}} (à cause des temps de latence) Cette connaissance n'est pas demandée aux étudiants.
{{formatnum:4000000}} / 4*32*(256-94)*400 = {{Unité|0.482253086|{{abréviation|Hz|hertz}}}} (à cause des temps de latence) Cette connaissance n’est pas demandée aux étudiants.


6°)
6°)
<source lang="c">
<source lang="c">
#include <pic1684.h>
#include <pic1684.h>
//#include <htc.h> serait-il mieux ?
//#include <htc.h> serait-il mieux ?
void interrupt decalage(void);
void interrupt decalage(void);
Ligne 168 : Ligne 168 :


== Exercice 2 ==
== Exercice 2 ==
Une partie matérielle est constituée de deux afficheurs sept segments multiplexés. Les sept segments sont commandés par le '''PORTC''', tandis que les commandes d'affichages sont réalisée par les bits b0 et b1 du '''PORTB'''. Un schéma de principe est donné ci-après.
Une partie matérielle est constituée de deux afficheurs sept segments multiplexés. Les sept segments sont commandés par le '''PORTC''', tandis que les commandes d'affichages sont réalisée par les bits b0 et b1 du '''PORTB'''. Un schéma de principe est donné ci-après.


[[Fichier:Afficheurs7seg.png|thumb|500px|Comment utiliser deux afficheurs multiplexés]]
[[Fichier:Afficheurs7seg.png|thumb|500px|Comment utiliser deux afficheurs multiplexés]]


1°) A l'aide de la documentation calculer les valeurs dans un tableau "unsigned char SEGMENT[] = {0x3F,...};" pour un affichage des chiffres de 0 à 9.
1°) A l'aide de la documentation calculer les valeurs dans un tableau "unsigned char SEGMENT[] = {0x3F,...};" pour un affichage des chiffres de 0 à 9.


2°) réaliser une fonction responsable du transcodage :
2°) réaliser une fonction responsable du transcodage :
Ligne 185 : Ligne 185 :


{{Solution|contenu=
{{Solution|contenu=
1°) 0x3F est 0011 1111 sur un affichage xgfe dcba ce qui allume les segments fedcba affiche donc un 0 et nous donne en même temps la marche à suivre.
1°) 0x3F est 0011 1111 sur un affichage xgfe dcba ce qui allume les segments fedcba affiche donc un 0 et nous donne en même temps la marche à suivre.
* 1 <-> xgfe dcba = 0000 0110 = 0x06
* 1 <-> xgfe dcba = 0000 0110 = 0x06
* 2 <-> xgfe dcba = 0101 1011 = 0x5B
* 2 <-> xgfe dcba = 0101 1011 = 0x5B
Ligne 220 : Ligne 220 :
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.
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.
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.
<source lang="c">
<source lang="c">
//****** Mikro C ********
//****** Mikro C ********
Ligne 256 : Ligne 256 :
}
}
</source>
</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 :
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 :
<source lang="c">
<source lang="c">
void interrupt(void) {
void interrupt(void) {

Version du 18 mai 2016 à 20:01

Interruption timer0 en langage C
Image logo représentative de la faculté
Exercices no8
Leçon : Utiliser les PIC 16F et 18F
Chapitre du cours : Interruption timer0 en langage C

Exercices de niveau 15.

Exo préc. :Le Timer0 des 16FXXX et le langage C
Exo suiv. :Le mode comparaison du module CCP (Capture Compare PWM)
En raison de limitations techniques, la typographie souhaitable du titre, « Exercice : Interruption timer0 en langage C
Utiliser les PIC 16F et 18F/Exercices/Interruption timer0 en langage C
 », n'a pu être restituée correctement ci-dessus.




Exercice 1 (Hitech C et Mikro C)

Si vous voulez savoir comment est réalisé pratiquement ce qui est décrit dans cet exercice, visitez le chapitre Embarquer un PIC 16F84 d'un autre livre.

Un PIC16F84 est enfoui dans un FPGA. Sa seule particularité est de fonctionner à 50 Mhz contre 10 (resp. 20 Mhz) de fréquence maximale d'horloge pour les PIC 16F84 (resp. 16F84A). Il exécute le programme suivant (écrit avec le compilateur Hitech C) :

//#include <pic1684.h>
#include <htc.h> //A changer si autre compilateur
void interrupt decalage(void); //A changer si autre compilateur
unsigned char nb; 
main(void) { 
  TRISA = 0xF9; // 6 entrees, 2 sorties pour A 
  TRISB = 0x00; // 8 sorties pour B 
  OPTION = 0x07; // prescaler 256 , entree sur quartz (A changer si autre compilateur : OPTION_REG)
  INTCON = 0xA0;  // autorise l'interruption timer 
  PORTB = 0x01; // une seule diode allumee		 
  TMR0 = 0x00 ; 
  nb=0; 
  while(1) { 
   // on ne fait rien que recopier sur 2 segments la valeur de SW1 
      if ((PORTA & 0x01) == 1) PORTA = 0x06; 
    } 
} 

void interrupt decalage(void) { //A changer si autre compilateur
  nb++; 
  //TMR0 = 0x00; //c'est fait car ici par overflow
  if (!(nb % 16)) 
  PORTB = (PORTB << 1) ; 
  if (PORTB == 0x00)   PORTB = 0x01; 
  T0IF = 0;  // acquittement interruption 
}

Remarquez comment est écrit une interruption avec ce compilateur.

1°) Repérer et modifier les lignes de ce programmes pour qu’il fonctionne avec le compilateur MikroC.

2°) Calculer si le chenillard réalisé par ce programme est visible à l'œil humain (fréquence de changement de position des LEDs inférieure à 20 Hz).

3°) Comment peut-on écrire l'instruction "if (!(nb % 16))" pour plus d'efficacité.

4°) Quelle est la suite des états (LEDs allumées) réalisée par ce programme.

Les deux questions suivantes sont issues du Devoir Surveillé de juin 2010.

5°) Le programme suivant est donné comme exemple du compilateur MikroC et tourne dans un PIC 16F84 qui a un quartz de 4 Mhz.

unsigned cnt; 
void interrupt() { 
  if (TMR0IF_bit) { 
    cnt++;                 // increment counter 
    TMR0IF_bit = 0;        // clear TMR0IF 
    TMR0   = 96; 
  } 
} 

void main() { 
  OPTION_REG = 0x84;       // Assign prescaler to TMR0 
  ANSEL  = 0;              // Configure AN pins as digital 
  ANSELH = 0; 
  C1ON_bit = 0;            // Disable comparators 
  C2ON_bit = 0; 
  TRISB = 0;               // PORTB is output 
  PORTB = 0xFF;            // Initialize PORTB 
  TMR0  = 96;              // Timer0 initial value 
  INTCON = 0xA0;           // Enable TMRO interrupt 
  cnt = 0;                 // Initialize cnt 

  do { 
    if (cnt >= 400) { 
      PORTB = ~PORTB;      // Toggle PORTB LEDs 
      cnt = 0;             // Reset cnt 
    } 
  } while(1); 
}

Quelle est la fréquence de clignotement des LEDs reliées au PORTB ?

6°) Modifier l'interruption (du programme de départ) pour qu'elle réalise un chenillard d'une LED se déplaçant vers les poids faibles.

Exercice 2

Une partie matérielle est constituée de deux afficheurs sept segments multiplexés. Les sept segments sont commandés par le PORTC, tandis que les commandes d'affichages sont réalisée par les bits b0 et b1 du PORTB. Un schéma de principe est donné ci-après.

Comment utiliser deux afficheurs multiplexés

1°) A l'aide de la documentation calculer les valeurs dans un tableau "unsigned char SEGMENT[] = {0x3F,...};" pour un affichage des chiffres de 0 à 9.

2°) réaliser une fonction responsable du transcodage :

unsigned char Display(unsigned char no) { 
    unsigned char Pattern; 
    unsigned char SEGMENT[] = {0x3F,....

3°) Réaliser le programme main() responsable de l'initialisation de l'interruption qui doit avoir lieu toutes les 10ms (avec un quartz de 4 Mhz) et qui compte de 00 à 99 toutes les secondes environ (avec un "Delay_ms(1000);")

4°) Réaliser enfin l'interruption qui affichera tantôt les dizaines, tantôt les unités.