Outils pour utilisateurs

Outils du site


tuto_avr_eclipse_utilisation_du_convertisseur_analogique-digital

[TUTO] [AVR] [Eclipse] Utilisation du convertisseur Analogique-Digital


Introduction

Dans ce tutoriel, je vous propose de mettre en oeuvre le convertisseur analogique-numérique (ADC1)) et d'envoyer le résultat de la lecture à un PC connecté au travers de la liaison USB de nos Arduinos préféré Arduino Uno et Arduino Nano). On commencera par implémenter la partie communication, a l'aide de la librairie de communication Série que l'on a créé lors du Tutoriel précédent 2). On s'appliquera ensuite a utiliser configurer et lire le résultat de la numérisation d'un signal analogique. Comme signal analogique, on peut utiliser n'importe quoi : un simple potentiomètre, un capteur de température genre LM335, une thermistance CTN, ou autre. Pour les besoins du présent tutoriel, nous n'utiliserons rien ; le ATmega328P disposant d'une sonde de température interne. Il n'y a donc pas de câblage. Le but est de faire des acquisitions-numérisations, pas d'illustrer le calcul en virgule fixe, ni de travailler sur un capteur tel qu'une thermistance CTN qui est non linéaire, et implique donc un traitement adapté.

Mes sources, si vous voulez les télécharger pour les étudier ou vous y référer, elles sont là : https://github.com/spelle/AVR_ADC.git.


Creation du Projet

Pour ma part, le projet, je l'ai nommé AVR_ADC ; toujours la même convention de codage. Et toujours pareil aussi, j'ai commencé par la creation de mon repository, clonage, etc… Se référer aux tutoriels précédents pour plus de précisions à ce sujet3).

[ACTION] Créer un nouveau projet C/C++ de type AVR Cross Target Application nommé AVR_ADC, pour un ATmega328P cadencé à 16MHz

La seule chose a faire, est éventuellement renommer la configuration Debug en un nom, plus représentatif comme ATmega328P_16MHz par exemple, et demander l'optimsation en taille.

[ACTION] Cliquer sur le menu Project > Build Configurations > > Manage…
[ACTION] Supprimer la configuration Release
[ACTION] Renommer la configuration Debug en ATmega328P_16MHz

[ACTION] Afficher les propriétés du projet : click-droit > Properties
[ACTION] Dans le panneau de droite, sélectionner C/C++ Build > Settings

[ACTION] Dans AVR Compiler > Optimizations, sélectionner Size Optimizations (-Os) pour Optimitzation Level

Répéter l'opération pour AVR C++ Compiler :

[ACTION] Dans AVR C++ Compiler > Optimizations, sélectionner Size Optimizations (-Os) pour Optimitzation Level

[ACTION] Appliquer les changements et valider

Il convient ensuite d'ajouter un fichier source ; conformément à notre convention de nommage, nous l'appellerons ainsi : AVR_ADC.c.


Communication Série

Le fichier d'en-tête AVR_ADC.h

Nous allons commencer par créer le canal qui nous permettra de Debugger notre programme. Notre Arduino ne disposant pas de moyen sophistiqué de debogage (JTAG par exemple), il nous faut le faire nous même. Notre moyen de debuggage sera l'envoie de traces de la part de notre Arduino.

Il existe bien un moyen qui est la Debug Wire, mais ni notre Arduino, ni nosIDE (Arduino ou Eclipse) ne sont capable d'en tirer partie.

Pour ce faire, nous allons ajouter un fichier d'en-tête a notre projet. Il va s'appeller AVR_ADC.h :

AVR_ADC.h
/*
 * AVR_ADC.h
 *
 *  Created on: 6 nov. 2013
 *      Author: A127590
 */
 
#ifndef AVR_ADC_H_
#define AVR_ADC_H_
 
 
 
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
 
 
 
#include <AVR_USART_lib.h>
 
 
 
