Notions de bases en C

Les variables

Une variable est un « conteneur » qui stocke les données. Ce conteneur peut occuper un ou plusieurs octets dans la mémoire du microcontrôleur (en général la mémoire vive RAM).

Une variable doit toujours être déclarée avant son utilisation. Cette déclaration a la forme suivante:

type identificateur;

ou bien la forme avec initialisation:

type identificateur = valeur;

type: c'est le type de la variable ou le type de données:

Il indique au compilateur comment manipuler les données stockées dans la variable. Exemple de type: float. C’est un des types de données que l’on verra par la suite.

Il indique aussi quelle quantité d’espace mémoire il faut réserver pour stocker le contenu de la variable.

L’identificateur ou le nom de la variable :

Il est utilisé uniquement pour identifier la variable chaque fois qu’on veut y avoir accès ou modifier son contenu. Dans l'exemple de programme vu précédemment  « radius » et « perimeter » sont des identificateurs.

La figure ci-après illustre une représentation du stockage de trois variables dans un espace mémoire d’un microcontrôleur 8 bits, comme par exemple ceux de la famille PIC18:


 

La première variable : length, est de type int; elle est codée sur 16 bits pour le compilateur MPLAB XC8. Ainsi elle occupe deux octets d’espace mémoire.

La seconde variable : letter, du type char, elle occupe 8 bits d’espace mémoire; soit un mot.

La troisième variable : weight de type float, codée sur 32 bits pour la majorité des compilateurs, elle est contenue dans quatre mots soit 4 octets de la mémoire de données.

Exemple d'application 1: 

(+) Cliquer pour voir cet exemple(−) Fermer

Le simulateur intégré dans l’environnement de développement MPLAB X sera utilisé comme outil, pour afficher des données sur la zone d'affichage réservée au régistre UART, dans la fenêtre de déboggage.

Avant de poursuivre, il faut d'abord configurer le simulateur pour qu'il exécuter cette tâche, étant donné que le compilateur MPLAB XC8 ne permet pas d'afficher, des données sur une console d'un régistre quelconque du simulateur, en particulier avec la fonction prédéfinie printf().

1- Configuration du simulateur:

Pour configurer le simulateur, deux étapes sont nécessaires:

Etape 1: ajouter dans le code source:

  • une fonction d'initialisation de l'UART: init_uart();
  • une fonction putch() qui affiche des caractères; celle-ci sera appelée par la fonction prédéfinie printf(), pour l'affichage de données sous forme de chaînes de caractères.

Etape 2: valider l'affichage de l'UART du simulateur MPLAB X.

2 - Essai de mise en oeuvre:

Nous allons afficher le message "Hello, world !" sur la console UART du simulateur:

Après le lancement de MPLAB X, on va créer un nouveau projet: cliquer sur New Project ou sur Crtl+Maj+N.  Dans la fenêtre qui s’ouvre choisir : dans Catégories : Microchip Embedded, et dans Projects : Application Project(s), Puis cliquer sur Next

Dans Device, taper pic16f887 ; dans Tools, sélectionner Simulator ;  puis cliquer sur Next.

Dans Compiler Toolchains, sélectionner le compilateur XC8, puis cliquer sur Next.

Donner le nom du projet dans Project Name : Test_uart, puis choisir le répertoire qui contiendra le projet (Project Location) en cliquant sur Browse

Pour valider le tout, cliquer sur Finish.

Ensuite, faire un clic droit sur le projet nouvellement crée, puis :

Dans la liste des menus qui s’ouvre, clic gauche sur Properties, sélectionner Simulator, puis dans Options for Simulator, sélectionner Uart1 IO Options, cocher la case Enable Uart1 IO, puis Output sur Windows ;  ci-dessous un exemple de figure qui indique les paramètres de configuration:

Pour valider cette configuration cliquer sur OK. Cette fenêtre se ferme.

Dans l'affichage graphique général du projet, en haut à gauche le projet Test_uart contient plusieurs dossiers; aller dans le dossier Source Files, puis un Clic droit, ensuite New, puis cliquer sur main.c, et dans la petite fenêtre qui s'ouvre, renommer le main_test_uart par exemple; puis cliquer sur Finish.

Attendre que le compilateur importe les librairies nécessaires au projet. Puis, ajouter la librairie d’entrées-sorties standard « stdio.h » au début du programme. 

Le début du programme devra contenir deux fichiers entêtes :

#include <xc.h>
#inculde <stdio.h>

