Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

Cours 3 ASPGBM3-LMD

Télécharger au format pdf ou txt
Télécharger au format pdf ou txt
Vous êtes sur la page 1sur 54

Institut Supérieur des Technologies Médicales de

Tunis

Cours : Architecture des systèmes à


z
processeurs
3ème année Licence Appliquée en GBM

Cours Préparé par :


M. Hedi ABDELKRIM
M. Slim BEN OTHMAN
M. Ahmed Karim BEN SALEM
M. Taoufik Majoul
(Classés par ordre alphabétique de noms)
Chapitre 3
Programmation des microcontrôleurs
 Introduction
 z
2.1 Rappel structure interne
 2.2 Les mémoires/accès à la mémoire EEPROM
 2.3 Les ports d’entrée/sortie
 2.4 Les interruptions
 2.5 Les timers
Introduction

 Coût réduit
 Encombrement moindre
z
 Fiabilité
 Mise en œuvre plus simple
 Consommation plus faible

3
Rappel de la structure Interne d’un µC
uLa structure interne d'un microcontrôleur comporte typiquement :
 Une unité de calcul et de commande
 Mémoire ROM
 Mémoire RAM
 Un contrôleur d’interruption
 Un compteur/temporisateur (timer)
 Des entrées/sorties parallèles (ports) z
 Un UART (port série)

Il peut aussi posséder :


 Un Watchdog : (surveillance du programme)
 Une sortie PWM (modulation d’impulsion)
 Un CAN/CNA (Convertisseur analogique numérique)
 Un interface I²C, CAN, etc.

4
Rappel de la
structure
Interne d’un
PIC16F877

5
Mémoires du microcontrôleur PIC (1)

Détail d’un registre SFR Déclaration de « i » en RAM

Void main () {
z int i;
set_tris_b(0);

Output_b(0b00101010);
}

Affectation d’une valeur à un


registre SFR

6
Mémoires du microcontrôleur PIC (2)
 Mémoire RAM
 General Purpose Register : mémoire RAM classique, utilisée pour stocker
des variables.
Exemple
int i; z
i++; // incrémentation de i depuis la RAM

 SFR (Special Function Register) : c’est aussi de la mémoire RAM, sauf que
les rôles de chacune des cases mémoire (registres) ont été définis par le
fabriquant. Chaque registre SFR est connecté à un
composant/périphérique matériel spécifique et permet de le contrôler.
Exemple
7
ADCON0 register (adresse 9Fh) : permet de piloter le convertisseur A/D.
Mémoires du microcontrôleur PIC (3)

 Mémoire ROM
Appelée aussi (à juste titre) mémoire
programme. C’est une mémoire Flash
z
qui contient le programme à exécuter.

 Mémoire EEPROM
C’est une mémoire similaire à la mémoire
programme. On s’en sert surtout pour
stocker des constantes.

8
Fonctions PICC pour l’accès à la mémoire EEPROM
Instruction de lecture Instruction d’écriture

value = read_eeprom (address) write_eeprom (address, value)

Paramètres: Paramètres:
address est un entier sur 8 bits (varie de 0 à 63 pouraddress est un entier sur 8 bits (varie de 0 à
un 16F84) 63 pour un 16F84).
value est un entier sur 8 bits value est un entier sur 8 bits
z Fonction: Ecrit un octet dans l’adresse
Fonction: Lit un octet de l’adresse spécifiée de spécifiée de l’EEPROM.
l’EEPROM. Cette fonction peut prendre plusieurs
millisecondes pour s’exécuter..
Exemple : Exemple :
#define case 10 #define case 10
volume = read_eeprom (case); volume++;
write_eeprom(case,volume);
On peut initializer le contenu d’un bloc de la mémoire EEPROM au début du programme en
utilisant la directive #ROM 0x2100 = {liste de valeurs},
Exp : avec #ROM 0x2100 = { 0, 8, 3, 9, 4, 1}
Read_eeprom(3) renvoie la valeur 9
9
Chapitre 3
Programmation des microcontrôleurs
 Introduction
 z
2.1 Rappel structure interne
 2.2 Les mémoires/accès à la mémoire EEPROM
 2.3 Les ports d’entrée/sortie
 2.4 Les interruptions
 2.5 Les timers
