#format wiki #language fr #acl +All:read <> = TD = == Présentation == Les TD de l'UE 441 ont plutôt vocation à étudier de façon théorique les interconnexions et méthodes d'utilisation des différents modules que l'on peut retrouver dans un micro-contrôleur. Cette section a pour but de présenter des méthodes générales de résolution de ce type de TD et de répertorier les TD traités en cours. == Circuits usuels == Un micro-contrôleur est un système complexe avec diverses fonctionnalités, capable de gérer des entrées-sorties, réaliser des calculs, stocker des variables en mémoire... Ces différentes opérations sont réalisées par des circuits spécialisés contenus dans l'ensemble qu'est le micro-contrôleur. On présente ici ceux rencontrés en TD : * Micro-processeur : Exécute les instructions des programmes et gère les données mises en jeu. Ils ne possèdent pas de pattes de gestion d'entrée-sortie mais de bus d'adresses et de données. * Mémoire morte (ROM : ''Read Only Memory'') : Chargée pendant la programmation du micro-contrôleur, elle est accessible en lecture seule lorsque celui-ci est en fonctionnement. La puce correspondante ne possède donc pas de broche d'écriture. * Mémoire vive (RAM : ''Random Access Memory'') : Mémoire utilisée pour réaliser des calculs pendant le fonctionnement du micro-contrôleur. Les données ne sont pas sauvegardées. La puce correspondante possède une broche pour autoriser l'écriture. == Bus et pins usuels == Les noms des pins utilisés sont normalement conventionnés. Cependant, en cas de doute, il vaut mieux se référer à la datasheet du composant. * '''Ax''' (x étant un nombre) : Fil d'adresse, la taille du bus d'adresses (nombre de fils d'adresse) détermine l'espace adressable par le processeur. ''Exemple : 16 fils d'adresse permettent de réaliser 2^16 adresses'' * '''Dx''' (x étant un nombre) : Fil de donnée, la taille du bus de données (nombre de fils de donnée) détermine la taille (en bits) des variables stockées en mémoire. On peut déduire la taille mémoire disponible en multipliant le nombre d'adresses réalisables par la taille des données stockées. * '''WE''' : Write Enable. Autorise l'écriture dans la mémoire. * '''CS''' : Chip Select. Permet d'activer ou désactiver la puce concernée. * '''RS''' : Register Select. == Sujets de TD == * Étude structurelle du micro-ordinateur Replica1 : [[attachment:TD_Replica1.pdf]] * Correction : [[attachment:Correction_TD_Replica1.pdf]] = TP = * TP N°1 : Prise en main de l’environnement de développement MCUXpresso ; * TP N°2 : Les timers ; * TP N°3 : La liaison série ; * TP N°4 : Utilisation du langage assembleur sur ARM Cortex M0+ ; * TP N°5 : Synthèse UART / Timer ; * Examen : Tableau d’affichage ; * TP N°6 : Appel de fonctions interruptions ; * TP N°7 : Liaisons I2C * Exemple de Compte-rendu en 2018 : [[attachment:TP5-LEQUIN-DHOOGE.pdf]] * TP N°8 : Convertisseurs numérique vers analogique et analogique vers numérique ; * Projet. = Programmation = == Présentation == Cette section a pour but de répertorier des exemples de code utiles pour les TP (et pour le partiel) de l'UE441 du M1 IST de EEA. Vous pouvez évidement contribuer à cette page mais assurez vous de rajouter du code compréhensible (commentaires, nom de variables explicites, etc), fonctionnel, et bien répertorié (cette page a des sections, respectez les). Un fichier de présentation un peu général a été rédigé par M. Juton et est disponible ici : [[attachment:Creation_projet_MCUXPRESSOIDE.pdf]]. == Documentation == Un de vos meilleurs amis et de vos pires ennemis lorsque vous programmerez sur les LPC804 sera le [[attachment:LPC804_UserManual.pdf]]. Ce monstre de 355 pages regroupe toutes les fonctions utiles et toute la documentation nécessaire pour programmer sur la carte. Le problème est que, si on ne l'a jamais fait, lire cette doc est un peu compliqué. Voici un exemple rapide de lecture de ce document pour réaliser une fonction demandée. Dans le sujet0 fourni pour préparer le partiel de cette année, il est demandé de paramétrer un convertisseur analogique/numérique. Pour cela on nous indique le chapitre 22 de la doc. Il faut dans un premier temps alimenter le ADC. Pour cela on suit la doc à partir du paragraphe d'introduction et on trouve qu'il faut aller voir dans le registre {{{LPC_SYSCON->PDRUNCFG}}}. Dans la table indiquée (Table 84), on trouve que pour alimenter le ADC il faut mettre le bit 4 (première colonne sur la ligne ADC_PD) à 0 (Powered). On en déduit qu'il faut utiliser l'instruction {{{#!highlight C LPC_SYSCON->PDRUNCFG &= ~(1<<4) }}} De même pour toutes les fonctions demandées. Tout est dans la doc, il suffit de trouver la bonne page. == Code de base == == LED == La LED est l'élément de base pour sortir une info basique sur ce que fait le programme. Comme toutes les entrée/sortie, il faut définir le sens avec la variable {{{DIR0}}}. Pour une LED, il faut la positionner sur sortie (1). Le registre {{{LPC_GPIO_PORT -> DIR0}}} regroupe les directions pour toutes les entrées sorties. Il faut donc faire un OU logique avec la variable {{{blue (1<<11)}}} qui est un 1 décalé de 11 bits, ce qui correspond à la LED bleue. Pour choisir ensuite l'état de de la LED, il faut faire la même opération avec le registre {{{LPC_GPIO_PORT -> PIN0}}}. Le programme ci-dessous permet de faire clignoter la LED bleue de la carte à un fréquence proche de 1Hz. Si l'on considère que la fréquence est réellement de 1Hz, il permet aussi de déduire le temps d'une instruction machine élémentaire (en comptant le nombre d'instructions nécessaires pour finir la boucle de temporisation). '' Remarque : Malheureusement, il n'y a pas de technique magique pour trouver le numéro du pin correspondant à l'entrée/sortie que l'on veut utiliser. Avec un peu de chance, c'est indiqué directement sur la carte. À défaut, il faudra aller fouiller les schematics et retrouver l'élément qui nous intéresse. '' -- AlexandreD'hooge <> ''Remarque (bis) : Avant toute chose, il faut égalment activer les périphériques GPIO (entrées/sorties Tout ou Rien) et IOCON (configuration des broches en entrée et en sortie). Pour cela, on écrit un 1 logique aux bits de rang 6 et 18 (respectivement GPIO et IOCON) du registre {{{LPC_SYSCON->SYSAHBCLKCTRL0}}}. Sans cela, le programme ne marchera pas sur la carte.'' --Etienne Stransky {{{#!highlight C #include #include #include //bits de GPIO utilises #define blue (1<<11) int main(void){ int cpt; LPC_SYSCON->SYSAHBCLKCTRL0 |= (IOCON | GPIO0); LPC_GPIO_PORT -> DIR0 |= blue; while(1){ LPC_GPIO_PORT -> PIN0 ^= blue; // OU exclusif pour changer l'état de la LED for(cpt=0;cpt<200000;cpt++); // temporisation sale pour attendre à peu près 1s } } }}} {{{#!wiki caution '''Sens et état de la LED''' Bien que cela fonctionne, il est fortement déconseillé de changer le sens de la sortie correspondant à la LED pour la faire clignoter. Si vous rendez ça comme solution elle sera très probablement considérée comme fausse ou au moins très fortement pénalisée }}} == Boutons == Lancer des commandes, c'est bien. Mais récupérer un peu d’interactions avec l'utilisateur, c'est mieux ! Le plus simple pour cela est d'utiliser les boutons. La carte de base en comporte 3 (dont un reset qui peut à tout moment "griller" votre carte donc on va dire 2...). Ils sont montés selon un schéma spécial qui fait que tout appui sur un bouton allume directement la LED associée (basiquement, chaque LED est en série avec un bouton). L'utilisation des boutons, comme toutes les I/O du GPIO, se fait au travers du registre {{{LPC_GPIO_PORT}}}. {{{#!highlight C #include #include #include //bits de GPIO utilises #define button (1<<13) int main(void){ int cpt; LPC_SYSCON->SYSAHBCLKCTRL0 |= (IOCON | GPIO0); while(1){ if ((LPC_GPIO_PORT -> PIN0 & button)==0){ // le bouton est enfoncé // Des instructions... } else{ // il ne l'est pas // Encore des instructions... } // Toujours des instructions... } } }}} D'autres boutons sont utilisables avec l'extension de la carte mais il sont définis dans les header fournis avec. == Timers == La carte utilisée possède différents timers, le plus utilisé étant le timer standard {{{CTIMER0}}}. Son paramétrage (activation, reset, démarrage, division de fréquence...) se fait donc dans le registre {{{LPC_CTIMER0}}}. === Diviseur de Fréquence === Le compteur principal {{{TC}}} est incrémenté à chaque fois que le prescale counter {{{PC}}} (cadencé à la fréquence d'horloge, ici 12MHz) atteint la valeur enregistrée dans le prescale register {{{PR}}}. En pratique on a au début du main : {{{#!highlight C // Préparation des entrées/sorties et périphériques LPC_SYSCON->SYSAHBCLKCTRL0 |= (IOCON | GPIO0 | CTIMER0 ); LPC_GPIO_PORT->DIR0 |= (SEG_SDAT|SEG_SCLK|SEG_LCLK); // Afficheur 4*7 segments LPC_GPIO_PORT->DIR0 |= (LED1|LED2|LED3|LED4); // 4 leds LPC_CTIMER0->TCR = 1; // Déclenchement du compteur Timer Control Register LPC_CTIMER0->PR = 12000; // Diviseur de fréquence }}} == PWM == Pour générer une pwm sur une sortie de la carte, il faut vérifier plusieurs paramètres. Ces paramètres sont détaillés en fin de sujet du TP3. * La sélection de l’horloge: par défaut l’horloge CPU. * Préscalaire dans {{{LPC_CTIMER0->PR}}} * Période du timer {{{LPC_CTIMER0->MR[3]}}} * Demander au timer de reprendre à 0 une fois la période atteinte {{{LPC_CTIMER0->MCR}}} * Le temps à l'état bas de la PWM {{{LPC_CTIMER0->MR[1]}}} * Placer la sortie en mode PWM {{{LPC_CTIMER0->PWMC}}} * Assigner la PWN à la pin voulue (par exemple 19) {{{LPC_SWM->PINASSIGN4}}} En plus de tout ça il faut évidement allumer le timer {{{ LPC_SYSCON->SYSAHBCLKCTRL0 }}}, activer la pin 19 en mode sortie {{{LPC_GPIO_PORT->DIR0}}} et lancer le timer {{{LPC_CTIMER0->TCR}}} comme présenté precedement. Une fois la PWM configurée, il reste à choisir sa forme à l'aide des Shadow Register : {{{LPC_CTIMER0->MSR[3]}}} pour la période et {{{LPC_CTIMER0->MSR[1]}}} pour le temps bas. Le code suivant permet de faire "battre" une LED. C'est un exercice du TP2. {{{#!highlight C #include #include "LPC8xx.h" #include "syscon.h" #include "Multi_Shield.h" #define CTIMER (1<<25) int main(void) { // préparation des entrées/sorties et périphériques LPC_SYSCON->SYSAHBCLKCTRL0 |= (IOCON | GPIO0); LPC_GPIO_PORT->DIR0 |= (SEG_SDAT|SEG_SCLK|SEG_LCLK); // afficheur 4*7 segments // Initialisation du timer principal (Timer Counter) LPC_SYSCON->SYSAHBCLKCTRL0 |= CTIMER; // Activation LPC_SYSCON->PRESETCTRL0 &= ~CTIMER; // Allumer le reset LPC_SYSCON->PRESETCTRL0 |= CTIMER; // Éteindre le reset // CETTE LIGNE NECESSITE DES COMMENTAIRES // Initialisation de la SM LPC_SYSCON->SYSAHBCLKCTRL0 |= SWM; // Activation LPC_SWM->PINASSIGN4 = 0xFFFF01FF; // Association de MATCH1 et LED1 LPC_SYSCON->SYSAHBCLKCTRL0 &= ~SWM; // Extinction de la SM LPC_CTIMER0->PR = 469; // réglage du diviseur de fréquence // MCR (Match Control Register) sert à configurer quoi faire quand un des Match Register atteint le Timer Counter LPC_CTIMER0->MCR |= 1 << 1; // Active le reset du Timer Counter quand il match MR[0] LPC_CTIMER0->MR[0] = 255; // Valeur stockée dans le Match Register 0. Lorsque la valeur du Timer Counter atteindra celle ci, le TC se resetera. LPC_CTIMER0->MR[1] = 0; // Idem pour le Match Register 1 à priori mais on ne lui a pas assigné d'action. /!\ Cette ligne est possiblement inutile /!\ // Le PWMC (PWM Controle register) sert à configurer la sortie de la PWN LPC_CTIMER0->PWMC = 1 << 1; // PWMEN1 à 1 enable PWM for chanel 1 // TCR (Time Control Register) sert à controler le Timer Counter. On l'allume + reset LPC_CTIMER0->TCR = 3; // équivalent à (1<<1)|(1<<2) (enable: bit 1 , reset: bit 2) LPC_CTIMER0->TCR = 1; // On aurait pu mettre aussi (1<<1) ou encore LPC_CTIMER0->TCR &= ~(1<<2) pour juste enlever le 1 sur le bit de reset int largeur = 0; // gestion de la largeur en cours de la PWM int sens = 0; // gestion du sens de variation (plus ou moins intense) while(1) { if((LPC_CTIMER0->TC & 0x3F) == 0){ if(largeur == 0 || largeur == 255) // si on atteint un extrême, on change de sens sens = !sens; if(sens) largeur = (largeur + 1) % 256; // augmentation de la largeur else largeur = (largeur + 255) % 256; // diminution de la largeur LPC_CTIMER0->MR[1] = largeur; // Assignation de la largeur } segments(largeur & 0xFFFF,0); } return 0 ; } }}} Ce code sert à faire "battre" la LED. C'est l'objet d'une question dans le TP2. == Ecran LCD == L'écran LCD est présent sur les extensions de carte pour le LPC804. Son utilisation est assez simple et il fait l'objet d'une petite partie du TP3 dans laquelle on s’intéresse à l'espace mémoire occupé par la fonction {{{sprintf}}}. De plus, il peut servir d'affichage très rudimentaire pour le debug (si on n'a pas envie d'utiliser la console de mcuxpresso ni la visualisation des variables). === code === Voici un code simple d'utilisation de l'écran LCD. D'autres fonctions sont disponibles. {{{#!highlight C #include "lib_UE441_lcd.h" // contient les fonctions utiles pour l'utilisation de l'écran int main(void) { char text[32];// contiendra le texte à afficher init_lcd(); lcd_position(0,0); // on positionne le curseur au début (ligne,colonne). 16 colonnes sur l'écran. sprintf(text,"\O_O/ \O_O/ \O_O/");// formate la chaîne pour l'affichage et la stocke dans text lcd_puts(text);// affiche le texte lcd_position(1,0);// seconde ligne lcd_puts("Second line boss !");// On n'est pas obligé d'utiliser la fonction sprintf si le texte est simple while(1); // si on attend pas, on verra rien return 0 ; } }}} == Interruptions == === Par bouton === Le principe des interruptions est que l'on va assigner une pine à un type d’interruption et on va lui donner une priorité. Si l’événement attendu survient (input, timer, etc), une certaine fonction va être appelée et l'on va interrompre le programme principal. Un des intérêts est que les interruptions sont gérées à un niveau plus bas et sont donc beaucoup plus rapidement prises en compte que si l'on vérifiait l’appui sur un bouton. En contrepartie, c'est chiant à coder. {{{#!highlight C int main(void) { char text[32]; uint32_t i; //Configuration de l'horloge à 15 MHz LPC_PWRD_API->set_fro_frequency(30000); // Peripheral reset to the GPIO0 and pin interrupt modules. '0' asserts, '1' deasserts reset. LPC_SYSCON->PRESETCTRL0 &= (GPIO0_RST_N & GPIOINT_RST_N); LPC_SYSCON->PRESETCTRL0 |= ~(GPIO0_RST_N & GPIOINT_RST_N); //Mise en fonctionnement des périphériques utilisés LPC_SYSCON->SYSAHBCLKCTRL0 |= (IOCON | GPIO0 | SWM | CTIMER0 | GPIO_INT); //initialisation de l'affichuer lcd avec un affichage init_lcd(); sprintf(text,"Waiting..."); lcd_gohome(); lcd_puts(text); // Configuration des interruptions sur front descendant des boutons // Configure P0.18, P0.19 as pin interrupts 1, 0 // Make PORT0.18, PORT0.19 outputs driving '0'. LPC_GPIO_PORT->DIR0 |= (1<<19)|(1<<17)|(1<<21)|(1<<11); // Configure P0.18 - P0.19 as pin interrupts 1 - 0 by writing to the PINTSELs in SYSCON LPC_SYSCON->PINTSEL[0] = 13; // PINTSEL0 is P0.13 LPC_SYSCON->PINTSEL[1] = 12; // PINTSEL1 is P0.12 // Configure the Pin interrupt mode register (a.k.a ISEL) for edge-sensitive on PINTSEL1,0 LPC_PIN_INT->ISEL = 0x0; // Configure the IENR (pin interrupt enable rising) for rising edges on PINTSEL0,1 //LPC_PIN_INT->IENR = 0x0; // Configure the IENF (pin interrupt enable falling) for falling edges on PINTSEL0,1 LPC_PIN_INT->IENF = 0x3; // Clear any pending or left-over interrupt flags LPC_PIN_INT->IST = 0xFF; // Enable pin interrupts 0 - 1 in the NVIC (see core_cm0plus.h) NVIC_EnableIRQ(PININT0_IRQn); NVIC_EnableIRQ(PININT1_IRQn); // config priority. De base elles sont prioritaires mais on redéfinit leurs priorités NVIC->IP[6]= (0<<6)|(3<<14); while(1) { // affichage du timer sur l'écran LCD sprintf(text," %d ",i++); lcd_position(1,1); lcd_puts(text); } return 0 ; } //fonction interruption 0 GPIO sur front descendant void PININT0_IRQHandler(void){ LED1= !LED1; // Falling edge on PIN INT0, LED off LPC_PIN_INT->FALL = 1<<0; // Clear the interrupt flag return; } } }}} === Par Timer === Voilà pour les interruptions par bouton. Mais on peut également faire des interruptions par timer comme explicité dans le code suivant : {{{#!highlight C #include #include #include "LPC8xx.h" #include "fro.h" #include "rom_api.h" #include "syscon.h" #include "swm.h" #include "i2c.h" #include "ctimer.h" #include "core_cm0plus.h" #include "lib_UE441_lcd.h" //periode en ms des notes de la gamme LA440 #define P_DO 3822 #define P_RE 3405 #define P_MI 3033 #define P_FA 2862 #define P_SOL 2550 #define P_LA 2271 #define P_SI 2024 #define P_DOA 1911 int Gamme[8]={P_DO,P_RE,P_MI,P_FA,P_SOL,P_LA,P_SI,P_DOA}; //boutons et leds de la carte #define BP1 LPC_GPIO_PORT->B0[13] #define BP2 LPC_GPIO_PORT->B0[12] #define LED1 LPC_GPIO_PORT->B0[19] //utilisée ici en PWM #define LED2 LPC_GPIO_PORT->B0[17] #define LED3 LPC_GPIO_PORT->B0[21] #define LED4 LPC_GPIO_PORT->B0[11] volatile int temps=0; // temps actuel qui descend toutes les secondes volatile int total=1; // temps total de secondes que l'on doit compter volatile int prochain=1; // Prochain nombre de secondes que l'on comptera int main(void) { char text[32]; //text utilisé pour l'afficheur LCD //Configuration de l'horloge a 15 MHz LPC_PWRD_API->set_fro_frequency(30000); // Peripheral reset to the GPIO0 and pin interrupt modules. '0' asserts, '1' deasserts reset. LPC_SYSCON->PRESETCTRL0 &= (GPIO0_RST_N & GPIOINT_RST_N); LPC_SYSCON->PRESETCTRL0 |= ~(GPIO0_RST_N & GPIOINT_RST_N); //Mise en fonctionnement des peripheriques utilisés LPC_SYSCON->SYSAHBCLKCTRL0 |= (IOCON | GPIO0 | SWM | CTIMER0 | GPIO_INT); //initialisation de l'affichuer lcd init_lcd(); // Configuration de l'interruption pour le bouton comme précédemment LPC_GPIO_PORT->DIR0 |= (1<<19)|(1<<17)|(1<<21)|(1<<11); LPC_SYSCON->PINTSEL[1] = 12; // PINTSEL1 is P0.12 LPC_PIN_INT->ISEL = 0x0; LPC_PIN_INT->IENF = 0x3; LPC_PIN_INT->IST = 0xFF; NVIC_EnableIRQ(PININT1_IRQn); // config priority. De base elles sont prioritaires NVIC->IP[6]= (0<<6)|(3<<14); // configuration du SysTick Timer SysTick -> CTRL |= (1<<0); // active le timer SysTick -> LOAD = 0xb71aff; // compte à peu près une seconde SysTick -> CTRL |= (1<<1); // active les interruptions par le SysTick //Affichage du texte de base qui restera sur l'ecran LCD. sprintf(text,"Temps: ",temps,total); lcd_position(0,0); lcd_puts(text); sprintf(text,"Prochain: ",temps,total); lcd_position(1,0); lcd_puts(text); while(1) { // efface l'espace des infos sprintf(text," ",prochain); lcd_position(0,7); lcd_puts(text); sprintf(text," ",prochain); lcd_position(1,10); lcd_puts(text); // affichage les nouvelles infos sprintf(text,"%u sur %u ",temps,total); lcd_position(0,8); lcd_puts(text); sprintf(text,"%u",prochain); lcd_position(1,10); lcd_puts(text); } return 0 ; } //Interruption du timer void SysTick_Handler(void){ temps++; // incrémente le nombre de secondes if(temps>=total){// on est arrivé à la fin du temps LED1= !LED1; // la LED change temps=0; // le compte revient a 0 total=prochain; // on prend en compte le prochain temps } } //Interruption du bouton void PININT1_IRQHandler(void){ prochain=(prochain+1) % 20; //Incrémentation du prochain temps pris en compte LPC_PIN_INT->FALL = 1<<1; // Efface l'interruption return; } }}} == Liaison Série == La liaison série est la coeur de la transmission d'info machine vers machine (M2M). Le principe est très simple. On va envoyer un bit de start, les 8 bits d'information (avec le bit de poids faible en premier), puis optionnelement un bit de parité, et enfin un bit de stop. On transmet donc 8 bits par trame (ça tombe bien c'est la taille d'un caractère ASCII). Pour cela, on va utiliser le module UART du LPC804 pour parler (par exemple à notre ordi via minicom sur linux). Le code présenté ci-dessous permet de: * Envoyer une lettre après l’appui ou le relâchement d'un bouton * Renvoyer tout caractère envoyé via la liaison série * Afficher sur l'écran LCD les caractère reçus * Traiter différemment certains caractère spéciaux (retour, entrée) {{{#!highlight C #include "LPC8xx.h" #include #include "syscon.h" #include "swm.h" #include "utilities.h" #include "uart.h" #include "chip_setup.h" #include "lib_UE441_lcd.h" // Boutons: #define BP1 (1<<13) // LED: #define blue (1<<11) void envoyer(char lettre){ // on commence par attendre que la liaison soit libre while((LPC_USART0->STAT & TXRDY) == 0); // Le registre est maintenant disponible LPC_USART0->TXDAT = lettre; // on ecrit notre lettre dedans et le LPC804 fait le reste return; } // // Main routine // int passe = 1; // garde la valeure precedente du bouton int lettre = 'b'; char text[32]; int main(void) { // Enable clocks to relevant peripherals LPC_SYSCON->SYSAHBCLKCTRL0 |= (UART0 | SWM); LPC_SYSCON->SYSAHBCLKCTRL0 |= (IOCON | GPIO0); // Connect UART0 TXD, RXD signals to port pins ConfigSWM(U0_TXD, DBGTXPIN); ConfigSWM(U0_RXD, DBGRXPIN); // Select frg0clk as the source for fclk0 (to UART0) LPC_SYSCON->UART0CLKSEL = FRGCLKSEL_MAIN_CLK; // Give USART0 a reset LPC_SYSCON->PRESETCTRL0 &= (UART0_RST_N); LPC_SYSCON->PRESETCTRL0 |= ~(UART0_RST_N); // le registre BRG contient la valeure par laquelle diviser l'horloge pour obtenir la bonne fréquence en // fonction du baud rate voulue. La fréquence de base est 12Mhz donc on divise par 104 pour avoir 115384 LPC_USART0->OSR = 4; LPC_USART0->BRG = 20; // Configure the USART0 CFG register: // 8 data bits, no parity, one stop bit, no flow control, asynchronous mode // mode par défaut pour le minicom sur debian LPC_USART0->CFG = DATA_LENG_8|PARITY_NONE|STOP_BIT_1; // Configure the USART0 CTL register (nothing to be done here) // No continuous break, no address detect, no Tx disable, no CC, no CLRCC LPC_USART0->CTL = 0; // Clear any pending flags, just in case LPC_USART0->STAT = 0xFFFF; // Enable USART0 LPC_USART0->CFG |= UART_EN; // Enable the USART0 RX Ready Interrupt // LPC_USART0->INTENSET = RXRDY; // NVIC_EnableIRQ(UART0_IRQn); // initialisation du LCD et positionement au début. init_lcd(); lcd_position(0,0); while(1){ // gestion du bouton if ((LPC_GPIO_PORT -> PIN0 & BP1) != passe){ // le bouton change d'etat passe = LPC_GPIO_PORT -> PIN0 & BP1; if(passe==0){ // envoyer 'B' envoyer('B'); } else{ //envoyer 'b' envoyer('b'); } } // stocke la valeure précédente pour détecter les fronts passe = LPC_GPIO_PORT -> PIN0 & BP1; // Detection de la récéption d'une trame if ((LPC_USART0->STAT & RXRDY) == 1){ // on a reçu un octet lettre = LPC_USART0->RXDAT; // on le stocke dans lettre envoyer(lettre);// renvoit la lettre text[0]=(int)lettre;// place la lettre dans un mot lcd_puts(text);// affiche le mot à la suite sur l'afficheur // si la trame représente un appui sur la touche retour: // on efface tout l'ecran et on se place au debut if (lettre == '\b'){ lcd_position(0,0); lcd_puts(" "); lcd_position(1,0); lcd_puts(" "); lcd_position(0,0); } // si la trame represente un appui sur la touche entre // on se place en debut de seconde ligne if (lettre == 13){ lcd_position(1,0); } } }; } // end of main }}} == Sujet 0 == Voici un début de correction du sujet 0 proposé pour préparer le partiel. Gardez un œil très critique avec ce qui est proposé dans ce document. [[attachment:sujet0_Grizzly.pdf]]