Le programme main_test_uart.c va contenir trois fonctions :  main(), init_uart() et putch() ; les prototypes de ces trois fonctions peuvent être déclarés ensuite :

void main(void);
void init_uart(void);
void putch(char);

Pour que le simulateur puisse afficher des données la console UART,  les deux fonctions init_uart() et putch() devront ressembler à ceci :

void init_uart(void) {
    TXSTAbits.TXEN = 1;   //enable transmitter
    RCSTAbits.SPEN = 1;   //enable serial port
}

Puis

void putch(char data) {
    while(!PIR1bits.TXIF){ //wait until the transmitter is ready
        continue;}
    TXREG = data;          //send one character
}

Exemple de programme qui permet d'afficher un message sur la console UART du simulateur:


/******************************************************************************
 | Getting start with C programming in embedded systems
 | File:   main_test_uart.c (test_uart: main program)
 | Author: 
 | 
 | Created on 8 septembre 2025, 11:17
 *****************************************************************************/

/*-----------------------------------------------------------------------------
  HEADER FILES
  NOTE: The processor specific header file is not required since we will not
  be using any processor specific features - this is all generic C code
-----------------------------------------------------------------------------*/
#include <xc.h>
#include <stdio.h>
//Compiler directive WDTE = OFF stop the 16F887 automatic reset.
#pragma config WDTE=OFF
/*----------------------------------------------------------------------------
 FUNCTION PROTOTYPES
 ----------------------------------------------------------------------------*/
void main(void);
void init_uart(void);
void putch(char);
/*============================================================================
 FUNCTION: init_uart
 DESCRIPTION: initialize uart, because we are using xc8
 PARAMETERS: none
 RETURN: nothing
 REQUIREMENTS: none
 ===========================================================================*/
void init_uart(void) {
    TXSTAbits.TXEN = 1;   //enable transmitter
    RCSTAbits.SPEN = 1;   //enable serial port
}
/*============================================================================
 FUNCTION: putch
 DESCRIPTION: print out single char. This function is call by printf function
 PARAMETERS: character
 RETURN: nothing
 REQUIREMENTS: none
 ===========================================================================*/
void putch(char data) {
    while(!PIR1bits.TXIF){ //wait until the transmitter is ready
        continue;}
    TXREG = data;          //send one character
}
/*============================================================================
 FUNCTION: main
 DESCRIPTION: print out the message Hello world 
 PARAMETERS: none
 RETURN: nothing
 REQUIREMENTS: none
 ===========================================================================*/
void main(void) {
    init_uart();
    printf("\nHello, world !");
    while(1){ // wait here
        ;
    }
}

Enregistrer, puis cliquer sur Debug Main Project ; attendre et corriger d’éventuelles erreurs.
En cliquant sur l’ongle UART 1 Output nous obtenons :

sim_uart_test_out1

3 - Exemple: affichage des variables.

Ce programme a pour but d'illustrer la notion de variables. Nous allons afficher différents types de variables, ainsi que la taille mémoire qui leur est réservée dans la console UART du simulateur. 

On commencera d'abord par créer un nouveau projet, en suivant la procédure de l'essai de mise en oeuvre (2). Puis plusieurs variables vont être déclarées, ensuite initialisées. Le sous-programme main() se chargera d'afficher toutes les variables créées, ainsi que la taille mémoire qui leur est réservée.

Un exemple de programme accomplissant cette tâche est donné ci-dessous:


/******************************************************************************
 | Getting start with C programming in embedded systems
 | File:   main_ex1.c (Example1: main program)
 | Author: 
 | 
 | Created on 8 septembre 2025, 16:38
 *****************************************************************************/

/*-------------------------------------------------------------------------------
  HEADER FILES
  NOTE: The processor specific header file is not required since we will not
  be using any processor specific features - this is all generic C code
-------------------------------------------------------------------------------*/
#include                  // Processor specific header file
#include               // Standard I/O - required for printf() function
//Compiler directive WDTE = OFF stop the 16F887 automatic reset.
#pragma config WDTE=OFF
/*-------------------------------------------------------------------------------
  PROGRAM CONSTANTS
-------------------------------------------------------------------------------*/
#define csteValue 50
/*----------------------------------------------------------------------------
 FUNCTION PROTOTYPES
 ----------------------------------------------------------------------------*/
