Vous êtes sur la page 1sur 16

Travaux dirigé N° 5

Générateur de signaux PWM - ADC


I. Génération d’un signal PWM

Exercice 1 :
1. Pour générer correctement le signal PWM sur CCP1 ou CCP2, préciser dans le bon ordre les
étapes qui doivent être exécutées.

a) Fixer la période de la PWM en configurant PR2


b) Fixer le duty cycle en configurant CCPRxL et les bits 4 et 5 du registre CCPxCON
c) Configurer la broche CCPx en sortie
d) Configurer la valeur du pré-diviseur du timer 2 et démarrer le timer 2
e) Configurer le module CCPx pour fonctionner en mode PWM, ceci se fait en mettant
les bits 2 et 3 du registre CCPxCON à 1.

2. Est-il possible d’utiliser le Timer 1 pour configurer la PWM sur CCP1 et Timer 3 sur CCP2.
Seul le Timer 2 est associé au module PWM sur CCP1 ou CCP2.

3. Le microcontrôleur dispose d’un registre appelé IPR2. Est-ce qu’il peut remplacer PR2 et
remplir la même fonction.
Le module PWM est associé au registre PR2, CCPxCON,CCPRxL mais pas IPR2 qui n’a
aucun rapport avec le module PWM.

4. En consultant la documentation technique, est-ce que la résolution de la PWM est fixe ?


La résolution du signal PWM n’est pas fixe. Elle dépend de la fréquence dusignal
d’oscillateur et de la fréquence du signal PWM à générer.

5. Quelle est la résolution maximale de la PWM.


La résolution maximale du signal PWM est égale à 10 bits.
6. Donner l’expression de la résolution (en bits) en fonction de Fosc et FPWM.
La résolution de la PWM est donnée par :
𝑅é𝑠𝑜𝑙𝑢𝑡𝑖𝑜𝑛𝑀𝑎𝑥=𝑙𝑜𝑔F𝑜𝑠𝑐𝐹𝑃𝑊𝑀𝑙𝑜𝑔2 𝑏𝑖𝑡𝑠

7. On donne Fosc = 40MHz. Compléter le tableau suivant :

FPWM 2,44 kHz 9,77 kHz 39,06 kHz 156,25 kHz 312,50 kHz 416,67 kHz

Timer Prescaler (1 ; 4 ; 16) 16 4 1 1 1 1

Valeur PR2 255 255 255 63 31 23

Résolution maximale (bits) 10 10 10 8 7 6,58

Exercice 2 :
On donne :
• Fosc=20Mhz
• FPWM=2Khz
• Rapport cyclique (duty cycle)= 40% →= 0,4
• Module à utiliser :RB3/CCP2

1. Déterminer la valeur de PR2 et du pré diviseur Nps.

1
TPWM=[(PR2)+1]*4*Tosc*Nps

On commence par la valeur du pré-diviseur Nps = 1

TPWM Fo𝑠𝑐
PR2 = ( )−1=( )−1
4 ∗ Tosc ∗ Nps 4 ∗ FPWM ∗ Nps

20. 106
PR2 = ( ) − 1 = 2499 > 255
4 ∗ 2000 ∗ 1

On prend Nps=4

Fo𝑠𝑐 20. 106


PR2 = ( )−1 =( ) − 1 = 624 > 255
4 ∗ FPWM ∗ Nps 4 ∗ 2000 ∗ 4

On prend Nps=16

Fo𝑠𝑐 20. 106


PR2 = ( )−1 =( ) − 1 = 155,25 < 255
4 ∗ FPWM ∗ Nps 4 ∗ 2000 ∗ 16

