🛠 Registres AVR et interruption timer : échantillonner le multiplexeur

Arduino Esplora — Board Fiche · avance · Schéma : IMG-esplora-avance-1-esplora-registres-interruption-timer.svg — Schéma fonctionnel du multiplexeur 4 vers 1 de l'Esplora : broches A0-A3 en adresse, A4 en ADC commun, canaux boutons/slider/lumière/température/son, avec le timer TCNT2 en horloge.

Objectives

Understand — then bypass — the Esplora library. The 10 multiplexed channels (buttons, slider, light, temperature, microphone, TinkerKit A/B, joystick) share the ADC input A4, selected by address pins A0–A3 (MAX_CHANNELS=13 in Esplora.cpp). This tutorial manipulates AVR registers directly (DDRB/PORTB, ADMUX, ADCSRA) and triggers sampling via Timer2 compare match interrupts, for precise periodic scanning without delay.

Hardware

Full Code

/* Balayage periodique du multiplexeur de l'Esplora SANS la bibliotheque,
   pilote par interruption de comparaison du Timer2 (~1 kHz).
   Adresses physiques d'apres Esplora.cpp : A0..A3 = adresse, A4 = commun.
   Sur l'ATmega32u4, A0..A4 correspondent a PORTB bit0..bit4. */
#include <avr/io.h>
#include <avr/interrupt.h>

#define MUX_PORT PORTB
#define MUX_DDR  DDRB
#define ADC_COM  4            // A4 -> ADMUX MUX = 4

volatile uint16_t mesures[6]; // boutons non mesures ici : canaux analogiques
volatile uint8_t canal = 0;

ISR(TIMER2_COMPA_vect) {
  // 1) selection du canal sur A0..A3
  MUX_PORT = (MUX_PORT & 0xF0) | (canal & 0x0F);
  // 2) lancement d'une conversion sur A4 (ADMUX deja configure)
  ADCSRA |= (1 << ADSC);
}

ISR(ADC_vect) {
  mesures[canal] = ADCL | (ADCH << 8);   // lecture 10 bits
  canal = (canal + 1) % 6;               // cycle : 4=slider? voir note
}

void setup {
  Serial.begin(9600);
  MUX_DDR |= 0x0F;                       // A0..A3 en sortie
  ADMUX  = (1 << REFS0) | ADC_COM;       // ref 5V, entree A4
  ADCSRA = (1 << ADEN) | (1 << ADIE) | (1 << ADPS2) | (1 << ADPS1); // /64
  // Timer2 en CTC, comparaison ~1 kHz (16 MHz / 1024 / 16)
  TCCR2A = (1 << WGM21);
  TCCR2B = (1 << CS22) | (1 << CS21) | (1 << CS20);
  OCR2A  = 124;
  TIMSK2 = (1 << OCIE2A);
  sei;
}

void loop {
  static uint32_t t = 0;
  if (millis - t > 250) {
    t = millis;
    // Canaux physiques : dependront du cablage exact du mux (voir Esplora.cpp)
    Serial.print("c4="); Serial.print(mesures[4]);
    Serial.print(" c5="); Serial.print(mesures[5]);
    Serial.print(" c6="); Serial.print(mesures[6]);
    Serial.print(" c7="); Serial.println(mesures[7]);
  }
}

Expected Verification

The serial monitor displays four columns that vary when you manipulate the slider, light, temperature, and microphone — without ever calling the Esplora library (verify with the library manager that it is not compiled). The regularity of the scan is guaranteed by Timer2: disconnect the monitor, and sampling continues at ~1 kHz.

Common Errors

  1. Writing to PORTB without a mask: Bits 4–5 of PORTB also carry A4/A5 (accelerometer); always use MUX_PORT = (MUX_PORT & 0xF0) | channel.
  2. Forgetting the settling time: After changing channels, ~50 µs are required before conversion; a Timer2 that is too fast (tens of kHz) mixes up channels.
  3. Reading ADCL/ADCH in the wrong order: Reading ADCH before ADCL corrupts the last conversion; reading ADCL first locks the registers.
  4. Conflict with the Servo library or tone: Timer2 is also used by tone on the AVR; this sketch does not use tone, but if you add it, choose Timer1 or Timer0.
  5. Confusing library logical channels with ADC channels: The number sent to A0–A3 is not the 3-bit MUX value of ADMUX; the ADC channel always remains A4.

Other tutorials for this board

Code examples for this board

← Back to the board 🛠 All tutorials