#undef PDEBUG_INIT
#undef PDEBUG
 
 
 
#ifdef DEBUG
	#define PDEBUG_INIT( BR ) USART_Init( BR )
	// no need of a terminal \n. put by default
	#define PDEBUG( ... ) printf( __VA_ARGS__ )
#else /* DEBUG */
	#define PDEBUG_INIT( BR ) /* not debugging: nothing */
	#define PDEBUG( ... ) /* not debugging: nothing */
#endif /* DEBUG */
 
#endif /* AVR_ADC_H_ */

Pour faire simple, La serie de directives préprocesseur fait que si le symbol DEBUG est defini, le compilateur substituera USART_Init à PDEBUG_INIT et printf([…]) à PEDBUG([…]). Si le symbol DEBUG n'est pas défini, USART_Init et PDEBUG sont substitués par une chaîne vide, et seront donc ignorées.

Un tel artifice nous permet de poser des traces de debuggage. Le symbole DEBUG devra être défini pendant tant que nous seront en debuggage et enlevé lorsque le projet (Thermostat d'ambiance) sera fini.


Le fichier source AVR_ADC.c

Le fichier AVR_ADC.c ne présente pas difficultés. Nous avons repris celui du projet AVR_Blink_A_LED_Timer.

AVR_ADC.c
/*
 * AVR_ADC.cpp
 *
 *  Created on: Oct 9, 2013
 *      Author: lhotse
 */
 
 
 
#include "AVR_ADC.h"
 
 
 
ISR(TIMER1_COMPA_vect)
{
	// Toggle the LED
	PORTB ^= (1 << PORTB5); // Toggle the LED
 
	PDEBUG( "Hello World !\n" ) ;
}
 
 
 
int main( void )
{
	// Set Port B direction Register
	DDRB 	|= (1<<DDB5) ; // For LED on Pin PORTB5
 
	// Configure the Timer/Counter1 Control Register A
	TCCR1A	= 0 ;
	// Configure the Timer/Counter1 Control Register B
	TCCR1B	= (1 << WGM12) ; // Configure timer 1 for CTC mode
 
	TIMSK1	= (1 << OCIE1A); // Enable CTC interrupt
 
	OCR1A	= 62499 ; // Set CTC compare value to 1Hz at 1MHz AVR clock, with a prescaler of 64
 
	sei(); //  Enable global interrupts
 
	PDEBUG_INIT( 9600 ) ;
 
	TCCR1B |= (1 << CS12) ; // Start timer at Fcpu/64
 
	while( 1 )
	{
		sleep_mode();
	}
 
	return( 0 ) ;
}

Les seules nouveautés sont le PDEBUG_INIT avant le démarrage du Timer ; et le PDEBUG dans l'ISR. Ceci produisant l'envoi d'un message Hello World ! toutes les secondes.

Afin que les symboles PDEBUG et PDEBUG_INIT aient une substitution, il convient de définir le symbole DEBUG au moment de la compilation.

[ACTION] Afficher les Propriétés du projet : Clique-droit » Properties.
[ACTION] Selectionner C/C++ Build > Settings.
[ACTION] Dans AVR Compiler > Symbols, ajouter la définition du symbole DEBUG dans la liste Define Syms (-D) ; Le symbole est juste défini, sans valeur.
[ACTION] Dans AVR C++ Compiler > Symbols, ajouter la définition du symbole DEBUG dans la liste Define Syms (-D) ; Le symbole est juste défini, sans valeur.
[ACTION] Appliquer/Valider les changements.

Il convient ensuite de compiler le projet.


Compilation et Premiers Tests

Si une compilation est lancée a ce moment là, le compilateur se plaint de ne pas trouver le fichier d'en-tête AVR_USART_lib.h. Il convient donc de l'ajouter.

[ACTION] Afficher les Propriétés du projet : Clique-droit » Properties.
[ACTION] Selectionner C/C++ Build > Settings.
[ACTION] Dans AVR Compiler > Directories, ajouter le chemin contenant le fichier d'en-tete AVR_USART_lib.h (“${workspace_loc:/AVR_USART_lib}”).
[ACTION] Dans AVR C++ Compiler > Directories, ajouter le chemin contenant le fichier d'en-tete AVR_USART_lib.h (“${workspace_loc:/AVR_USART_lib}”).
[ACTION] Appliquer/Valider les changements.

La compilation échoue ensuite à l’édition des liens. Le compilateur se plaint de ne pas trouver de référence pour les fonctions USART_Init, USART_Transmit, et USART_putchar_printf. Il convient de mentionner au compilateur de se lier à la librairie AVR_USAR_lib.

[ACTION] Afficher les Propriétés du projet : Clique-droit » Properties.
[ACTION] Selectionner C/C++ Build > Settings.
[ACTION] Dans AVR C++ Linker > Libraries, ajouter la librairie AVR_USART_lib dans la liste Librarie (-l)
[ACTION] Dans AVR C++ Linker > Libraries, ajouter le chemin vers la librairie AVR_USART_lib dans la liste Libraries Paths (-L) (“${workspace_loc:/AVR_USARt_lib/${ConfigName}}”).
[ACTION] Appliquer/Valider les changements.

La compilation réussit. Le téléversement est une formalité.

Pour tester, un terminal série (e.g. : putty) est tout indiqué. On doit recevoir le message Hello World !! toutes les secondes.

—-

Conversion Analogique-Numérique

Nous nous proposons donc de mettre en oeuvre le Convertisseur Analogique-Numerique (ADC4) de nos microcontrolleurs préférés.

Pour simplifier les choses, nous allons utiliser le Single-Conversion Mode. A l'aide de notre timer, nous allons donc effectuer une lecture toutes les secondes, et afficher le resultat au travers de notre liaison serie.

Le fichier AVR_ADC.c en est modifié comme suit :

AVR_ADC.c
/*
 * AVR_ADC.cpp
 *
 *  Created on: Oct 9, 2013
 *      Author: lhotse
 */
 
 
 
#include "AVR_ADC.h"
 
 
 
ISR(TIMER1_COMPA_vect)
{
	// Toggle the LED
	PORTB ^= (1 << PORTB5); // Toggle the LED
 
	// Read the ADC value
	uint16_t uiADCvalue = ADCL ;
	uiADCvalue |= (ADCH<<8) ;
 
	PDEBUG( "Read ADC value : %i\n", uiADCvalue ) ;
 
	// Restart a conversion
	ADCSRA |= (1 << ADSC) ;
}
 
 
 
int main( void )
{
	// Set Port B direction Register
	DDRB	|= (1<<DDB5) ; // For LED on Pin PORTB5
 
	// Configure the Timer/Counter1 Control Register A
	TCCR1A	= 0 ;
	// Configure the Timer/Counter1 Control Register B
	TCCR1B	= (1 << WGM12) ; // Configure timer 1 for CTC mode
 
	TIMSK1	= (1 << OCIE1A); // Enable CTC interrupt
 
	OCR1A	= 62499 ; // Set CTC compare value to 1Hz at 1MHz AVR clock, with a prescaler of 64
 
	sei(); //  Enable global interrupts
 
	PDEBUG_INIT( 9600 ) ;
 
	TCCR1B |= (1 << CS12) ; // Start timer at Fcpu/64
 
	// Select the 1.1V voltage reference (needed for acquiring the Internal Temperature Sensor).
	ADMUX |= (1<<REFS0) | (1<<REFS0) ;
	// Select ADC8
	ADMUX |= (1<<MUX3) ;
 
	// Enable the ADC, set prescaler to F_CPU/128
	ADCSRA |= (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0) ;
 
	// Start a Single Conversion
	PRR &= ~(1 << PRADC) ;
	ADCSRA |= (1 << ADSC) ;
 
	while( 1 )
	{
		sleep_mode();
	}
 
	return( 0 ) ;
}

L'initialisation de l'ADC est effectué grace aux lignes suivantes :

  • Comme mentionné dans la datasheet, le capteur de temperature interne doit etre acquis en utilisant la reference interne de 1.1V.
// Select the 1.1V voltage reference (needed for acquiring the Internal Temperature Sensor).
ADMUX |= (1<<REFS0) | (1<<REFS0) ;
  • L'ADC acquiert le signal au travers d'un multiplexeur. Il y a 8 cannaux externe, et 1 interne mais il n'est possible d'acquerir qu'un seul signal a la fois au travers du multiplexeur piloté par les bits MUXn du registre ADMUX
// Select ADC8
ADMUX |= (1<<MUX3) ;
  • L'ADC doit ensuite etre activé. Par la meme occasion, le prescaler est selectionné. Le prescaler a pour but de fournir a l'ADC une clock comprise entre 50kHz et 200kHz. Notre clock etant de 16MHz, la seule valeur possible est Fcpu/128 = 125kHz
// Enable the ADC, set prescaler to F_CPU/128
ADCSRA |= (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0) ;
  • Le demarrage de la Conversion se par simple ecriture du bit ADCSC 5). Il est necessaire de desactiver l'economie d'energie relative a l'ADC (mettre a 0 le bit PRADC 6) du registre PRR 7)).