Les ports d’entrée/sortie (1)
 Quels sont les ports d’E/S de ce microcontrôleur ?

PORTA PORTB
z

PORTE
Université de Savoie

PORTC

PORTD 0 0 11
Les ports d’entrée/sortie (2)

 Deux modes de sorties :

 Sortie trois états (push-pull)z


 Sortie collecteur ouvert (open drain)

12
Les ports d’entrée/sortie (3)
1. Sortie trois états : Push-Pull
Fonctionnement
T1 T2 Sortie
BloquéEtat haute impédance
Bloqué "Z"
Bloqué Saturé "0"
z
Saturé Bloqué "1"
Saturé Saturé non utilisé

 Des sorties trois états peuvent être reliées entres elles mais il faut bien
veiller à ce qu’une seule impose un niveau (haut ou bas) et que les
autres sorties soit en haute impédance.
13
Les ports d’entrée/sortie (4)
2. Sortie collecteur ouvert : Open Drain

Fonctionnement
z T2 S
Saturé "0"
Bloqué Dépend du montage
du circuit extérieur

14
Les ports d’entrée/sortie (5)
2. Sortie collecteur ouvert (2)

 Pour générer le niveau "1", une résistance extérieure est nécessaire


(résistance de tirage // pull-up).
Plusieurs sorties "collecteur ouvert" peuvent être reliées entre elles, cela
réalise un "ET logique "
+ Une sortie « collecteur ouvert » peut commander une charge sous une
15
tension différente de la tension d'alimentation
Les ports d’entrée/sortie (2)

 Trois modes d’entrées:


 Entrée flottante
z
 Entrée avec Pullup
 Entrée avec Pulldown

16
Les ports d’entrée/sortie (5)
• Technologies des ports en entrée:
Mode Floating input Mode Pull Down

z
➢ le circuit extérieur impose
le potentiel de la broche
Mode Pull Up
➢ Le potentiel de la broche se retrouve au
potentiel de référence (VCC ou GND)
grâce à la résistance de rappel.
➢ Le circuit extérieur doit avoir une
résistance de sortie faible devant R,
sinon, la tension chute 17
Les ports d’entrée/sortie (6)
 Bouton poussoir :  Led :

Donner la valeur de la résistance


sachant qu’une led rouge a une tension de 1,5V
et qu’il faut 10 mA pour avoir un éclat correct.
18
Les ports d’entrée/sortie (7)
Cas du PIC16F877
Récapitulatif (PIC 16F877)
 Combien possède t-on de bits d’E/S pour les ports A, B, C, D et E ?

 Quels registres respectifs permettent


z de les configurer en entrée ou en
sortie ?

 Quelle mise en garde est faite pour le PORTA ?

 Quelleparticularité du PORTB peut nous être utile pour connecter un


bouton poussoir par exemple ?
19
Fonctions PICC de gestion des entrées et des sorties
Instructions de lecture

Par bit Par octet


(ou broche) (ou port)

value = input (PIN_xx) value = input_a ()


value = input_b ()
Paramètres: PIN_xx est l’adresse de la broche à lire.
z
Fonction: renvoi l’état (0 ou 1) de la broche PIN_xx.
Exemple : Fonction: renvoi un entier sur 8 bits représentant
while ( !input(PIN_B1) ); l’état du port correspondant.
// waits for B1 to go high Exemple :
data = input_b();
int i=PIN_B1; Sw = input_a() & 0x07;
while(!i);
//waits for B1 to go high

Il faut s’assurer que les broches/ports soient correctement configurées en entrée avant
d’utiliser ces fonctions.
20
Fonctions PICC de gestion des entrées et des sorties

Instructions d’écriture
Par bit Par octet
(ou broche) (ou port)
output_a (value)
output_high (PIN_xx) / output_low (PIN_xx) output_b (value)
output_bit (PIN_xx, value)
Paramètres: z
PIN_xx est l’adresse de la broche à écrire. Paramètres:
value est la valeur de forçage (0 ou 1) value entier de 8 bits à écrire sur le port de sortie
Fonction: force l’état de la broche PIN_xx à 0 ou 1. correspondant.
Exemple : Fonction: écrire un entier sur 8 bits sur le port
output_high(PIN_A0); correspondant.
output_bit( PIN_B0, 0); Exemple :
// Same as output_low(pin_B0); OUTPUT_B(0xf0);
output_bit( PIN_B0,input( PIN_B1 ) );
// Make pin B0 the same as B1

Il faut s’assurer que les broches/ports soient correctement configurées en sortie avant
d’utiliser ces fonctions. 21
Fonctions PICC de gestion des entrées et des sorties

Directive d’accès direct aux registres SFR

#BYTE id = x

Paramètres:
id est un nom de variable.
x est une adresse mémoire sur 8 bits z
Fonction: crée une variable id à l’adresse x de la mémoire de données du PIC.
Exemple :
#byte pp_b=6
//pp_b est une variable définie à l’adresse du register SFR PORTB

pp_b = ~pp_b
//inverser l’état du port B

Ce mécanisme est utilisé pour contourner les restrictions des instructions de


lecture/écriture précédentes.
22
Chapitre 3
Programmation des microcontrôleurs
 Introduction
 z
2.1 Rappel structure interne
 2.2 Les mémoires/accès à la mémoire EEPROM
 2.3 Les ports d’entrée/sortie
 2.4 Les interruptions
 2.5 Les timers
Les interruptions
Une interruption, est un événement externe ou interne au système qui interrompt le
déroulement du programme en cours et oblige le système à exécuter une routine
particulière.
Le système d’interruption est un dispositif incorporé au séquenceur qui détecte les signaux
d’interruption. Ces signaux arrivent de façon asynchrone, à n’importe quel moment, mais ils
ne sont pris en compte qu’à la fin de l’opération en cours.
z
Événements externes
• Changement sur une entrée spécifique appelée entrée d’interruption. (tout µC en a au moins
une),
• Changement sur un bit de port. (sur le PIC16F84, seuls les bits RB4 à RB7 peuvent déclencher
une interruption),

Événements internes
• Débordement Timer
• Fin écriture EEPROM
• Fin de conversion A/N
• ……
24
Explication du mécanisme d’interruption

Programme principal

main() Routine d’interruption


Si une interruption doit
début
modifier le
Initialisations déroulement du
z
programme principal,
interruption Actions
on fera en sorte que sa
Actions 1
Boucle de routine modifiera une
fonctionnement
interruption Fin
variable globale qui
normal.
Actions 2 sera testée dans le
programme principal.

Fin

25
Gestion de l’interruption par le microcontrôleur

Sauvegarde du contexte dans une pile :


- adresse de la prochaine instruction à exécuter dans le
programme interrompu,
- contenu des registres qui seront modifiés par le
programme d’interruption,
- contenu du registre STATUS rassemblant les indicateurs
z

Restauration du contexte à partir de la pile

26
Sources d’interruption (1)
Sources d’interruption du 16F877
Le 16F877 dispose de 15 sources d’interruptions.
Les événements susceptibles de déclencher une interruption sont les suivants :
1. Timer 0
2. Timer 1
3. RB0 du port B
4. Changement d’état du port B
z
5. Port parallèle (lecture/ecriture)
6. Convertisseur ADC
7. Transmission sur UART
8. Réception sur UART
9. Synchronisation du port série
10. CCP1 (Capture, Compare, PWM)
11. CCP2 (Capture, Compare, PWM)
12. Timer 2
13. Comparateur
14. Opération d’écriture dans la mémoire EEPROM
15. Collusion de bus
27
Sources d’interruption (2)
Sources d’interruption du 16F84
Le 16F84 ne dispose que de 4 sources d’interruptions possibles (contre 13 pour le 16F876).
Les événements susceptibles de déclencher une interruption sont les suivants :

- TMR0 : Débordement du Timer0. Une fois que le contenu du Tmr0 passe de 0xff à 0x00, une
interruption peut être générée.
z

- EEPROM : cette interruption peut être générée lorsque l’écriture dans une case EEPROM interne est
terminée.

- RB0/INT : Une interruption peut être générée lorsque, la pin RB0 (INTerrupt pin), étant configurée
en entrée, le niveau qui est appliqué est modifié.

- PORTB : De la même manière, une interruption peut être générée lors du changement d’un niveau
sur une des pins RB4 à RB7. Il n’est pas possible de limiter l’interruption à une seule de ces pins.
L’interruption sera effective pour les 4 pins ou pour aucune. 28
Activation des interruptions (1)
Pour qu’une interruption sur les microcontrôleurs PIC soit prise en compte, deux autorisations sont requises :
• Autorisation individuelle : on configure la ou les interruptions autorisées.
• Autorisation globale : on autorise ou interdit toutes les interruptions (qui doivent être autorisées
individuellement).

INTCON:
SFR 0Bh z

29
Activation des interruptions (2)
INTCON:
SFR 0Bh

30
Programmation d’une interruption (1)

 Configuration de la prise en compte de l’interruption dans le


programme void config_int ()
• enable_interrupts (level) {
Active le niveau d’interruption précisé par level ext_int_edge(L_TO_H);
enable_interrupts(INT_EXT);
enable_interrupts(GLOBAL);
• disable_interrupts (level)
}
Désactive le niveau d’interruption précisé par level
Pour le PIC16F84 level peut être : z
GLOBAL 0x0B80
INT_RTCC ou INT_TIMER0 : interruption TMR0 void main (void)
INT_RB : interruption PortB {
config_port();
INT_EXT : interruption RB0/INT config_int();
INT_EEPROM : interruption EEPROM ….
while(1)
{
• ext_int_edge (edge) …
}
Définit le niveau edge du front considéré par une interruption externe }

edge est une constante = L_TO_Hpour désigner un front montant () 31

H_TO_Lpour désigner un front descendant ()


31
Programmation d’une interruption (2)

 Attribuer les routines d’interruption


#INT_EXT
void routine_ISR ()
• #INT_XXX {

Placer cette directive avant le corps de la fonction d’interruption,
}
permet de définir la routine d’interruption et sa nature :
z
#INT_RTCC ou #INT_TIMER0 : interruption TMR0
#INT_RB : interruption Portb
void main (void)
#INT_EXT : interruption RB0/INT {
#INT_EEPROM : interruption EEPROM config_port();
config_int();
….
while(1)
{

}
}
32