𝑁𝑝𝑠 = 16
Par conséquent : {
𝑃𝑅2 = 155

2. On pose Y= ( CCPR2L CCP2CON <5 :4>) .


Déterminer l’expression de Y en fonction de 
𝑇𝑂𝑁 𝜏
On a : = = ⇒𝜏 = 𝛼 ∗ 𝑇𝑃𝑊𝑀
TPWM TPWM

On a :  = (CCPRxL :CCPxCON<5 :4>)* Tosc*Nps=Y* Tosc*Nps

𝜏 𝛼 ∗ 𝑇𝑃𝑊𝑀 𝛼 ∗ [(PR2) + 1] ∗ 4 ∗ Tosc ∗ Nps


𝑌= = = = 4 ∗ 𝛼 ∗ [(PR2) + 1]
Tosc ∗ Nps Tosc ∗ Nps Tosc ∗ Nps

3. Déterminer la valeur de Y en décimal puis en binaire naturel sur 10 bits.

𝑌 = 4 ∗ 𝛼 ∗ [(PR2) + 1] = 4 ∗ 0,4 ∗ (155 + 1) = 249,6

On prend la valeur la plus proche par excès Y=250=(00 1111 1010)2.

𝜏 𝛼∗𝑇𝑃𝑊𝑀 𝛼∗Fosc 0,4∗20.106


On vérifie que : 𝑌 = Tosc ∗Nps
=T =𝐹 = = 250
osc ∗Nps 𝑃𝑊𝑀 ∗Nps 2000∗16

4. En déduire la valeur de CCPR2L, DC2B1 et DC2B0.

𝐶𝐶𝑃𝑅2𝐿 = 0011 1110


Par conséquent {
𝐷𝐶2𝐵1 = 1; 𝐷𝐶2𝐵0 = 0

2
5. Développer un programme en langage C permettant de générer le signal PWM.

#define _XTAL_FREQ 20000000


#include <xc.h>
main()
{
PR2=155;
CCPR1L=0b00111110;
CCP2CONbits.DC2B0=0; CCP2CONbits.DC2B1=1;
TRISB3=0; //configuration de RB3/CCP2 en sortie
T2CON=0b0000 0110; // Nps = 16 TMR2ON = 1
CCP2CONbits.CCP2M2=1; CCP12CONbits.CCP2M3=1; // Configuration en mode PWM

while(1);
{
}
}

Exercice 3:
Le signal de la figure suivante représente la valeur moyenne d’un signal PWM qu’on désire générer.

Figure-1
• La durée des paliers est fixée par le timer2 (en utilisant le postscaler)
• L’amplitude des paliers est fixée par le module PWM

PARTIE I : PWM avec rapport cyclique fixe


On donne :
• Fosc=22Mhz.
• FPWM=8Khz
1. Déterminer PR2 pour avoir la fréquence FPWM désirée.

On commence par la valeur du pré-diviseur Nps = 1

TPWM Fo𝑠𝑐
PR2 = ( )−1=( )−1
4 ∗ Tosc ∗ Nps 4 ∗ FPWM ∗ Nps
22. 106
PR2 = ( ) − 1 = 686.5 > 255
4 ∗ 8000 ∗ 1

On prend Nps=4

Fo𝑠𝑐 22. 106


PR2 = ( )−1 =( ) − 1 = 170,875 < 255
4 ∗ FPWM ∗ Nps 4 ∗ 8000 ∗ 4

3
Par conséquent : Nps = 4 et PR2=171

Si on désigne par Y la variable formée par le registre CCPR1L et les bits DC1B0 et DC1B1 :
2. Déterminer Y pour avoir le palier d’amplitude 0.5V.

Pour avoir le palier d’amplitude 0,5V c’est l’équivalent de générer un signal PWM de rapport
0.5
cyclique 𝛼 = 5 = 0,1

𝑇𝑂𝑁 𝜏 0,1 0,1


On a : = TPWM
= T ⇒𝜏 = 𝛼 ∗ 𝑇𝑃𝑊𝑀 = 𝐹 = 8000 = 12,5µ𝑠
PWM 𝑃𝑊𝑀

On a :  = (CCPRxL :CCPxCON<5 :4>)* Tosc*Nps=Y* Tosc*Nps

𝜏 12,5. 10−6 ∗ 22. 106


𝑌= = = 68,75
Tosc ∗ Nps 4

On prend la valeur la plus proche par excès : Y=69=(00 0100 0101)2.

𝐶𝐶𝑃𝑅1𝐿 = 0001 0001


Par conséquent {
𝐷𝐶1𝐵1 = 0; 𝐷𝐶1𝐵0 = 1

3. En déduire la valeur de Y pour chacun des paliers (faire un tableau).

Le signal à générer est un signal périodique de période 12ms. Chaque palier correspond à un
𝑃𝑎𝑙𝑖𝑒𝑟
signa de rapport cyclique 𝛼 = 𝑃𝐸 ; 𝑃𝐸 = 5𝑉.
𝜏 𝛼 ∗ 𝑇𝑃𝑊𝑀 𝛼 ∗ Fosc
𝑌= = =
Tosc ∗ Nps Tosc ∗ Nps 𝐹𝑃𝑊𝑀 ∗ Nps

On définit les valeurs de Y pour chaque palier dans le tableau suivant : (Y est la valeur
entière)

Palier(V) 0 0,5 1 1,5 2 2 ,5 3


𝛼 0 0,1 0,2 0,3 0,4 0,5 0,6
Y 0 69 138 207 275 344 413

4. Déterminer T2CON.

Nps=4 → T2CON = 0b0000 0101 ;

5. Donner le programme en langage C permettant de générer un signal PWM ayant pour valeur
moyenne 2V.

Un signal de valeur moyenne 2V correspond à un signal PWM de rapport cyclique 0,4 ce qui
correspond à une valeur de Y = 275.

Y=(275)10 = (01 0001 0011)2.

4
𝐶𝐶𝑃𝑅1𝐿 = 0100 0100
Par conséquent {
𝐷𝐶1𝐵1 = 1; 𝐷𝐶1𝐵0 = 1

Le programme permettant de générer un tel signal est donné par :

#define _XTAL_FREQ 22000000


#include <xc.h>

#include<xc.h>
#include <pic18f4520.h>
main()
{
PR2=171;
CCPR1L=0b0100 0100;
CCP1CONbits.DC1B0=1;
CCP1CONbits.DC1B1=1;
TRISC2=0;
T2CON=0b0000 0101; // Nps = 4 ; TMR2ON = 1
CCP1CONbits.CCP1M2=1;
CCP1CONbits.CCP1M3=1;
while(1);
{
}
}

PARTIE II : PWM avec mise à jour du rapport cyclique


On donne Fosc=22Mhz.
On veut que la mise à jour du rapport cyclique se fait chaque Te=8.TPWM soit chaque Te=1ms
1. Déterminer la valeur de T2CON.

Pour que le rapport cyclique soit mis à jour tous les Te = 1ms, il faut configurer le postscaler
(postdiviseur) du Timer2 de telle sorte qu’une interruption du Timer 2 aura lieu tous les 1 ms.
Etant donné la période Te = 8.TPWM , on choisit le postscaler = 8.
5
Par conséquent :T2CON = 0b0011 1101 ; on maintient la valeur de Nps=4. T2CKPS=01

2. En exploitant les valeurs de Y calculées dans la première partie, donner le tableau qu’il faut
utiliser pour la mise à jour du rapport cyclique.

Le signal à générer est un signal périodique de période 12ms.


On définit les valeurs de Y pour chaque palier dans le tableau suivant : (Y est la valeur
entière)

Palier(V) 0 0,5 1 1,5 2 2 ,5 3 2,5 2 1,5 1 0,5


Rapport
0 0,1 0,2 0,3 0,4 0,5 0,6 0,5 0,4 0,3 0,2 0,1
cyclique 
Y 0 69 138 207 275 344 413 344 275 207 138 69

3. Quels bits faut-il configurer pour exploiter le timer2 en mode interruption ?

Pour configurer le timer2 en mode interruption, il faut configurer les bits suivants :

- RCONbits IPEN = 0;

- INTCONbits.GIE = 1;

- INTCONbits.PEIE = 1;

- PIR1bits.TMR2IF = 0;

- PIE1bits.TMR2IE = 1;

Le registre T2CON est configuré de la façon suivante :

- T2CONbits.T2CKPS = 1;

- T2CONbits.T2OUTPS = 8;

- T2CONbits.TMR2ON = 1;

4. Donner le programme d’interruption permettant de mettre à jour le rapport cyclique.

#define _XTAL_FREQ 22000000


#include <xc.h>

#include<xc.h>
unsigned int temp,i=0;
void __interrupt() Timer2(void);

const unsigned int TAB_Y[12]={0,69,138,207,275,344,413,344,275,207,138,69};

void __interrupt() Timer2(void)


{
if (TMR2IF)
{
if (i>11) { i=0;}

6
CCPR1L=TAB_Y[i]>>2;
DC1B0=TAB_Y[i];
DC1B1=TAB_Y[i]>>1;
//ou bien on peut procéder par masquage de la façon suivante :
// temp=(TAB_Y[i] & 0x0003);
//CCP1CON=temp<<4;
}
i++;
PIR1bits.TMR2IF=0;
}
main()
{
PR2=171;

CCP1CON=0;

TRISC2=0;

CCP1CONbits.CCP1M2=1;
CCP1CONbits.CCP1M3=1;
RCONbits IPEN=0;
INTCONbits.GIE=1;
INTCONbits.PEIE =1;
PIR1bits.TMR2IF=0;
PIE1bits.TMR2IE=1;
T2CONbits.T2CKPS=1;
T2CONbits.T2OUTPS=8;
T2CONbits.TMR2ON=1;
while(1);
{
}

II. Convertisseur A/N :


Exercice 4 :
1. Parmi le nombre des bits suivants, lequel des convertisseurs présente la meilleure résolution ?
• 8 bits ;
• 10 bits
• 12bits
• 16 bits
La résolution augmente avec le nombre de bits (n = 16 bits).
2. Dans la question 1 lequel présente le pas de quantification q est le plus faible ?
𝑉𝑟𝑒𝑓+ − 𝑉𝑟𝑒𝑓−
𝑉𝑖𝑛 = .𝑁
2𝑛
n=16 bits

3. En prenant Vref+ = 5V, Vref- = 0V. Calculer le pas de quantification dans les cas suivants :
a) n= 8 bits

b) n=10 bits

𝑉𝑟𝑒𝑓+ −𝑉𝑟𝑒𝑓−
Le pas de quantification est défini par :𝑞 = 2𝑛 −1

7
5 5
a) 𝑞 = = = 19,6𝑚𝑉
28 −1 255

5 5
b) 𝑞 = 210 −1 = 1023 = 4,8𝑚𝑉

4. Pour Vref+ = 2,56V ; donner la valeur de la tension d’entrée Vin, qui correspond aux valeurs
numériques suivantes :
a) D7..D0 = 10111010
b) D7..D0 = 11111111