// Start a Single Conversion
PRR &= ~(1 << PRADC) ;
ADCSRA |= (1 << ADSC) ;

L'initialisation de l'ADC est terminée ; une premiere conversion a été initiée ; le timer est demarré. La prochaine interruption arrivera dans une seconde ; ce qui est largement suffisant pour que la conversion se finisse. D'après la datasheet la première conversion prends 25 temps de cycles; les suivantes en prennent 13 ; à 125kHz, je vous laisse faire le calcul.

L'ISR du timer en est donc modifié de la maniere suivante :

  • La conversion precedente est largement terminée. Il est possible de lire les registres de donnée de l'ADC.
// Read the ADC value
uint16_t uiADCvalue = ADCL ;
uiADCvalue |= (ADCH<<8) ;
N.B. : Il faut lire les deux registres independamment ; une logique empeche la mise a jour de ces deux registres tant que le registre ADCH n'est pas lu apres un lecture du registre ADCL.

* L'affichage de la valeur lue est trivial a l'aide de la fonction printf().

PDEBUG( "Read ADC value : %i\n", uiADCvalue ) ;
  • Une autre conversion est ensuite lancée.
// Restart a conversion
ADCSRA |= (1 << ADSC) ;

Sur la base du meme code, simplement en changeant la reference de tension et la selection du canal, il est facile d'aller acquerir les autres cannaux de l'ADC.

// Select the AVcc voltage reference
ADMUX |= (1<<REFS0) ;
// Select ADC0
ADMUX &= ~(1<<MUX3) & ~(1<<MUX2) & ~(1<<MUX1) & ~(1<<MUX0) ;

Bien entendu, l'utilisation de l'ADC complexifie notre code, aussi il parait opportun de créer une librairie pour ce faire. Cela peut faire l'objet d'un petit exercice…

Concernant le calcul effectif de la temperature, il est abordé dans un tutoriel ditinct relatif aux sondes de temperature type thermistance CTN.


Remarques, Propositions d'améliorations, Questions

Vous pouvez poster vos remarques, propositions d’amélioration, et questions sur le forum, dans la discussion prévue a cet effet : http://fablab-robert-houdin.org/fablab/phpBB-3.0.11-fr/phpBB3/viewtopic.php?f=3&t=17


tuto_avr_eclipse_utilisation_du_convertisseur_analogique-digital.txt · Dernière modification: 2013/11/13 15:02 par spelle