Académique Documents
Professionnel Documents
Culture Documents
Compte Rendu Embeddedc
Compte Rendu Embeddedc
MODULE : C EMBARQUE
Initiation au PIC16F84
NABIL BOULARTAL
Les PIC sont des microcontrôleurs RISC (de l'anglais, Reduced Instructions Set
Computer) ; qui signifie : calculateur à jeu réduit d'instructions. Ils sont dédiés aux
applications qui ne nécessitent pas une grande quantité de calculs complexes, mais
qui demandent beaucoup de manipulations d’entrées / sorties. En effet, il existe
plusieurs familles de microcontrôleurs, dont les plus connues sont : Atmel, Motorola,
Microship, Intel,…etc. La famille des PIC à bus de données 8 bits est subdivisée, à
l’heure actuelle, en 3 grandes catégories :
Base-ligne : utilisent des mots d’instruction de 12 bits.
Mid-Range : utilisent des mots d’instruction de 14 bits.
High-End : utilisent des mots d’instruction de 16 bits.
1) La référence :
Les PIC 16FXX sont des microcontrôleurs 8 bits (largeur du bus de données)
conçus en technologie CMOS (faible consommation électrique). Les µC PIC utilisent
une architecture RISC (Processeur à jeu d’instructions réduit) avec 35 instructions
codées en un mot de 14 bits. Pour identifier un pic, on utilise le numéro inscrit sur
son boitier, exemple du PIC 16F84-04 :
Référence du PIC
84
a) Exemple d’alimentation :
b) Exemple d’horloge :
Pour fonctionner correctement, le microcontrôleur nécessite la présence d'une
horloge qui doit être câblée entre les bornes « OSC1 et OSC2 ». Cette horloge peut
être réalisée de différentes façons :
3) Structure interne :
:020000001628C0
:0E0006008312031321088A00200882000800DC
:1000140003208A110A128000840AA00A0319A10A83
:08002400F003031D0A28080087
:10002C00831603130610831206140B30FB002630C4
:10003C00FC005D30FD00FD0B2128FC0B2128FB0B87
:10004C0021280000000006100B30FB002630FC00BD
:10005C005D3
0FD00FD0B3028FC0B3028FB0B3028ED
:08006C000000000019283928EA
:02400E004A2F37
:00000001FF
Application 2:
Supposant le montage suivant permettant de contrôler 8 diodes LED :
1) Nous proposons faire clignoter les LEDs branchées au port B du microcontrôleur de
deux façons différentes :
- Si RA0 = 0, tous les diodes LEDs clignotent avec une période d’une seconde.
- Si RA0 = 1, les diodes LEDs doivent clignoter chaque 500 ms comme indiqué dans
la figure ci-dessous.
*********************************************************************
En binaire
*********************************************************************
#define B1 RA0_bit //Déclaration du boutton B1 dans la broche 0 du
//PORTA
int i;
void main()
{
TRISA=0b11111111;
PORTB=0b00000000;while(1)
{if(B1==0)
{for(i=0; i<2; i++){
PORTB=0b11111111; Delay_ms(500);
PORTB=0b00000000; Delay_ms(500);
}
}else
{
PORTB=0b00000011; Delay_ms(1000);
PORTB=0b00001100; Delay_ms(2000);
PORTB=0b00110000; Delay_ms(3000);
PORTB=0b11000000; Delay_ms(4000);
PORTB=0b00000000; Delay_ms(1000);
} } }
*********************************************************************
En hexadecimal
*******************************************************************
#define B1 RA0_bit //Déclaration du boutton B1 dans la broche 0 du
//PORTA
int i;
void main()
{
TRISA=0xFF; //0b11111111
TRISB=0x00;
PORTB=0x00;while(1)
{if(B1==0)
{for(i=0; i<2; i++){
PORTB=0xFF; Delay_ms(500);
PORTB=0x00; Delay_ms(500);
}
}else
{
PORTB=0x03; Delay_ms(1000);
PORTB=0x0C; Delay_ms(2000);
PORTB=0x30; Delay_ms(3000);
PORTB=0xC0; Delay_ms(4000);
PORTB=0x00; Delay_ms(1000);
} } }
Afficheurs 7 segments:
Application 3:
On veut commander un afficheur à 7 segments afin de réaliser un compteur modulo 10
à l’aide d’un microcontrôleur 16F84A.
void main()
{ TRISA=0b00000011;
TRISB=0b00000000;
//int i;
PORTB = 0;while(1)
{if(RA0_Bit == 1)
{for(i=0;i<10;i++) {
PORTB = CHIFFRE[i]; delay_ms(1000); //De 0 à 9
}
}if(RA1_Bit == 1)
{for(i=0;i<10;i++) {
PORTB = CHIFFRE[9-i]; delay_ms(1000); //De 9 à 0
}
}
}
}
Autrement:
*********************************************************************
Methode 1 En binaire:
*********************************************************************
void main()
{
TRISA=0b00000011; // Configuration du port A (Broche RA0 et RA1 en
entrée)
TRISB=0b00000000; // Configuration du port B en sortie
PORTA = 0; // Initialisation du port A
PORTB = 0; // Initialisation du port B
while(1)
{if(RA0_Bit == 1)
{
PORTB = 0b00111111;//Affichage du chiffre 0
delay_ms(100);
PORTB = 0b00000110;//Affichage du chiffre 1
delay_ms(100);
PORTB = 0b01011011;//Affichage du chiffre 2
delay_ms(100);
PORTB = 0b01001111;//Affichage du chiffre 3
delay_ms(100);
PORTB = 0b01100110;//Affichage du chiffre 4
delay_ms(100);
PORTB = 0b01101101;//Affichage du chiffre 5
delay_ms(100);
PORTB = 0b01111101;//Affichage du chiffre 6
delay_ms(100);
PORTB = 0b00000111;//Affichage du chiffre 7
delay_ms(100);
PORTB = 0b01111111;//Affichage du chiffre 8
delay_ms(100);
PORTB = 0b01101111;//Affichage du chiffre 9
delay_ms(100);
}if(RA1_Bit == 1)
{
PORTB = 0b01101111;//Affichage du chiffre 9
delay_ms(100);
PORTB = 0b01111111;//Affichage du chiffre 8
delay_ms(100);
PORTB = 0b00000111;//Affichage du chiffre 7
delay_ms(100);
PORTB = 0b01111101;//Affichage du chiffre 6
delay_ms(100);
PORTB = 0b01101101;//Affichage du chiffre 5
delay_ms(100);
PORTB = 0b01100110;//Affichage du chiffre 4
delay_ms(100);
PORTB = 0b01001111;//Affichage du chiffre 3
delay_ms(100);
PORTB = 0b01011011;//Affichage du chiffre 2
delay_ms(100);
PORTB = 0b00000110;//Affichage du chiffre 1
delay_ms(100);
PORTB = 0b00111111;//Affichage du chiffre 0
delay_ms(100);
}
}
}
*********************************************************************
Methode 2 En decimal:
*********************************************************************
int i,CHIFFRE[10]={
63, // Code du digit 0
6, // Code du digit 1
91, // Code du digit 2
79, // Code du digit 3
102, // Code du digit 4
109, // Code du digit 5
125, // Code du digit 6
7, // Code du digit 7
127, // Code du digit 8
111 // Code du digit 9
};
void main()
{
TRISA=0b00000011; // Configuration du port A (Broche RA0 et RA1 en
entrée)
TRISB=0b00000000; // Configuration du port B en sortie
*********************************************************************
Methode 3 En Hexadecimal:
*********************************************************************
int i, CHIFFRE[] ={
0x3F, // Code du digit 0
0x06, // Code du digit 1
0x5B, // Code du digit 2
0x4F, // Code du digit 3
0x66, // Code du digit 4
0x6D, // Code du digit 5
0x7D, // Code du digit 6
0x07, // Code du digit 7
0x7F, // Code du digit 8
0x6F, // Code du digit 9
};
void main()
{
TRISA=0x03; // Configuration du port A (Broche RA0 et RA1 en entré
e)
TRISB=0x00; // Configuration du port B en sortie
Minuterie:
Application 4:
On veut réaliser une minuterie d’escalier à 3 temps réglable (3min, 6min, 9min) à l’aide
d’un microcontrôleur 16F84A.
Objectif : A l’aide des microcontrôleurs, il est possible de réaliser des montages avec
une véritable gestion de l’information et des protocoles pour la communication de
données (entrées/sorties). Il devient possible d’utiliser, pour l’interface utilisateur, des
périphériques "évolués" comme des claviers matriciels ou encore des afficheurs à
cristaux liquides (LCD). Nous nous intéressons dans ce 2 ème TP à la gestion du
clavier matriciel et de l’afficheur LCD 2x16.
Application 1:
while(1)
{if(B1==1 && B2==0 && B3==0)
{
Lcd_Out(1, 1, msg1); //Commande affiche le contenu du tableau msg1
//sur la 1er ligne et la 1er colonne de LCD
D1 = 1; delay_ms(500);
D1 = 0; delay_ms(500);
}else if(B1==0 && B2==1 && B3==0)
{
Lcd_Out(1, 1, msg2);//Commande affiche le contenu du tableau msg2
//sur la 1er ligne et la 1er colonne de LCD
D2=1;delay_ms(500);D2=0;delay_ms(500);
}else if(B1==0 && B2==0 && B3==1)
{
Lcd_Out(1, 1, msg3);//Commande affiche le contenu du tableau msg3
//sur la 1er ligne et la 1er colonne de LCD
D3=1;delay_ms(500);D3=0;delay_ms(500);
}else
{
Lcd_Cmd(_LCD_CLEAR);//Effacer le contenu de l’ecran LCD
}while (1);}
TP 2, INITIATION A LA PROGRAMMATION DU Cortex M4
NUCLEO STM32F446RE
Vous devez remplir le formulaire en fournissant une adresse e-mail valide pour recevoir le
lien de téléchargement dans votre boîte de réception.
2. Une fois STM32CubeIDE installé, il est temps de l'ouvrir et de sélectionner votre répertoire
de travail, comme illustré sur la figure.
3. Après avoir choisi votre répertoire de travail, vous accéderez à la première fenêtre.
Cortex-A : Les processeurs de ce profil sont utilisés dans les appareils à haute
performance tels que les téléphones mobiles.
Cortex-R : Les processeurs de ce profil sont principalement utilisés dans les
applications en temps réel, où la priorité est de réduire le temps de réponse. Il existe
plusieurs versions d'ARM Cortex R.
Cortex-M : Les processeurs de ce profil sont utilisés pour les systèmes embarqués
basés sur des microcontrôleurs. La famille Cortex-M inclut les modèles Cortex-M0,
Cortex-M0+, Cortex-M1, Cortex-M3, Cortex-M4 et Cortex-M7.
ARM Cortex-M4
Le Cortex-M4 est un processeur 32 bits conçu pour des performances de traitement
élevées, une gestion de 4 Go d'espace d'adressage mémoire, un traitement rapide
des interruptions et une faible consommation d'énergie. Il possède une architecture
Harvard pipeline à 3 étages, idéale pour les applications embarquées nécessitant un
traitement haut de gamme. Carte mémoire :
ARM Cortex-M4 Registre
Le Cortex-M4 a des registres de 32 bits, comprenant :
1- 13 registres généraux, numérotés de R0 à R12.
2- Le Pointeur de pile (SP), aliasé en Main Stack Pointer et Process Stack Pointer,
numéroté R13.
3- Le Registre de liaison (LR), numéroté R14.
4- Le Compteur de programme (PC), numéroté R15.
5- Des registres spéciaux, tels que le Registre d'état du programme (PSR), les
registres de masque d'exception et le Registre de contrôle.
Les registres les plus importants à connaître pour le moment sont les suivants, nous en discuterons plus en
détail lors des prochaines séances :
1- Registres à usage général : Les registres R0 à R12 sont destinés aux opérations
de données et sont divisés en deux ensembles : - Registres bas : Les registres R0 à
R7 font partie de cet ensemble et sont accessibles par toutes les instructions. -
Registres hauts : Les registres R8 à R12 font partie de cet ensemble et ne sont
accessibles que par des instructions 32 bits, et non par des instructions 16 bits.
2- Compteur de programme (PC) : Le registre R15 est utilisé comme compteur de
programme. Il stocke l'adresse de la prochaine instruction à exécuter. Dans une
valeur de PC de 32 bits, le bit [0] est toujours mis à zéro afin que le PC reste aligné
sur les limites d'instruction des mots (32 bits) ou des demi-mots (16 bits).
3-Registre d'état du programme (PSR) : Le registre d'état du programme est
constitué de divers indicateurs tels que les indicateurs de traitement arithmétique
et logique et les indicateurs d'état d'exécution. Le PSR est une combinaison du
registre d'état du programme d'application (APSR) et du registre d'état du
programme d'exécution (EPSR).
4-Registre de liaison (LR- R14) : Le registre de liaison (LR) est le registre R14, et il
stocke les informations de retour pour les sous-routines, les appels de fonction et
les exceptions. Le registre de liaison est accessible en mode privilégié ou non
privilégié.
PARTIE 1
Pour Configurer n’importe quel GPIO d’un stm32 il faut suivre les étapes suivantes :
Pour cette partie, nous allons suivre les étapes mentionnées ci-dessus pour une
configuration graphique.
Bibliothèque HAL (Hardware Abstraction Layer)
HAL (Hardware Abstraction Layer) fourni par STMicroelectronics pour une utilisation
avec les microcontrôleurs STM32.
Le pilote HAL est une couche de logiciel qui fournit une interface standardisée pour
interagir avec les fonctionnalités matérielles des microcontrôleurs STM32. Il est conçu
pour simplifier le processus de développement de logiciels pour le STM32 en
fournissant un ensemble d'API (interfaces de programmation d'applications) qui
peuvent être utilisées pour accéder aux périphériques matériels du microcontrôleur
de manière cohérente et portable. Le pilote HAL est écrit en C et est destiné à être
utilisé avec le langage de programmation C, bien qu'il puisse également être utilisé
avec d'autres langages pouvant s'interfacer avec le code C.
Application 1:
1- L’initialisation de l’horloge principale de la carte.
Pour configurer l'horloge système sur notre carte à l'aide de l'interface graphique (GUI)
de l'outil STM32Cube, voici les étapes à suivre :
.
Pour configurer une broche GPIO à l'aide de STM32CubeMX, voici les étapes à
suivre : Dans l'onglet Pinout & Configuration, choisir la broche GPIO à
configurer sur le diagramme de la pinout.
Cliquez sur le bouton "Générer le code" ou Cliquez sur icone comme la figure ci-dessous .
Après le code généré dans le fichier Main.C ainsi toutes les bibliothèques nécessaires de votre espace de travail.
Code Généré
int main(void)
{
/* Reset of all peripherals, Initializes the Flash interface and the
Systick. */
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
/* Initialize all configured peripherals */
MX_GPIO_Init();
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
}
}
HAL_Init(); Sert à initialiser la librairie HAL,elle doit être la première instruction à être exécutée dans le
programme principal (avant d'appeler toute autre fonction HAL), elle effectue ce qui suit : Configurer le Flash
prefetch, les caches d'instructions et de données.
SystemClock_Config(); Ce bloc sert a configurerez horloge de système
void SystemClock_Config(void)
*/
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE3);
*/
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLN = 84;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 2;
RCC_OscInitStruct.PLL.PLLR = 2;
default (reset)
Apres Pour compiler et générer fichier hex on doit activer option comme la figure ci-dessous
Apres on lance la simulation on doit remarquer que les 3 LEDS clignote avec un Delay de 300ms
Application 2:
Sur le même Project, Essayez de modifier le code précédent afin d'avoir 6 LEDS qui clignotent
séquentiellement
Application 3:
Sur le même Project, Essayez de réaliser un compteur 0 a 9 avec afficheur 7SEG-CAT sur la PORT D de
notre microcontrôleur.
Remarque : il faut suivre les mêmes étapes de configuration des GPIOs
II-PARTIE 2
Dans cette section, nous configurons les GPIOs directement à l'aide des registres en nous
basant sur la datasheet du microcontrôleur.
Microcontrôleur GPIO pins :
Le microcontrôleur utilisé dans ce TP, le STM32F401VE, est basé sur le cortex M-4 d'ARM et dispose de 6 ports :
PORTx avec x=(A, B, C, D, E, H). Chaque port a une plage d'adresses associée, comme décrit ci-dessous :
Nous pouvons observer que chaque port est alloué une quantité de mémoire
déterminée, en raison de ses différentes fonctionnalités et de ses registres spéciaux
associés. Pour configurer les GPIO sur notre carte, nous allons suivre les étapes
suivantes :
1-Activer l'horloge du port GPIO:
Il est important de savoir que chaque registre correspond à une adresse physique
spécifique définie par le fabricant. Ainsi, nous devons d'abord définir l'adresse de
chaque pointeur dans notre programme. Par exemple :
#define RCC_AHB1ENR (*((volatile unsigned long *) 0x40023830))
Cette ligne de code définit une constante qui pointe vers une adresse mémoire
spécifique dans le registre RCC, et peut être utilisée pour lire ou écrire des valeurs à
cette adresse. Pour simplifier cette tâche, nous incluons le fichier stm32f401xe.h, qui
contient les déclarations des registres associées à leurs adresses physiques. C'est la
meilleure façon, pour les débutants, d'éviter les erreurs potentielles. Par défaut,
l'option d'horloge est désactivée pour tous les ports GPIO du microcontrôleur afin
d'économiser de l'énergie. Pour activer l'horloge d'un port, nous utilisons le registre
RCC_AHB1ENR qui est mappé à l'adresse physique 0x40023830.
Dans ce registre chaque 2 bits est associé a un pin avec la relation 2y,2y+1 (avec y est
le numéro de pin).
Alors on :
00 : configurer la broche comme entré (par défaut )
01 : configurer la broche comme sortie
10 : le mode de fonctionnement alternatif
11 : mode analogique
Alors si je vous mettre le PA2 comme une sortie :
GPIOA->MODER |=(1<<4) ; //PA2output
Si je vous mettre plusieurs broches en sortie PA1, PA3, PA5, PA6 ;
GPIOA->MODER |= (1<<2)| (1<<6)| (1<<10)| (1<<12) ;
Vous pouvez utiliser des valeurs décimales, binaires ou hexadécimales, ou encore le
décalage selon votre méthode préférée.
3-Configurer le type de sortie du pin
Dans cette partie on va configurer le registre GPIOX_OTYPER .
GPIOA_OTYPER est mappé sur l’adresse : 0x40020004 (Adresse de base de GPIOA+
adresse offset de OTYPER).
Alors dans ce registre on a juste 16 bits qu’on peut configurer les autres sont réservés.
Si je mets :
0 : sortie push-pull (par défaut)
1 : sortie open-drain
Une sortie push-pull est capable de fournir du courant à la charge connectée et de la
mettre à la masse. Cela signifie que la sortie peut être utilisée pour envoyer des
signaux logiques à haut niveau (1) ou à bas niveau (0).
Une sortie open-drain, en revanche, ne peut pas fournir de courant à la charge. Elle ne
peut que la mettre à la masse. Pour envoyer un signal logique à haut niveau (1), il faut
utiliser une résistance de pull-up pour maintenir la tension à haut niveau lorsque la
sortie open-drain est mise à la masse. Pour envoyer un signal logique à bas niveau (0),
la sortie open-drain est mise à la masse directement.
Alors si je vous mettre le PA2 Sortie push-pull :
GPIOA->OTYPER &=~(0x1 << 2);
4-Configurer la vitesse du pin
Dans cette partie on va configurer avec le registre GPIOx_OSPEEDR.
GPIOA_OSPEEDR est mappé sur l’adresse : 40020008
Dans ce registre chaque 2 bits est associé a un pin avec la relation 2y,2y+1 (avec y est
le numéro de pin).
Alors on :
00 : faible vitesse
01 : vitesse moyenne
10 : vitesse élevée
11 : très haute vitesse
Alors si je veux mettre PA2 comme une vitesse élevée , je vous mettre 0 dans bit[4] et
1 dans le bit[5]
GPIOA->OSPEEDR &= ~ (0x1 << 4) ; //mettre 0 dans bit 4 (c’est optionnel c’est la valeur
par défaut mais pas toujours pour les autres GPIO)
GPIOA->OSPEEDR |= (0x1 << 5) ;;// mettre 1 le bit 5
5-configuration pull-up/pull-down
Dans cette section, nous allons configurer à l'aide du registre GPIOx_PUPDR. Ce
registre nous permet d'utiliser des résistances internes pull-up ou pull-down. Chaque
2 bits sont associés à un pin selon la relation 2y, 2y+1 (où y est le numéro du pin).
Alors on :
00 : No pull-up, pull-down
01 : pull-up
10 : pull-down
11 : Reserved
Application :
En suivant les étapes précédentes, nous voulons créer une fonction de configuration
du port. Trois LED sont connectées à la PORTA (broches 1, 2 et 3) ;
Void GPIO_Config(void){
RCC->AHB1ENR |=0X01; // activer le clock de la port A
GPIOA->MODER |=(0x1<<2 | (0x1<<4)| (0x1<<6); // configurer PA1,2,3 comme sortie .
GPIOA->MODER &= (unsigned) ~ (0x1 << 3) | (unsigned)( ~(0x1<<5)) | (unsigned)( ~(0x1<<7));// cette instruction
n’est pas
nécessaire dans
notre cas
GPIOA->OTYPER &=(unsigned)~(0x7 << 1); // definir sortie avec push pull
GPIOA->OSPEEDR |= (0x1 <<3) | (0x1 << 5) | (0x1 << 7); // Définir la vitesse plus élevés
}
void delay_ms(uint32_t ms){
// Convertir le délai en nombre de cycles d'horloge
uint32_t delay = ms * (SystemCoreClock / 1000);
while (delay--) {// Boucle de délai en utilisant l'instruction NOP
__NOP(); }
}
//Fonction Main
int main(){
GPIO_Config() ; // appel de fct en haut pour configurer les port
While(1){
GPIOA->ODR |= 0x7 << 1; //écrire 1 sur pin (1,2,3) càd allumer les leds
delay_ms(1000); //delay
GPIOA->ODR &=(unsigned) ~(0x7<<1);//écrire 0
delay_ms(1000);
} //end while
}//end main
On écrivant ce code dans IDE Keil U Vision comme ci -dessous :
Partie 2 :
Dans cette partie on va clignoter les leds brancher sur PA1-PA6 séquentiellement l’une après l’autre.
Pour réaliser cette partie on a utilisé deux méthodes :
1-Méthode 1 (méthode simple )
While(1){
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET);//allumer
HAL_Delay(300);//delay
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);//eteindre
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_SET);//allumer
HAL_Delay(300);//delay
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_RESET);//eteindre
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_SET);//allumer
HAL_Delay(300);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
HAL_Delay(300);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
HAL_Delay(300);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_SET);
HAL_Delay(300);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_RESET);
}
Ce code allume et éteint chaque broche l'une après l'autre avec un délai de 300ms entre
chaque broche avec la fonction HAL_Delay(300).
2-Méthode 2 (méthode avec boucle for( ;;))
Pour résoudre cette application le code précédent utilise 18 ligne,
Par contre on peut les simplifier et optimiser notre code en utilisant ce code suivant :
While(1)
{
short i; //declaration local d’un variable
for(i=1;i<7;i++)
{
HAL_GPIO_WritePin(GPIOA, 1<<i, GPIO_PIN_SET);\\allumer
HAL_Delay(300);\\delay de 300 ms
HAL_GPIO_WritePin(GPIOA,1<<i, GPIO_PIN_RESET);\\eteindre
}
}
Partie 3:
Dans cette partie, nous allons utiliser un afficheur 7 segments pour afficher un
compteur allant de 0 à 9 sur le PORT D de notre microcontrôleur. Nous allons
travailler sur le même projet que les parties 1 et 2 et ajouter les modifications
nécessaires pour atteindre notre objectif. Pour commencer, nous devons
activer l'horloge du PORT D en utilisant l'instruction suivante :
__HAL_RCC_GPIOD_CLK_ENABLE();
Après l’activation de l’horloge, maintenant il faut configurer les broches utilisés,
c’est-à-dire PD0-PD6 comme sorties :
GPIO_InitStruct.Pin=
GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6;
}
Remarque La fonction Static void MX_GPIO_Init() déjà générée dans la partie 1 sera
utilisée pour écrire toutes les configurations nécessaires.
Nous allons maintenant passer à la fonction Main() pour écrire notre
programme qui inclura la déclaration d'un tableau de 10 éléments, représentant
chaque numéro en hexadécimal
//la déclaration d’un tableux de 10 éléments qui contient les présentation de chaque
numéro en hexadécimal/
char value[10] ={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
//char value[10] ={63,6,91,79,102,109,125,7,127,111}
while (1)
{
https://github.com/Mouad-elatmani/Cortex_M4_STM32
solution des applications par la méthode du
registre
L’IDE utilisée dans cette partie est le KEIL U VISION 5.(voir annexe).
On va répéter toutes les applications faites en méthode graphique mais en utilisant
cette fois les registres
Partie 1 :
Dans cette partie on a 6 leds brancher sur les pins PA1 -PA6, et nous devons
clignoter 3 .
Voici le code de cette partie qui sera divisé en deux partie (configuration des
pins et code principale) :
Configuration des broches :
void GPIO_Init(void){
// définir PA1-PA6 commme sortie
GPIOA->MODER |=(0x1<<2) | (0x1<<4)| (0x1<<6)| (0x1<<8)| (0x1<<10)| (0x1<<12);
GPIOA->MODER &= (unsigned)~(0x1<<3)|(unsigned)~(0x1<<5)|(unsigned)~(0x1<<7)
|(unsigned)~(0x1<<9)|(unsigned)~(0x1<<11)|(unsigned)~(0x1<<13);
GPIOA->OTYPER &=(unsigned)~(0x7F<<1); //configurer les broches comme sortie push-pull
GPIOA->OSPEEDR |= (0x1 <<3) | (0x1 << 5) | (0x1 << 7); // définir le vitesse élevée
GPIOA->OSPEEDR |= (0x1 <<3) | (0x1 << 5) | (0x1 << 7)
| (0x1 << 9)| (0x1 << 11)| (0x1 << 13); // Définir la vitesse
plus élevés}
Alors GPIO_Init est une fonction qui contient les configurations des broches utilisées lors de
nos programme , alors pour le code principal est :
#include "stm32f401xe.h"
void GPIO_Init(void);
void delay_ms(uint32_t ms)
{
uint32_t delay = ms * (SystemCoreClock / 1000); // Convertir le délai en nombre de
cycles d'horloge
while (delay--)
__NOP(); // Boucle de délai en utilisant l'instruction NOP}
int main()
{
GPIO_Init();
while(1){
GPIOA->ODR |= 0x7 << 1; //allumer led avec décalage
delay_ms(500);
GPIOA->ODR &=(unsigned) ~(0x7<<1);//éteindre
GPIOA->ODR |= 0x7 << 4;//allumer
delay_ms(500);//delay
GPIOA->ODR &=(unsigned) ~(0x7<<4);//eteindre
}
}
Application 2:
Dans cette partie on va réaliser un compteur 0-9 avec un afficher 7 seg-cat sur PORT D
de notre microcontrôleur.
Voici le code utilisé pour configurer les broches :
void GPIO_config_D(void){
RCC->AHB1ENR |=0X08; // active l’horloge de du port D
GPIOD->MODER |=0x1555; //PD0-PD6 comme sortie
GPIOD->OTYPER &=(unsigned)~(0x7F);//sortie pull-push
GPIOA->OSPEEDR |=0x2AAA;
}
Alors le code pour réaliser un compteur est :
#include "stm32f401xe.h"
GPIO_config_D();
char value[10] ={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
void delay_ms(uint32_t ms)
{
uint32_t delay = ms * (SystemCoreClock / 1000); // Convertir le délai en nombre de
cycles d'horloge
while (delay--)
__NOP(); // Boucle de délai en utilisant l'instruction NOP}
int main()
{
GPIO_config_D();
while(1){
for(int i =0;i<10;i++)
{
GPIOD->ODR |= value[i];//allumer leds de 7seg
delay_ms(250);//delay
GPIOD->ODR &=(unsigned) ~(value[i]);//eteindre leds 7segs
}
}
}
Tous les codes précédents sont faits avec un système d’horloge par défauts, mais si
vous voulez définir votre horloge qui dépend de votre application (par exemple
travailler avec une horloge extérieure)
Voici le code suivant :
Ce code configure l'horloge pour utiliser l'oscillateur externe (HSE) et configure le PLL
pour utiliser l'HSE comme source, avec des valeurs de PLLM, PLLN et PLLP définies. Il
vérifie également que l'HSE est prêt à être utilisé et que le PLL est prêt avant de
sélectionner le PLL comme horloge système.
//Active Horologe extern
RCC->CR |= RCC_CR_HSEON;
// attendre que l’horloge soit prêt
while (!(RCC->CR & RCC_CR_HSERDY)); // dans notre cas simulation sur Proteus on a pas besoin de cette
instruction
// configuration de PLL
RCC->PLLCFGR = RCC_PLLCFGR_PLLSRC_HSE | // déterminer HSE comme une source de PLL
(192 << 6) | // PLLM = 8
(4 << 16) | // PLLN = 192
(2 << 27); // PLLP = 4
// Active le register PLL
RCC->CR |= RCC_CR_PLLON;
while (!(RCC->CR & RCC_CR_PLLRDY));
// Sélectionner PLL comme source Horloge
RCC->CFGR |= RCC_CFGR_SW_PLL ;
// Wait for PLL to be selected as system clock
while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL);
Donc on peut jouer sur le registres et sélection l’horloge qui répond au besoin de notre application.
Remarque :
Il est important de noter que ces étapes sont très détaillées et nécessitent une bonne
compréhension de la puce STM32F401VE et de ses registres. Il est fortement recommandé de
consulter la documentation du fabricant et de lire le manuel de l'utilisateur pour obtenir des
informations détaillées sur la configuration de l'horloge. Ou bien les configurer avec la méthode
graphique
Application3: Application LED avec Botton d'interruption et
déclencheurs
Maintenant, nous allons aborder une autre application qui concerne les interruptions.
Nous allons d'abord donner une brève introduction sur les interruptions
Introduction
Les interruptions et les déclencheurs dans Cortex-M4 font référence au mécanisme
par lequel le processeur est informé d'un événement et arrête temporairement sa
tâche actuelle pour gérer une demande de haute priorité.
Les interruptions sont des événements asynchrones qui sont générés par des
périphériques externes ou internes, tels qu'un temporisateur ou un périphérique de
communication, et déclenchent le processeur pour appeler une routine de service
d'interruption spécifique (ISR).
L'ISR gère l'événement et renvoie le contrôle au programme principal une fois terminé.
Les déclencheurs sont utilisés pour implémenter les changements de contexte et les
exceptions logicielles.
Le processeur peut également prioriser et gérer l'ordre dans lequel les interruptions
sont traitées.
#include "GPIO.h"
#include "EXTI.h"
int main(void) {
EXTI_EnableClock();// Active l'horloge d'interruption externe
EXIT_INIT(0, 0, FALLING);//Configure l'interruption externe à l'aide
de la fonction EXIT_INIT
Led_Button_INIT();// configurer la LED et le bouton.
while(1){
}
return 0;
}
Introduction
L'USART (Universal Asynchronous/Synchronous Receiver-Transmitter) est un
périphérique couramment présent dans les microcontrôleurs dotés d'un processeur
Cortex M4. Il permet la transmission et la réception de données série entre le
microcontrôleur et un autre appareil, avec la possibilité de fonctionner en mode
asynchrone ou synchrone pour la communication entre microcontrôleurs.
Objectif
Dans cette application , nous allons configurer un microcontrôleur avec un processeur
Cortex M4 (STM32F401) en écrivant un code en C. Ce code initialisera la transmission
de données (une chaîne de caractères "SEAI 2022 !") à travers l'USART de PA2.
Nous pourrons récupérer ces données en utilisant un outil de terminal virtuel dans
Proteus.
Code de Programme en C
#include "GPIO.h"
#include "USART.h"
void TRANSMIT_DATA (char *Data); // Prototype de la fonction TRANSMIT_DATA
void TRANSMITTER_PIN_INIT (void); // Prototype de la fonction
TRANSMITTER_PIN_INIT
int main(void) {
//initialise la communication USART avec un débit en bauds de 0x683,
//un mode de transmission, une longueur de mot de 8 bits et un
suréchantillonnage de 16x.
Maintenant il faut cherchez dans la barre des outils de < pack installer> cette partie nous permettons de
télécharger tous les devices et les bibliothèques que nous allons utiliser.
Après o choisit la famille de microcontrôleur on écrivant leur nom dans la barre de recherche :STM32F401VEHX ,
Une fois la famille ou bien le microcontrôleur télécharger, il faut revenir au keil pour créer le premier projet ,
Cliquer sur <new uvison projet> et sélectionne la série de votre microcontrôleur et cliquer sir ok :
Lorsqu’on clique sur OKI une fenêtre de <manage time environnement> est s’ouvre, dans cette fenêtre on
sélectionne le core et les startups et on clique sur ok :
QAQ&url=https%3A%2F%2Fwww.st.com%2Fresource%2Fen%2Freference_manual%2Fdm00135183-stm32f446xx-advanced-arm-based-32-bit-
mcus-stmicroelectronics.pdf&usg=AOvVaw1xMhfIcYj5KZGwMN-VVjUR
Livres:
Mastering STM32 A step-by-step guide to the most complete ARM Cortex-M platform, using a free and
powerful development environment based on Eclipse and GCC Carmine Noviello
Discovering the STM32 Microcontroller Geoffrey Brown
The Definitive Guide to ARM Cortex-M3 and Cortex-M4 Processors joseph yiu