32
Exemple de programmation d’une interruption
void main()
int16 compt;
{
int led_rouge;
. . .
#int_EXT
ext_int_edge(L_TO_H);
void ma_fonction()
enable_interrupts(INT_EXT);
{
enable_interrupts(GLOBAL);
compt=compt+1;
led_rouge=!led_rouge; z
while(1)
output_bit(PIN_A0, led_rouge);
{
}
if (compt>1000)
{
compt=0;
change_led();
}
delay_ms(300);
}
} 33
Chapitre 3
Programmation des microcontrôleurs
 Introduction
 z
2.1 Rappel de la structure interne
 2.2 Les mémoires/accès à la mémoire EEPROM
 2.3 Les ports d’entrée/sortie
 2.4 Les interruptions
 2.5 Les timers
Fonctions PICC de gestion des temporisations

Le compilateur intègre des fonctions très pratiques pour gérer les délais :
• delay_cycles (valeur) ; // temporisation en Nbre de cycles
• delay_us (valeur) ; // temporisation en µs
• delay_ms (valeur) ; // temporisation en ms
z

Pour pouvoir utiliser ces fonctions, il faut indiquer la fréquence du quartz de


votre application. Cette ligne doit être définie au début du programme.
#use delay (clock = fréquence_du_quartz_en_HZ)