𝑉𝑟𝑒𝑓+ − 𝑉𝑟𝑒𝑓−
𝑉𝑖𝑛 = .𝑁
2𝑛
2,56−0
Pour N = 10111010 = 186 𝑉𝑖𝑛 = . 186 = 1,86𝑉
28

2,56−0
Pour N = 1111 1111 = 255 𝑉𝑖𝑛 = . 255 = 2,55𝑉
28

5. Dans quels registres est chargé le résultat de conversion. Comment peut-t-on savoir la
disponibilité de la valeur numérique.

Le résultat de conversion est chargé dans les registres ADRESH et ADRESL. Le résultat est
considéré disponible quand le bit GO revient à zéro ou bien quand le bit ADIF passe à 1.

6. Dans un ADC, que se passe-t-il, si on commence une nouvelle conversion avant de lire la
donnée précédente ?

L’ancienne donnée sera écrasée par la nouvelle.

7. Pour un microcontrôleur PIC18F4520 ; donner la valeur de la tension de référence qui donne


un pas de quantification de 2mV.

𝑉𝑟𝑒𝑓+ − 𝑉𝑟𝑒𝑓−
𝑞= ⇒ 𝑉𝑟𝑒𝑓+ − 𝑉𝑟𝑒𝑓− = 𝑞 ∗ (2𝑛 − 1) 𝑜𝑟 𝑉𝑟𝑒𝑓− = 0𝑉
2𝑛 − 1

