TD1 Informatique Industrielle
TD1 Informatique Industrielle
TD1 Informatique Industrielle
Geii1 – II2
Algorithme et langage C
Ces exercices ont pour objectif de vous familiariser avec la syntaxe du langage C et les techniques de
transposition d'un algorithme.
Pour mener à bien ces activités, il vous faut consulter :
le cours (partie introduction au C).
tempo 1
Pour i variant de 1 à n faire
tempotempo*i
Fin Tant que
Factorielletempo
Utilisez une boucle while puis une boucle for Pour décrire ce traitement.
Le résultat final doit être placé dans une variable nommée factorielle.
Exercice 2 [if]
Résoudre l'équation ax2 + bx +c = 0.
Vous utiliserez l’instruction if.
Rappel : il faut calculer le déterminant ∆=(b2-4a.c)
Si ∆ est positif ou nul, alors 2 racines réelles (-b± √∆)/2.a
Si ∆ est négatif, alors pas de solution réelle (ici, on ne calculera pas les racines complexes).
Remarque: dans ce traitement, on suppose que les variables a,b,c existent déjà et contiennent un nombre. Dans votre
traitement, vous déclarerez les variables a,b,c et vous leur affecterez une valeur arbitraire.
Exercice 3 [for et if ]
Construire un programme qui permet de saisir une suite de caractères, puis de compter et d'afficher le nombre de lettres
‘e’ et d'espaces.
Remarque: le nombre maximum de caractères dans la chaîne est de 20.
Le nombre de lettres 'e' sera placé dans la variable compteurLettreE.
Le nombre d'espaces sera placé dans la variable compteurEsp.
Exercice 7 [fonctions]
Dans le cadre d'un système d'acquisition de données, 20 échantillons de tension ont été numérisés à l'aide d'un CAN 8
bits (1) ; les échantillons sont stockés en mémoire SRAM dans le tableau nommé tabEch.
Voici un morceau de code :
printf("valeur moyenne des échantillons %3.2f",valMoy());
printf("valeur max des échantillons %d",valMax());
printf("valeur min des échantillons %d",valMin());
Donnez l'algorithme et le code C qui permet d'obtenir et d'afficher la valeur moyenne (fonction valMoy()), la valeur
max (fonction valMax()) et la valeur min (valMin()) calculée à partir de ces 20 échantillons.
PA0 SRAM
CAN
8 bits
tabEch[0]
tabEch[1]
tabEch[2]
tabEch[19]
(1) un CAN 8 bits est un système qui transforme une valeur analogique en une grandeur
numérique équivalente. Dans notre cas, la grandeur numérique est codée sur 8 bits donc
entre 0 et 255
AVR
PORTA PORTA en sortie avec toutes les lignes à l'état logique '1'
PORTB PORTB en entrée
PORTC3-0 PORTC (poids faibles) en sortie (avec toutes les lignes initialement à l'état logique '0')
PORTC7-4 PORTC (poids forts) en entrée
AVR
PA.0 PA.1
VPA0
Q1 : indiquez dans quel sens (ENTREE/SORTIE) doit être configurée la broche PA0. Donnez la valeur de DDRA.0
Même travail avec PA1.
Q2 : quand le bouton poussoir est enclenché, quelle est la tension que l'on peut mesurer sur l'entrée PA0 VA0=
Quel est l'état logique équivalent que l'on peut lire sur PA0?
Q3 : quel état logique faut-il alors envoyer sur PA1?
Q4 : quand le bouton poussoir est relâché, quelle est la tension mesurée sur PA0 :
o 0V
o 5V
o tension ‘flottante’ impossible à déterminer (on dit haute impédance)
On est alors obligé de câbler une résistance R entre le Vcc est l'entrée PA0.
Vcc=5V
AVR
R
PA.0 PA.1
VPA0
Q5 : tracer le chemin du courant qui passe dans la résistance quand le bouton poussoir est enfoncé.
Remarque : les broches du microcontrôleur, quand elles sont configurées en entrée, présentent une impédance très
élevée (idéalement infinie).
On veut limiter le courant dans R à 100µA.
Donnez la valeur de R.
Q6 : tracez le chemin du courant qui circule dans la résistance quand le bouton poussoir est relâché.
Quelle est la tension aux bornes de R VR=
Quelle est la tension VPA0=
Quel est le niveau logique équivalent que l'on peut lire sur PA0?
Q7 : la résistance R est appelée résistance de pull-up (notée RPU). Justifiez ce terme et proposez une traduction en
français.
Mais celle-ci est configurable logiciellement au sens ou l'on peut choisir de d'activer ou pas la résistance.
AVR
5V
Système d’activation/désactivation
R de la résistance de pull-up.
Le contrôle se fait par le registre
DDRA
VPA0
Complétez alors :
DDRA
7 6 5 4 3 2 1 0
PORTA
7 6 5 4 3 2 1 0
Remarque : les résistances de pull-up n'ont aucun intérêt quand une broche est configurée
en sortie
Q11 : SYNTHESE complétez le code C la partie initialisations pour obtenir le fonctionnement attendu
void main(void)
{
// initialisations
………………………
// superboucle du cycle µc
while (1)
{
PORTA.1=!PINA.0;
}
}
Dans certains cas, la présence d'une résistance peut avoir des effets (indésirables?) qu'il faut prendre en compte.
Reprenons le montage et supposons qu'une capacité parasite de 40pF est présente.
AVR
5V
Rpu
R 30k
Cp
40p
Etat du BP
Enfoncé Relaché
VPA0 réelle
et l'on veut placer le bit PA2 à '1' (pour allumer la LED2) et le bit PA1 à ‘0’ (pour éteindre la LED1) sans modifier l’état
des autres lignes du PORTA.
Donnez le résultat obtenu lorsque l'on effectue l'opération suivante (OU logique avec un masque):
PA7 PA6 PA5 PA4 PA3 PA2 PA1 PA0
0 0 1 1 0 0 1 0
OU 0 0 0 0 0 1 0 0
=
Donnez le résultat obtenu lorsque l'on effectue l'opération suivante (ET logique avec un masque):
En Résumé
Pour isoler une ou plusieurs informations binaires présentes sur un port d’E/S, il est nécessaire d’effectuer une
opération de masquage entre ce port et une constante appelée masque. La mémorisation du résultat de l’opération de
masquage est réalisée en l’affectant à une variable.
<nom_variable> ← <Lecture_Contenu du Port> ET <Masque>
soit, par exemple, en C AVR :
<nom_variable> = PINx & <Masque>
En utilisant les fonctions de la librairie io.h, donnez le code qui permet de réaliser la même opération que celle
effectuée avec les masques.
Exercice 5
Un microcontrôleur est très souvent utilisé pour générer des intervalles de temps précis.
Pour créer des temporisations, vous pouvez :
utiliser les compteurs programmables (timers) qui sont intégrés dans le µc,
utiliser la notion de boucles dans un programme en prenant en compte la durée de chaque instruction
Un programme simple de temporisation se déroule comme suit :
DEBUT 1 chargement d'un registre (qui joue le rôle de compteur) à une valeur donnée (ici la
valeur est notée de façon générale Np)
CompteurN
2 décrémentation du registre
Compteurcompteur-1
FIN
La durée totale dépend du temps d'exécution de chaque instruction et de la valeur mise dans le registre.
La durée maximale dépend de la taille du registre (avec un compteur 8 bits, on a N=255 max). Toutefois, il est possible
d'imbriquer plusieurs boucles les unes dans les autres pour obtenir des temporisations plus longues.
En C, il est impossible d'évaluer simplement la durée des instructions. Par conséquent, les fonctions de temporisation de
base sont écrites en ASSEMBLEUR.
NOMBRE DE CYCLES
tempo:
ldi r16,N
boucle: dec r16
brne boucle
Recherchez dans la documentation du constructeur sur le jeu d’instructions assembleur la colonne qui indique le
nombre de cycles de chaque instruction.
4.1 Identifiez l'analogie entre le code assembleur et l'algorigramme.
4.2 Comptez le nombre de cycle de chaque instruction colonne (NOMBRE DE CYCLES).
4.3 Quel est le nombre de cycles nécessaires pour parcourir 1 fois la boucle?
4.4 Indiquez le nombre de cycles quand on exécute la séquence complète (TOT_CYCLE)?
4.5 Quelle est la temporisation la plus longue que l'on puisse obtenir si Fosc=16MHz (TMAX)?
4.6 Calculer la valeur de Np (format OCTET) pour obtenir une temporisation de 35µs.
4.7 Comment faire pour obtenir une temporisation plus longue ?
En langage C, il existe deux routines pour gérer les temporisations :
delay_us(valeur) pour une temporisation exprimée en µs (valeur est un entier entre 0 et 65 535)
delay_ms(valeur) pour une temporisation exprimée en ms
Ces deux routines sont définies dans la librairie #include <delay.h> .
IUT GEII ANGOULEME – geii1 [2010-2011] Informatique industrielle page 7
Exemple :
Pour obtenir une temporisation de 100µs, on écrira
delay_us(100);
TL=8µs
0V
Ts=10µs
Exercice 7
Ecrivez un programme C qui permette d'obtenir un chenillard sur le PORTB. Les bits seront décalés avec une période
de 100ms. Pour cela, vous disposez d'une fonction déjà écrite nommée delay_ms(valeur) qui est enregistrée dans
la bibliothèque delay.h fournie par le constructeur (<delay.h>).
Les LEDs du chenillard sont câblées en cathode commune à la masse. Dessinez le schéma du système.
Question 1
Citez les périphériques internes associés au microprocesseur. Donner leur rôle.
Question 2
Donnez les caractéristiques électriques de l'Atmega32 (tension max/min, fréquence max/min) [page 4]
Voici la caractéristique de consommation du composant (extraite de la doc. ATMEL) :
Question 3
Quel est le courant maximal "NORMAL" que peut débiter/absorber une broche du composant?
APPLICATION:
Le microcontrôleur doit fournir sur la broche PA0 un courant de 40mA pour alimenter une charge.
Ib=40mA
Vbe=1.7V
Calculer la valeur de Rb en tenant compte des caractéristiques de sortie en courant présentée ci dessous.
Question 4
Quelle est la quantité de mémoire embarquée ? Détaillez le rôle de chaque mémoire.
Question 5
A quoi sert une interruption ?
De combien de sources d’interruptions dispose-t-on dans ce microcontrôleur ?
Ces différentes sources ont-elles un ordre de priorité ?
En général, les systèmes à concevoir (donc les programmes) sont complexes et exigent une méthode de
spécification adéquate et claire.
La machine à états est un des outils efficace permettant de décrire le fonctionnement des systèmes.
Illustration
Pour l'exemple, nous allons gérer les rebonds d'un bouton poussoir (BP).
La variable V doit prendre la valeur 1 quand le BP est activé, 0 sinon.
Il faut savoir qu'un phénomène de rebonds apparaît lors du relâchement du BP (les lames du BP vibrent
mécaniquement). Pour traiter ces rebonds nuisibles, on peut mettre en œuvre le principe suivant :
au relâchement, c'est-à-dire quand un front montant est détecté, on attend 20ms (la valeur de 20ms
est empirique) puis l'on vient relire l'état du BP:
s'il est encore à l'état 1, on en conclue que le BP a été effectivement relâché
s'il est à 0, le front montant était un simple parasite, on attend le front montant suivant.
rebonds (~10ms)
Etat du BP
APPUI RELACHEMENT
20ms
V
INIT
BP=1/V=0
0
BP=1.T=20/V=0
BP=0/V=1
BP=0.T=20/V=1
2 1
BP=1/T=0
Méthodologie
Voici les étapes que je vous recommande de suivre pour construire précisément un diagramme d'états.
1. Identifiez toutes les entrées. Pour l'exemple, il s'agit de BP.
Remarque : ici, la variable T est une variable interne; elle s'incrémente automatiquement toutes les 1ms (on verra plus
tard comment) et elle est manipulée à la fois comme entrée ou comme sortie.
2. Énumérez toutes les sorties. V dans notre cas.
3. Énumérez tous les états possibles. Nous avons trois états (0, 1, 2).
4. Créez une variable assez grosse pour contenir tous les états possibles. Encoder les états sur le nombre nécessaire de
bits. Pour notre exemple on a E0 et E1 avec encodage {00, 01, 10, 11}.
5. Assignez un état initial au système. Le graphe montre que cet état est 0.
Ce qui est mentionné précédemment (points 1, 2, 3,4 et 5) est vrai tant pour les systèmes matériels que logiciels.
Cependant, pour l'aspect logiciel, nous devons ajouter quelques remarques supplémentaires pour tenir compte de
certaines réalités:
6. La variable contenant l'état du système peut être un peu plus grosse que nécessaire pour une simple question de
commodité. Dans les cas que nous traiterons, un type uint8 est généralement suffisant (255 états !!).
7. Il faut souvent créer des variables (au moins temporaires) pour représenter les entrées et les sorties.
8. Codez les instructions qui permettent le changement d'un état à un autre en fonction de l'état présent et des entrées.
Généralement, cette partie est écrite avec une instruction "switchcase".
9. Programmez le comportement de chaque état de façon claire et bien identifiée.
IUT GEII ANGOULEME – geii1 [2010-2011] Informatique industrielle page 10
Voici le code en C de cette machine :
#include <io.h>
#include <iut/types.h> // pour les types de variables
#include <delay.h>
// construire les états possibles
typedef enum {ETAT0,ETAT1,ETAT2} tetats;
// équivalences
#define V PORTC.0
#define BOUT_POUS PIND.4
void initAVR(void) {
DDRD.4=0;PORTD.4=1; // bouton poussoir en entrée avec pull-up
DDRC.0=1;PORTC.0=0; // led eteinte
}
/* ______ TRAITEMENT PRINCIPAL -----------------*/
void main(void) {
tetats etat=ETAT0;
uint8 T=0;
bit BP;
// initialiser les périphériques
initAVR();
// moteur ... de la machine !!!
while (1) {
// lire les entrées
BP=BOUT_POUS;
// faire évoluer la machine en fonction des états et des entrées
switch (etat) {
case ETAT0 :
if (BP==0) {etat=ETAT1; V=1;} else V=0;
break;
case ETAT1 :
if (BP==1) { T=0;etat=ETAT2;}
break;
case ETAT2 :
if (BP==0 && T==20) { T=0;etat=ETAT1;}
if (BP==1 && T==20) { etat=ETAT0;}
break;
}
// temporiser entre deux tops d'horloge
delay_ms(1);
T++; // incrémenter la variable interne
}
}
Application 1
Le microcontrôleur doit contrôler une DEL bicolore.
Quand le système démarre, la DEL doit s'allumer en rouge. Si le bouton-
poussoir BP0 est activé, la DEL affiche la couleur ambre.
Quand le bouton-poussoir est relâché, la DEL devient verte. Si le bouton
est encore activé, la DEL prend la couleur ambre. Quand il est relâché, la
DEL s'éteint. Si le bouton est encore activé, la DEL affiche la couleur
ambre. Quand il est relâché, la DEL tourne au rouge ce qui fait que le
système est de retour à son état initial et tout peut recommencer.
Application 2
On utilise toujours la même LED bicolore, mais cette fois ci, le défi est de concevoir un jeu de réflexe.
Quand le microcontrôleur démarre, il attend 10 secondes pendant lesquelles la led clignote en rouge à la cadence d'1/10
de seconde. Quand la lumière est éteinte, le joueur doit activer le bouton poussoir aussitôt que possible. Si le joueur
active le bouton à l'intérieur d'une seconde, la DEL devient verte. Si le joueur active sur le bouton passé une seconde, la
lumière prend la couleur rouge.
Il faut appuyer à nouveau sur le bouton poussoir pour revenir au départ.
OCF0
dedans !!!!!).
OCF0
OC0 Ttimer0
Question 1
Citez les registres de configuration du timer 0.
Complétez le code :
// ___ Librairies utiles
#include <io.h>
#include <iut/TPboard.h>
#include <delay.h>
#define DROITE 0
#define GAUCHE 1
u08 sens=GAUCHE;
Consulter la page 26,27 de la documentation AVR pour répondre aux questions 1,2.
QUESTION 1
Quelle est la fréquence de fonctionnement MAXIMALE quand le CAN travaille en résolution maximale de 10 bits?
QUESTION 2
Quel est le temps de conversion en mode normal ?
On place la valeur xxxx x110 dans le registre ADCSRA.
Quelle est la valeur de la fréquence d'horloge du CAN? Que pouvez-vous dire?
Quel est le temps de conversion?
QUESTION 3
Quelle est la valeur numérique que donne le CAN si VREF=2.56 et Ve=0.8V en mode 8 bits, 10 bits ?
Avec VREF=5V, quelle est la plus petite tension mesurable en mode 8 bits?
Si le CAN donne une valeur de 79, quelle est la tension d'entrée (VREF=5V).
Application 1
On veut écrire un programme simple de lecture de la tension de PA2 convertie au format 10 bits avec une tension de
référence à VCC.
La tension est lue une seule fois.
(1)
Pour cela, on utilise une procédure scrutation du bit 4 ADIF du registre ADCSRA
Déterminez l’algorithme des éléments de programme suivant:
1. Sous-programme init : définition du registre ADMUX et programmation des directions (PORTA).
2. Sous-programme acquisition : attente ADIF et lecture de la valeur convertie.
Le programme principal main est construit comme suit :
MAIN
DEBUT
valeur : entier
init
valeuracquisition
FIN
(1)
le bit ADIF du registre ADCSRA est un bit d'information (drapeau). Initialement (en début de conversion), il doit être
forcé à 0 (en écrivant un 1 dedans); il passe automatiquement à 1 en fin de conversion.
init
FIN
Application 3
On veut réaliser maintenant des périodes d’échantillonnage constantes et calibrées (Réf. de tension: AVCC).
Pour cela, utiliser le TIMER0 de l'AVR.
On veut faire 100 mesures d’un signal (appliqué sur PA0) dont la fréquence maximale est de 10kHz.
On choisit donc une fréquence d’échantillonnage de 20kHz.
Justifiez cette valeur d'échantillonnage !!!
Les 100 mesures (au format 8 bits) seront placées dans le tableau tech[100];
Complétez le code du programme principal et des programmes d’interruptions pour résoudre le problème.
#include <avr/io.h>
#include <avr/interrupt.h>
/**
* Initialisations des périphériques du µc.
*/
void init(void)
{
// timer0
< à compléter … >
// can
< à compléter … >
// it autorisées
sei();
}
/**
* Interruption TIMER0 de comparaison (50µs). Fech=20kHz
*/
ISR(TIMER0_COMP_vect)
{
< à compléter … >
}
/**
* acquisition d'une grandeur analogique.
*/
u08 acquisition(void) {