AVR ADC avec un Arduino UNO

Cet article explique comment utiliser le convertisseur analogique à numérique (ADC) présent sur le Atmega328p du Arduino UNO.

Dans cet article, nous utiliserons une boucle pour la lecture d’un canal. Je ferai un autre article qui expliquera comment faire cette lecture en interruption, ce qui est recommandé afin de libérer le programme principal.

Étape 1 : Initialisation du ADC

Dans l’initialisation, nous devons configurer le registre ADCSRA.

Screenshot_2

Le bit ADEN active le ADC alors que les bits ADPS0-ADPS3 sélectionnent la division de l’horloge du système qui établira la vitesse de l’horloge du ADC. Ce qui est important, c’est que l’horloge de l’ADC ne dépasse pas 200KHz lorsque les 10 bits de résolution sont nécessaires. Puisque nous avons une horloge de 16MHz sur le Arduino UNO, nous devons diviser par 80 ou plus. Selon la table 24-5 du datasheet, nous devrons donc utiliser le facteur de division 128.

Screenshot_3

Nous devons également configurer le registre ADMUX qui sélectionne la tension de référence utilisée par l’ADC.

Screenshot_3

Puisque la broche AREF du Arduino UNO n’est pas reliée, nous allons utiliser AVcc comme référence. La table 24-3 montre que le bit REFS0 doit être activé.

Screenshot_2

Voici à quoi le code de la fonction adcInit devrait ressembler :

void adcInit()
{
 ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) |(1<<ADPS0) ;
 ADMUX =  (1<<REFS0);
}

Étape 2 : Sélection du canal

Le Atmega328P utilisé par le Arduino UNO possède 6 canaux sur son ADC. Lorsqu’il n’y a qu’un canal utilisé, vous devez sélectionner le canal une seule fois. Sinon, vous devez sélectionner le bon canal avant chaque conversion. La sélection du canal s’effectue via le registre ADMUX avec les bits MUX3 à MUX0.

Screenshot_4

Voici à quoi la fonction adcSetCh devrait ressembler :

void adcSetCh(uint8_t ch)
{
 ADMUX &= 0xF0; 
 ADMUX |= (ch & 0x0F);
}

Étape 3 : Lecture de l’ADC dans une boucle

Il faut maintenant démarrer l’ADC. Cette opération s’effectue à l’aide du bit ADSC du registre ADCSRA. Lorsque ce bit est mis à 1, une conversion démarre. Le bit retourne à zéro lorsque la conversion est terminée.

Voici à quoi le code de la fonction adcRead devrait ressembler :

uint16_t adcRead(uint8_t ch)
{
 ADCSRA |= (1<<ADSC);
 while (ADCSRA & (1<<ADSC)); 
 return ADCW;
}

Exemple d’utilisation de l’ADC

Dans cet exemple, un potentiomètre est relié au canal 0 de l’ADC selon l’image suivante.

20171012_194317[1]

Le code fait la lecture de la broche aux 100ms puis il affiche le résultat sur le port série.

#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <stdlib.h>
#include "usart.h"
#include "adc.h"

uint16_t adcVal = 0;

int main(void)
{
  char strVal[6] = {0};
  usartInit(19200);
  adcInit();
  while (1) 
  {
    adcVal = adcRead(0);
    itoa(adcVal,strVal,10);
    usartSendStr(strVal);
    usartSendStr("\n\r");
    _delay_ms(100);
  }
}

Et voici le résultat observé, en variant de 0V à 5V le potentiomètre.

Screenshot_5

2 commentaires

  1. Merci Marc, pour cet article intéressant, encore plus pour un français trop paresseux pour lire l’anglais. Vous avez bien dégrossi le sujet. Je reste malgré tout un peu sur ma faim, et le meilleur passage est pour moi “Je ferai un autre article qui …” . Comment le convertisseur fonctionne-t-il avec la broche AREF ? A quelle valeur de condensateur est-il fait référence ? Quid de l’usage de l’interruption ?
    Peu importe pour l’instant, je vais commencer une deuxième lecture.
    Et puisque nous avons cet autre centre d’intérêt en commun, je vis aux pied des merveilleuses Pyrénées.

Laisser un commentaire

Votre adresse courriel ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire le pourriel. En savoir plus sur comment les données de vos commentaires sont utilisées.