Exemples :
#use delay (clock=4000000) // quartz de 4 MHz
35
Les Timers
Mode compteur ou temporisateur (1)
Un timer est le nom courant de compteur / temporisateur

45
Mesurer du temps (compter le
nombre de coups d’horloge)
> Mode temporisateur
z

Compter le nombre d’évènements


sur une broche
> Mode compteur

36
Applications du Timer

(a) Mesure de temps entre


deux évènements
(b) Mesure de la période entre
deux impulsions z
(c) Mesure de la largeur d’une
impulsion

Utilisation de la scrutation ou des interruptions

37
Fonctionnement du Timer0
Mode compteur ou temporisateur (2)
En pratique, on visualise la valeur de départ, puis la valeur d’arrivée. La valeur de comptage
est la différence des deux valeurs.

 Dans quel mode fonctionne le timer ici ?


 Donner la valeur du temps en fonction de A et B dans cette application.

38
Utilisation d’un prédiviseur (prescaler)

 Un prescaler permet de diviser la fréquence de comptage.

Quelle est le temps mesuré dans cette application en fonction de A et B ?

39
Structure du module Timer0 du PIC (1)

z
• Un registre sur 8 bits (TMR0) qui compte les fronts montants (ou descendants) du signal
qu’on lui fournit. Arrivé à 255, il repasse à 0. Il est accessible en lecture ou en écriture de la
même façon que le PORTA ou le PORTB.
• Un prédiviseur 3 bits (prescaler) qui divise la fréquence du signal qu’on lui fournit par une
valeur constante qu’il est nécessaire de programmer.
• Des aiguillages qui permettent de définir le chemin qu’emprunte le signal d’horloge
(externe/interne, avec/sans prescaler).
• Des bits de configuration dans le registre OPTION
• Un générateur d’interruption à chaque débordement du timer
40
Structure du module Timer0 du PIC (2)