𝑑′ 𝑜ù 𝑉𝑟𝑒𝑓+ = 0,002 ∗ 1023 = 2,046𝑉

Exercice 5 :
1. Pour un quartz de 12Mhz ; laquelle des valeurs suivantes qui correspond à la fréquence de
l’ADC.
a) Fosc/2
b) Fosc/4
c) Fosc/8
d) Fosc/16
e) Fosc/32

D’après le tableau d’assignation des bits ADCS2..0 du registre ADCON2

8
TAD = 16Tosc → FAD = Fosc/16

2. Quels sont les ports utilisés par l’ADC ?

PORTA : RA0, RA1, RA2, RA3, RA5


PORTE : RE0, RE1, RE2
PORTB : RB2, RB3, RB1, RB4, RB0

3. Dans quel registre, on désigne le nombre d’entrées analogiques ?

Les bits PCFG3..PCFG0 du registre ADCON1


4. Dans quel registre, on sélectionne la fréquence de l’ADC ?

Les bits ADCS2..ADCS0 du registre ADCON2 (voir question 8)

5. Dans quel registre, on sélectionne l’entrée à convertir ?

Les bits CHS3..CHS0 du registre ADCON0

6. Quelle est la valeur à charger dans le registre ADCON1, si on veut :


a) Vref+ = AN3,
b) Vref- = VSS ;
c) 3 entrées analogiques ?

