ADC-Prescaler automatisch bestimmen

Will man ADC-Messungen mehrfach für verschiedene CPU-Taktfrequenzen einsetzen, ist es ganz nützlich den ADC-Prescaler automatisch bestimmen zu lassen. Hierzu habe ich bei AVRFREAKS unter diesem Post nachfolgende Makro gefunden. Im zugehörigen Thread gibt es eine ganze Reihe von allgemeinen und speziellen Hinweisen, wie man eine Automatisierung von Prescalern vornehmen kann, z.B. auch solche für die Timer.

#define ADC_CLK (F_CPU / ADC_PRESCALER)
#define ADC_PRESCALER 2U
#define ADC_PRESCALER_MASK 0x0U

#if (ADC_CLK > ADC_CLK_MAX)
  #undef ADC_PRESCALER
  #undef ADC_PRESCALER_MASK
  #define ADC_PRESCALER 4U
  #define ADC_PRESCALER_MASK 0x2U
#endif

#if (ADC_CLK > ADC_CLK_MAX)
  #undef ADC_PRESCALER
  #undef ADC_PRESCALER_MASK
  #define ADC_PRESCALER 8U
  #define ADC_PRESCALER_MASK 0x3U
#endif

...

// Grenzen für ADC_CLK überprüfen.
#if (ADC_CLK < ADC_CLK_MIN)
  #error No ADC prescaler exists for ADC_CLK_MIN <= clkADC.
#endif
#if (ADC_CLK > ADC_CLK_MAX)
  #error No ADC prescaler exists for clkADC <= ADC_CLK_MAX.
#endif

Es wird einfach beginnend beim kleinsten Wert für den Prescaler der Reihe nach alle Prescaler-Werte geprüft, bis ein passender gefunden wurde. Die Grenzen für die den ADC-Takt werden über die Konstanten ADC_CLK_MIN und ADC_CLK_MAX vorgegeben. Beim Arduino (ATmega328p) liegen diese Grenzwerte bei 50 kHz und 200 kHz. Zum Schluss wird sicherheitshalber geprüft, ob auch wirklich ein valider Wert gefunden wurde.

Eingebunden wird das Makro wie folgt:

// Prescaler ermitteln
#define ADC_CLK_MIN  50000UL
#define ADC_CLK_MAX 200000UL
#include "ADC-Timing.h"

Danach steht die Konstante ADC_PRESCALER_MASK zur Verfügung, die z.B. wie folgt genutzt werden kann:

ADCSRA = (1<<ADEN) | ADC_PRESCALER_MASK;

ADC-Timing.h zum Download.

30.5.2015: Es wird geprüft, ob F_CPU definiert ist.