Module Timer0 du PIC16F84A


Le bloc Sync retarde le début du fonctionnement de 2
cycles d’instruction lorsqu’un bit relatif au Timer0 est
modifié. Cette fonction est due à l’architecture du
Timer0 et ne peut pas être contournée. 41

41
Structure du module Timer0 du PIC (3)

Cas du PIC 16F877


z

42
Configuration du Timer0
mode Timer

43
Configuration du Timer0
mode Compteur

44
// fonctions de configuration et d’utilisation du Timer0
//mode Timer
void setup_timer_0(int8 mode, int8 prescaler);
void set_timer0(int8 value);
int8 get_timer0( );
//mode Compteur
void setup_counters(int8 mode, int8 prescaler);
void set_rtcc(int8 value);
int8 get_rtcc( );

// Constants used for SETUP_TIMER_0() or SETUP_COUNTERS() :


mode
#define T0_INTERNAL 0
z
#define T0_EXT_L_TO_H 32
#define T0_EXT_H_TO_L 48
#define T0_8_BIT 0
prescaler
#define T0_DIV_1 8
#define T0_DIV_2 0
#define T0_DIV_4 1
#define T0_DIV_8 2
#define T0_DIV_16 3
#define T0_DIV_32 4
#define T0_DIV_64 5
#define T0_DIV_128 6
45
#define T0_DIV_256 7
Configuration du Timer0 sous PICC
Instruction de Configuration

setup_timer_0 (mode)

Paramètres:
mode peut être 1 ou 2 constantes définies dans le fichier devices .h
Constantes Groupe1 : RTCC_INTERNAL, RTCC_EXT_L_TO_H, RTCC_EXT_H_TO_L
Constantes Groupe2 : RTCC_DIV_2, RTCC_DIV_4, RTCC_DIV_8, RTCC_DIV_16,
z
RTCC_DIV_32, RTCC_DIV_64, RTCC_DIV_128, RTCC_DIV_256
Fonction: définit le réglage du signal d’horloge du timer.

Exemple :
setup_timer_0 (RTCC_DIV_2|RTCC_EXT_L_TO_H);

1:2 46
Forçage du Timer0 sous PICC
Instruction de forçage

set_timer0(value) or set_rtcc (value)

Paramètres:
Value information sur 8 bits à écrire dans le registre TMR0

Fonction: Met à jour (force) la valeur en cours de comptage à value. Le compteur s’incrémente à partir
z
de cette valeur, jusqu’à 255 puis recommence à compter à partir de 0.

Exemple :
// 4 mhz clock, sans prescaler,
setup_timer_0 (T0_INTERNAL);
// Dépassement chaque 35us
set_timer0(221); // 256-(.000035/(4/4000000))
221

47
Lecture du Timer0 sous PICC
Instruction de lecture

value=get_timer0() ou value=get_rtcc()

Paramètres:
Value information sur 8 bits du contenu du registre TMR0

Fonction: Retourne la valeur en cours de comptage.


z
Exemple : Mesurer le temps d’exécution d’une certaine function dans le code
// 4 mhz clock, sans prescaler,
setup_timer_0 (T0_INTERNAL);

set_timer0(0);
fonction_a_mesurer();
dly= get_timer0(); //en us dans ce cas dly=25

48
Configuration du Timer0
Exemple 1
On souhaite générer un signal carré de période 1ms (500us haut/ 500us bas)
sur une PIN RA0
→ Comment provoquer un débordement du timer chaque 500µs ?
• Problème : Trouver la valeur du prescaler (PRS), et celle de préchargement (TMR0=N),
• Données : Fosc = 4 MHz, Tref=500us
• Calcul:
TTMR : Horloge du Timer = 4
T
TMR
z = .PRS
Fosc