ADCON1 = 0b00011100 = 0x1C

7. Quelle est la valeur à charger dans le registre ADCON2, si on veut Fosc/4, Tacq = 4TAD et le
résultat de conversion est justifié à gauche ?

D’après les tableaux d’assignation des bits ACQT2..0 et ADCS2..0


ADCON2 = 0b00010100 = 0x14

Exercice 6 :
On veut mesurer la température d’une serre agricole en vue d’une régulation de la température durant
l’hiver. La serre est équipée :
- d’un capteur de température qui fournit une tension analogique comprise entre 0 et
5V correspondant à une variation de 0°C à 50°C.
- d’un commutateur Marche permet la mise en service du système de chauffage.

9
- D’un potentiomètre qui fournit une tension comprise entre 0 et 5V permettant de choisir la
consigne de T°.
- D’un élément chauffant commandé avec un signal TOR issu de RB2.

Le montage des entrées/sorties est représenté à la figure suivante :

- Le signal issu du capteur de T° est acheminé vers RA1.


- Le signal issu du potentiomètre (consigne) est acheminé vers RA0.
- Le commutateur de mise en marche MA est relié à RA3.

L’ADC est configuré conformément au cahier des charges suivant :


• 𝐹𝑜𝑠𝑐 = 4𝑀𝐻𝑧
4
• 𝑇𝐴𝐷 = 𝑇𝐶𝑌 =
𝐹𝑜𝑠𝑐

• 𝑇𝑎𝑐𝑞 = 4𝑇𝐴𝐷
• 𝑉𝑅𝐸𝐹+ = 𝑉𝐷𝐷; 𝑉𝑅𝐸𝐹− = 𝑉𝑆𝑆;
• Le convertisseur est configuré en mode scrutation (sans interruption)

1. Mesure de la température et lecture de la consigne .


1.1. Déterminer la valeur de ADCON0, ADCON1 et de ADCON2.

• ADCON0 = 0000 0001 pour la mesure de la consigne


• ADCON0 = 0000 0101 pour la mesure du signal issu du capteur

• 𝑉𝑅𝐸𝐹+ = 𝑉𝐷𝐷; 𝑉𝑅𝐸𝐹− = 𝑉𝑆𝑆; → VCFG1=VCFG0=0


• RA0/AN0 et RA1/AN1 sont des entrées analogiques le restes sont utilisées comme
entrées sorties digitales → PCFG3 : PCFG0 = 1101

• Si le résultat est justifié à droite ADFM=1


10
• Si le résultat est justifié à droite ADFM=0
4
• 𝑇𝐴𝐷 = 𝑇𝐶𝑌 = 𝐹 → ADCS2: ADCS0 = 100
𝑜𝑠𝑐

• 𝑇𝑎𝑐𝑞 = 4𝑇𝐴𝐷 → ACQT2 ∶ ACQT0 = 010

On suppose qu’initialement la justification se fait à gauche (ADFM = 0)


→ ADCON2 = 0b00010100

1.2. Développer une fonction init_ADC() permettant de configurer le convertisseur A/N.

void Init()
{
ADCON0 = 0b00000001;
ADCON1 = 0b00001101;
ADCON2 = 0b00010100 ;//bit 7=0; justification à gauche// bit7=1; justification à droite
TRISA = 0xFF;// toutes les lignes du PORTA en entrée
TRISB = 0xFE;// RB0 en sortie le reste du PORTB en entrée
}