void main(void); 
void init_uart(void);
void putch(char);
/*============================================================================
 FUNCTION: init_uart
 DESCRIPTION: initialize uart, because we are using xc8
 PARAMETERS: none
 RETURN: nothing
 REQUIREMENTS: none
 ===========================================================================*/
void init_uart(void) {
    TXSTAbits.TXEN = 1;   //enable transmitter
    RCSTAbits.SPEN = 1;   //enable serial port
}
/*============================================================================
 FUNCTION: putch
 DESCRIPTION: print out single char. This function is call by printf function
 PARAMETERS: character
 RETURN: nothing
 REQUIREMENTS: none
 ===========================================================================*/
void putch(char data) {
    while(!PIR1bits.TXIF){ //wait until the transmitter is ready
        continue;}
    TXREG = data;          //send one character
}
/*===============================================================================
  FUNCTION:     main()
  DESCRIPTION:  Prints out the storage size of each variable and their countent
  PARAMETERS:   none
  RETURNS:      nothing
  REQUIREMENTS: none
===============================================================================*/
void main(void)
{
    init_uart();
        /*-----------------------------------------------------------------------
        VARIABLE DECLARATIONS
        -----------------------------------------------------------------------*/
        char charVariable;              // first variable. Character
        int intVariable;                // second variable. Integer
        float floatVariable;            // third variable. Floatting point
        double doubleVariable;          // fourth variable. Double
        long longVariable;              // fifth variable. Long,same as "long int"
        short shortVariable;            // sixth variable. Short,same as "short int"

        /*-----------------------------------------------------------------------
	  Initialize Variables
	-----------------------------------------------------------------------*/
	charVariable = 'P';
        intVariable = 50;
	floatVariable = 351.74;
	doubleVariable = 2645;
	longVariable = 56213849;
	shortVariable = 9;

	/*-----------------------------------------------------------------------
	  Print out storage size of each variable
	-----------------------------------------------------------------------*/
	printf("\nFirst variable holds %c, and requires %d byte ",charVariable, sizeof( char ));
        printf("\nSecond variable holds %d, and requires %d byte ",intVariable, sizeof( int ));
        printf("\nThird variable holds %f, and requires %d byte ",floatVariable, sizeof( float ));
        printf("\nFourth variable holds %e, and requires %d byte ",doubleVariable, sizeof( double ));
        // %e to print scientific notation can also be use 
        printf("\nFifth variable holds %ld, and requires %d byte ",longVariable, sizeof( long ));
        printf("\nSixth variable holds %d, and requires %d byte ",shortVariable, sizeof( short ));
    while(1){ //wait here
        ;
    }
}

Pour l'exécuter, cliquer sur Build Project, si tout s'il n'y a pas d'erreur de compilation, le programme sera automatiquement exécuté. Cliquer sur l'onglet UART 1 Output de la console. On obtiendra un résultat semblable à celui de la figure ci-dessous:

test_variables_uart_out1


Les variables constantes :

Le terme variable constante sonne comme une contradiction, mais c’est pourtant une description précise de ce que cela représente. Dans les lignes précédentes nous avons parlé de variables. Tous les concepts relatifs aux variables restent les mêmes en ce qui concerne les constantes à une exception près, le type est modifié par le mot clé const :

const type indentificateur = valeur ;

Ceci a un effet dans la création de la variable. Son allocation mémoire et son initialisation se font comme une variable classique ; mais le mot clé const permet d’éviter que la  code ne change le contenu de cette variable.

Exemple de déclaration :

const float PI = 3.14159;

Le Linker pourra réserver 4 octets pour stocker le nombre 3.14159  grâce à cette instruction. Mais si on veut économiser la ressource, comme c’est le cas des systèmes embarqués, il est plus intéressant d’utiliser la directive "#define".

Dans ce cas, la syntaxe est le suivante :

# define label text

Exemple de déclaration :

# define  PI  3.14159

Ainsi à chaque fois que le préprocesseur rencontrera PI, il le remplacera par 3.14159.

Les constantes littérales:

Ce sont des valeurs telles que les nombres, les caractères ou les chaînes de caractères qui sont affectés à des variables, et susceptibles de ne pas changer au cours du déroulement du programme.

On distingue quatre types de constantes littérales:

Les entiers, les réels, les caractères et les chaînes de caractères.

Constantes entières:

Elles peuvent s'écrire dans le système décimal, octal ou hexadécimal:

Exemple:  

const int Max_Int 32768; 

# define Value 0x6E

Constantes réelles:

Ce sont des nombres décimaux contenant un point décimal et éventuellement un exposant séparé du nombre par " E ". Ils sont appelé des nombres flottants ou en virgule flottante.

Constantes caractères:

Elles sont constituée d'un caractère entre deux apostrophes.

Exemple:

# define letter 'A'

Entre les apostrophes il peut avoir aussi une suite de caractères dont le premier commence par " \ " (caractère d'échappement).

Constantes chaines de caractères:

Elles sont écrite entre guillemets.

Exemple:

# define grettings "Hello, world!"

Les constantes symboliques:

Une constante symbolique est un label ou un nom utilisé pour représenter des valeurs fixes qui ne pourront pas changer durant l’exécution du programme.

Elle est utilisée comme opérande dans une opération arithmétique ou logique, ou comme un paramètre pour une fonction.

Exemple d'application 2: 

(+) Cliquer pour voir cet exemple(−) Fermer

Cet exemple a pour but d'afficher les constantes créées dans le programme sur la console UART du simulateur.

Créer un nouveau projet, en respectant les étapes de l'exemple d'application sur les variables. Puis créer des constantes en leur donnant des valeurs. Le sous-programme main() se charge d'afficher les constantes créées sur la console UART.

Un exemple de programme accomplissant cette tâche est donné ci-dessous:


/******************************************************************************
 | Getting start with C programming in embedded systems
 | File:   main_ex2.c (Example2: main program)
 | Author: 
 | 
 | Created on 9 septembre 2025, 12:47
 *****************************************************************************/

/*-------------------------------------------------------------------------------
  HEADER FILES
  NOTE: The processor specific header file is not required since we will not
  be using any processor specific features - this is all generic C code
-------------------------------------------------------------------------------*/
#include                  // Processor specific header file
#include               // Standard I/O - required for printf() function
//Compiler directive WDTE = OFF stop the 16F887 automatic reset.
#pragma config WDTE=OFF
/*-------------------------------------------------------------------------------
  PROGRAM CONSTANTS
-------------------------------------------------------------------------------*/
#define Letter 'A'
#define Number 50
#define Grettings "Hello, world !"
/*----------------------------------------------------------------------------
 FUNCTION PROTOTYPES
 ----------------------------------------------------------------------------*/
void main(void); 
void init_uart(void);
void putch(char);
/*============================================================================
 FUNCTION: init_uart
 DESCRIPTION: initialize uart, because we are using xc8
 PARAMETERS: none
 RETURN: nothing
 REQUIREMENTS: none
 ===========================================================================*/
void init_uart(void) {
    TXSTAbits.TXEN = 1;   //enable transmitter
    RCSTAbits.SPEN = 1;   //enable serial port
}
/*============================================================================
 FUNCTION: putch
 DESCRIPTION: print out single char. This function is call by printf function
 PARAMETERS: character
 RETURN: nothing
 REQUIREMENTS: none
 ===========================================================================*/
void putch(char data) {
    while(!PIR1bits.TXIF){ //wait until the transmitter is ready
        continue;
    }
    TXREG = data;          //send one character
}
/*===============================================================================
  FUNCTION:     main()
  DESCRIPTION:  Prints out the storage size of each variable and their countent
  PARAMETERS:   none
  RETURNS:      nothing
  REQUIREMENTS: none
===============================================================================*/
void main(void)
{
    init_uart();
    // print out constants
    printf("\nFirst constant is %c", Letter);
    printf("\nSecond constant is %d", Number);
    printf("\nThird constant is %s", Grettings);
    while(1){ // wait here
        ;
    }    
}

Pour l'exécuter, cliquer sur Build Project, si tout s'il n'y a pas d'erreur de compilation, le programme sera automatiquement exécuté. Cliquer sur l'onglet UART 1 Output de la console. On obtiendra un résultat semblable à celui de la figure ci-dessous:

test_constant_uart_out1


Les exemples d'applications présentés dans cette partie ont utilisé la fonction prédéfinie printf(), pour afficher des données sur l'UART du simulateur MPLAB X. Cette fonction sera abordée dans le paragraphe consacré à la bibliothèque d'entrées-sorties du langage C.

Ce site web utilise des cookies

Certains d’entre eux sont essentiels pour son fonctionnement et d’autres nous aident à améliorer l’expérience utilisateur (cookies traceurs). Vous pouvez décider vous-même si vous autorisez ou non ces cookies. Merci de noter que, si vous les rejetez, certaines fonctionnalités du site pourront être défaillantes.