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