TTMR = Tref /( 256 − N )

On pose X=256-N et C=Tref/(4/Fosc), l’équation revient à PRS=C/X


• On peut commencer à chercher la valeur de PRS pour N=0
PRS=1.9 soit PRS=2
• On calcule ainsi, la valeur de N pour PRS=2
N=6 49
Configuration du Timer0
Exemple 1

On souhaite générer un signal carré sur la PIN RA0 de période 1ms (500us haut/
500us bas)
• PRS=2
• N=6
• provoquer un débordement du timer chaque 500µs qui déclenche une interruption
z
int state=0;
//instructions de configuration au niveau du main() #INT_TIMER0
//configuration et initialisation timer0 void ma_fonction()
setup_timer_0 (T0_INTERNAL|T0_DIV_2); {
set_timer0(6); state=!state;
//activation de l’interruption débordement timer0 output_bit(PIN_A0, state);
enable_interrupts(INT_TIMER0); set_timer0(6);
enable_interrupts(GLOBAL); }

50
Constants used in ENABLE/DISABLE_INTERRUPTS() are:

#define GLOBAL 0x0BC0 Les événements susceptibles de déclencher une interruption


#define PERIPH 0x0B40
#define INT_TIMER0 0x000B20 1. Timer 0
#define INT_TIMER1 0x008C01 2. Timer 1
#define INT_TIMER2 0x008C02 3. Timer 2
#define INT_RTCC 0x000B20
4. RB0 du port B
#define INT_EXT_L2H 0x50000B10
#define INT_EXT_H2L 0x60000B10
#define INT_EXT 0x000B10 z
5. Changement d’état du port B
#define INT_RB 0x00FF0B08 6. Port parallèle (lecture/ecriture)
#define INT_SSP 0x008C08
#define INT_PSP 0x008C80 7. Convertisseur ADC
#define INT_AD 0x008C40 8. Transmission sur UART
#define INT_TBE 0x008C10 9. Réception sur UART
#define INT_RDA 0x008C20 10. Synchronisation du port série
#define INT_CCP1 0x008C04 11. CCP1 (Capture, Compare, PWM)
#define INT_CCP2 0x008D01 12. CCP2 (Capture, Compare, PWM)
#define INT_COMP 0x008D40 13. Comparateur
#define INT_EEPROM 0x008D10 14. Opération d’écriture dans la mémoire EEPROM
#define INT_BUSCOL 0x008D08 15. Collusion de bus
51
Exercice d’application

À chaque contact d’une butée du moteur avec le capteur inductif ➔ front descendant sur RA4
Interruption en cas de débordement du Timer0
1. Déterminer le mode du Timer0
2. Déterminer le nombre de tours du moteur ?
52
Bits de configuration
Ils permettent d’activer ou de désactiver les fonctions matérielles du PIC à chaque remise à
zéro du programme.

Sont concernés par ces bits de contrôles :


• Le système de synchronisation
• La gestion de l’alimentation
• La sécurité du code (du programme) z

Les bits de configuration sont générés à partir des directives de compilation incluses dans
les fichiers de code source.

La directive qui indique comment programmer les bits ou fusibles de configuration du


PIC a cette syntaxe :
#fuses liste et état des fusibles

53
Directives de configuration Hardware du PIC16F84A
#FUSES

Liste et état des fusibles est une suite d’informations séparées par des virgules précisant les
fusibles à programmer et l’état de la fonction à valider ou non.

Le PIC16F84A dispose des fusibles de configuration suivants :


LP, XT, HS, RC pour le type d’horloge ;
WDT ou NOWDT pour valider ou z non le timer chien de garde ;
PROTECT ou NOPROTECT pour protéger ou non la mémoire de programme ;
PUT ou NOPUT pour valider ou non le timer à la mise sous tension ;

Exemple :
#fuses XT, NOWDT, PUT
Choisit un oscillateur de type horloge à quartz de fréquence inférieure OU égale 4
MHz (horloge de type XT), pas de timer chien garde (nowdt) , un timer à la mise sous
tension (put)

54

Vous aimerez peut-être aussi