1.3. Développer une fonction read_ADC(canal) permettant de :


- Choisir le signal à convertir.
- De charger la valeur de conversion dans une variable de sortie de type int.
Considérer les deux cas de figures suivants :
- Le résultat de conversion sur 10 bits subit une justification à droite.
- Le résultat de conversion sur 10 bits subit une justification à droite.

1er cas : Le résultat de conversion sur 10 bits subit une justification à droite

int read_ADC(char Channel)


{
ADCON0 = Channel ;
ADCON0bits.GO = 1;
while( ADCON0bits.GO == 1);
return ADRES; //justification à droite
}

2ème cas : Le résultat de conversion sur 10 bits subit une justification à gauche

int read_ADC(char Channel)


{
ADCON0 = Channel ;
ADCON0bits.GO = 1;
while( ADCON0bits.GO == 1);
return ((ADRESH<<2) + (ADRESL>>6)); //justification à gauche
}

1.4. Développer le programme principal qui permet de :


- Faire appel à la fonction init_ADC( ) ;
- Faire appel à la fonction read_ADC( ).
- Charger respectivement les variables Vcons et Vmes par la tension du potentiomètre et
celle du capteur de T°.

11
#define _XTAL_FREQ 4000000
#include <xc.h>

#define CHS0 0b00000001


#define CHS1 0b00000101
#define MA PORTAbits.RA3
#define KA1 LATBbits.LATB0

int Vcons, Vmes;

// ------------- Procédure Init -----------------------


void Init()
{
ADCON1 = 0b00001101;
ADCON0 = 0b00000001;
ADCON2 = 0b00010100 ;//bit 7=0; justification à gauche// bit7=1; justification à droite
TRISA = 0xFF;
TRISB = 0xFA;
KA1 = 0;
}
//--------------- Procédure Lecture_ADC ----------------

int read_ADC(char Channel)


{
ADCON0 = Channel ;
ADCON0bits.GO = 1;
while( ADCON0bits.GO == 1);
return((ADRESH<<2)+(ADRESL>>6));//justification à gauche
//return ADRES;//justification à droite
}

// ------------------- Programme principal -------------

void main()
{
Init();
while(1)
{
Vcons = read_ADC(CHS0);
Vmes = Lecture_ADC(CHS1);
}
}

2. Régulation de la Température :
Le résultat de conversion sur 10 bits subit une justification à droite.
2.1. Développer un organigramme permettant d’illustrer le fonctionnement du système.

12
Organigramme de fonctionnement de la serre :

Début

Init_ADC

Non
MA = 1

Lecture Vcons
oui

KA1 = 1

oui
Vmes <Vcons

Lecture Vmes
Non

KA1 = 0

2.2. Développer un programme principal permettant de :


- commander l’élément chauffant (RB0 = 1) si la température dans la serre est inférieure à la
consigne(Vmes < Vcons).
- D’arrêter l’élément chauffant (RB0 = 0) si la température dans la serre dépasse la
consigne(Vmes > Vcons).

#define _XTAL_FREQ 4000000


#include <xc.h>

#define CHS0 0b00000001


#define CHS1 0b00000101
#define MA PORTAbits.RA3
#define KA1 LATBbits.LATB0
13
int Vcons, Vmes;

// ------------- Procédure Init -----------------------


void Init()
{
ADCON1 = 0b00001101;
ADCON0 = 0b00000001;
ADCON2 = 0b00010100 ;//bit 7=0; justification à gauche// bit7=1; justification à droite
TRISA = 0xFF;
TRISB = 0xFA;
KA1 = 0;
}
//--------------- Procédure Lecture_ADC ----------------

int read_ADC(char Channel)


{
ADCON0 = Channel ;
ADCON0bits.GO = 1;
while( ADCON0bits.GO == 1);
return((ADRESH<<2)+(ADRESL>>6));//justification à gauche
//return ADRES;//justification à droite
}

// ------------------- Programme principal -------------

void main()
{
Init();
while(1)
{
do
{
Vcons = read_ADC(CHS0); // lire la consigne tant que MA=0 (HS)
}
while (MA == 0) ;
Vmes = read_ADC(CHS1);// KA1 = 1 lire(T°) tant que Vmes < Vcons
if(Vmes < Vcons) KA1 = 1; // actionner le chauffage
else KA1 = 0; // arrêter le chauffage
}
}
3. Programmation de l’ADC en mode interruption.
3.1. Développer une fonction init_ADC () permettant de configurer l’ADC en mode
interruption.

// ------------- Procédure Init -----------------------


void Init_ADC()
{
ADCON1 = 0b00001101;
ADCON0 = 0b00000011;
ADCON2 = 0b00010100 ;//bit 7=0; justification à gauche// bit7=1; justification à droite
TRISA = 0xFF;
TRISB = 0xFE;
INTCONbits.GIE=1;
INTCONbits.PEIE=1;

14
PIR1bits.ADIF=0;
PIE1bits.ADIE=1;
RCONbits.IPEN=0;
KA1 = 0;
}

3.2. Développer une fonction interruption permettant de lire la valeur de conversion issue du
potentiomètre de consigne et celle du capteur de mesure et la placer dans Vcons et Vmes.
Etant donné le microcontrôleur PIC18F4520 dispose d’un seul ADC, il faut déclarer une
variable select de type char permettant l’aiguillage de l’ADC vers la consigne ou vers la
mesure :
- Si select = 0 lire la consigne
- Si select = 1 lire la mesure.

void __interrupt() ADC1(void)


{
if (PIR1bits.ADIF)
{if(!select) // si (select=0) la valeur de la consigne est chargé dans le registre ADRESL-H
{ Vcons = (ADRESH<<2)+(ADRESL>>6);// cas où le résultat est justifié à gauche
ADCON0=CHS1;
}
else // si (select=1) la valeur de la consigne est chargé dans le registre ADRESL-H
{
Vmes=(ADRESH<<2)+(ADRESL>>6); // cas où le résultat est justifié à gauche
ADCON0=CHS0;
}
PIR1bits.ADIF=0;
select=!select; // complémenter select pour la prochaine conversion
}

3.3. Développer le programme principal qui permet de :


- Commander l’élément chauffant (RB0 = 1) si la température dans la serre est inférieure à
la consigne (Vmes < Vcons).
- D’arrêter l’élément chauffant (RB0 = 0) si la température dans la serre dépasse la consigne
(Vmes > Vcons).

#define _XTAL_FREQ 4000000


#include <xc.h>

#define CHS0 0b00000001


#define CHS1 0b00000101
#define MA PORTAbits.RA3
#define KA1 LATBbits.LATB0

int Vcons, Vmes;


void __interrupt() ADC1(void)

void __interrupt() ADC1(void)


{
if (PIR1bits.ADIF)
{if(!select) // si (select=0) la valeur de la consigne est chargé dans le registre ADRESL-H
{ Vcons = (ADRESH<<2)+(ADRESL>>6);// cas où le résultat est justifié à gauche
ADCON0=CHS1;
}
else // si (select=1) la valeur de la consigne est chargé dans le registre ADRESL-H

15
{
Vmes=(ADRESH<<2)+(ADRESL>>6); // cas où le résultat est justifié à gauche
ADCON0=CHS0;
}
PIR1bits.ADIF=0;
select=!select; // complémenter select pour la prochaine conversion
}

// ------------- Procédure Init -----------------------


void Init_ADC()
{
ADCON1 = 0b00001101;
ADCON0 = 0b00000011;
ADCON2 = 0b00010100 ; // bit7=0 → justification à gauche
TRISA = 0xFF;
TRISB = 0xFE;
INTCONbits.GIE=1;
INTCONbits.PEIE=1;
PIR1bits.ADIF=0;
PIE1bits.ADIE=1;
RCONbits.IPEN=0;
KA1 = 0;
}

void main()
{
Init_ADC();
while(1)
{
KA1=0;
ADCON0bits.GODONE=1;
while (MA == 1)
{
ADCON0bits.GODONE=1;
if(Vmes < Vcons) KA1 = 1; // actionner le chauffage
else KA1 = 0;
}
}
}

16

Vous aimerez peut-être aussi