Arduino Interrupts Speed Up Your Arduino To Be Responsive To Events PDF
Arduino Interrupts Speed Up Your Arduino To Be Responsive To Events PDF
Interrupts
Claus Kühnel
1. Edition 05/10/2017
Version 1.0
© 2017 Skript Verlag Kühnel, CH-8852 Altendorf, Switzerland
All rights reserved.
ISBN-10: 3-907857-34-8
ISBN-13: 978-3-907857-34-2
www.ckskript.ch
The book and the circuits described, procedures and programs, have been
carefully created and tested. Nevertheless, errors and mistakes cannot be
excluded.
Preface
Arduino family of microcontrollers has become an integral part of the world of
electronics. Users of Arduino range from makers to enthusiasts to
professionals. Therefore, it is not surprising that a large number of books on
the different aspects of application and programming of Arduino are available.
This is not another book on these aspects. I would like to deal with
interrupts, which make the execution of the Arduino program more effective.
Some years ago I published the book "Arduino: Hard- und Software Open
Source Plattform" (ISBN 978-3-907857-16-8) in German language. From my
readers I know that the section covering interrupts is seen as an important
complement to the widely available basics. This was the base for writing this
eBook which explains the usage of the interrupts of the ATmega328 based
Arduino.
Knowledge of Arduino and its programming with the Arduino development
environment (IDE) are assumed.
Arduino Boards
Arduino ADC
Internal ADC and PWM as DAC
Internal ADC in Free Running Mode
Arduino Interrupts
Contact to the outside world
ATmega328 Interrupt System
ATmega328 Interrupt Vector Table
External Interrupts INT0 & INT1
Registers for INT0 & INT1
INTx Program Sample
Pin Changed Interrupts PCINTx
Registers for PCINTx
PCINTx Program Sample
Timer Interrupts
Registers for Timer2
Register for Timer1
Timer2 Program Sample
Timer1 Program Sample
Watchdog
Watchdog Register
Watchdog Interrupt Program Sample
Analog Comparator
Registers for Analog Comparator
Analog Comparator Program Sample
Analog/Digital-Converter
Registers for ADC
ADC Program Samples
Resume
Impressum
Arduino Boards
If we talk about Arduino today we have to talk about the whole Arduino
family. Starting with Arduinos based on Atmel's AVR microcontrollers now
we have with Atmel's SAMD21 Cortex-M0 included in the family.
Furthermore, with Arduino Yùn and Arduino Tian we have Arduinos enhanced
by Linux devices.
Nevertheless, the ATmega328 based Arduino Uno Rev. 3 is the best-selling
device of the Arduino family furthermore (Figure 1).
If you prefer a more compact solution then you will find Arduino Nano
based on the same ATmega328 microcontroller as the Arduino Uno (Figure 2).
The assignment of the connectors of the Arduino Uno to the pins of the
ATmega328 (and the alternative functions) is shown in the following tables:
Like all other pins, the analog inputs are also equipped with switchable pull-
up resistors. However, a pull-up resistor that is switched on influences the AD
conversion. Therefore, pull-up resistors must be disabled while the pin is
configured as an analog input. Errors can also be expected if the connection
has previously been configured as a digital output.
In the following program example, adda.ino, an output voltage is generated
by PWM (pulse-width modulation). This voltage is smoothed to a DC voltage
by a RC combination. This DC voltage is, in turn, supplied to the ADC, and the
result of the AD conversion should then represent the value of the DA
converter. Figure 4 shows the complete circuitry.
If the time constant RC is selected too high, the settling time increases. If, on
the other hand, it is too small, the filtering effect is too low.
The time constant of 47 ms chosen according to Figure 4 is rather at the
lower end, which is why an optimal filter effect is not expected. But, this is
sufficient to demonstrate the principle of DA-AD-conversion.
In the program example adda.ino (Listing 1), a PWM value is set to I/O9
with analogWrite(AOUT, i) . The low-pass filter output is connected to the
analog input AIN0 of the internal ADC (ADC0). After a waiting time of 1
sec( delay (1000) ) the result of AD conversion is read
with analogRead(AIN0) . This procedure is repeated in an endless loop. The
remaining instructions are for serial output and configuration only.
A special feature is still to be considered. The 8-bit Timer1 is used for the
PWM, which is why only values between 0 and 255 can be set here. The
internal ADC, however, has a resolution of 10 bits, which is why the results
are between 0 and 1024. The factor 4 is therefore taken into account when
calculating the deviation (ADC-4DAC).
// Title : ADDA
// Author : Claus Kuehnel <ckuehnel@gmx.ch>
// Date : 2017-05-10
// Id : adda.ino
// Tested w/ : Arduino 1.8.0
//
// DISCLAIMER:
// The author is in no way responsible for any problems or damage caused by
// using this code. Use at your own risk.
//
// LICENSE:
// This code is distributed under the GNU Public License
// which can be found at http://www.gnu.org/licenses/gpl.txt
//
void setup()
{
pinMode(AOUT, OUTPUT); // configure PWM output
Serial.begin(19200); // baud rate of console output
Serial.println("DAC\tADC\tADC-4DAC");
}
void loop()
{
int i, val;
for (i=0; i<256; i+=16)
{
analogWrite(AOUT, i); // set PWM value from 0 to 255
delay(1000);
Serial.print(i); // console output of DAC (PWM) value
Serial.print("\t");
val = analogRead(AIN0); // read ADC result
Serial.print(val); // console output of ADC result
Serial.print("\t");
Serial.println(val - 4*i); // calculate deviation and output it
}
}
Listing 1 Source code adda.ino
After the start of the program adda.ino the console output can be viewed in
the monitor of the Arduino IDE. Figure 5 shows the serial output of the
individual conversions. The third column shows the calculated deviation
ADC-4DAC which cannot show typical values for the internal ADC because
of the non-optimum RC filtering.
Figure 5 Console output of adda.ino
Internal ADC in Free Running Mode
The internal ADC of the Arduino can operate not only in the single conversion
mode used by analogRead() but also in the free running mode. For the
initialization of the free running mode and to readout the results of the AD
conversion, however, one must use the direct register access.
The multiple registers are responsible for the operation of the ADC. At this
point, only the initialization can be considered. To look for all options, you
have to study the large-scale data sheet of the ATmega328.
The analog reference voltage can be selected via the ADMUX register
(REFS1, REFS0). I use AVcc = 5 V as reference voltage. The data format can
be set to left or right justified (ADLAR) and the analog multiplexer is set via
the bits MUX3-MUX0.
As can be seen from Figure 3, the analog inputs are not limited to the inputs
ADC5-ADC0. Still interesting for commissioning are the internal bandgap
reference, the internal ground and the temperature sensor. These are also
queried as known input voltages in the program example.
The setup of the two registers can be found most easily from the source code
of the program sample free_running_adc.ino (Listing 2).
// ADCSRA
#define FREE_RUNNING_MODE ((1<<ADEN) | (1<<ADSC) | (1<<ADATE) |
(1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0))
#define PURPOSE "Test of Free Running ADC"
word adc_value;
word getADC(void)
{
return (ADCL | (ADCH << 8));
}
void printResult(void)
{
digitalWrite(LED, 1); // LED on
delay(10);
adc_value = getADC();
digitalWrite(LED, 0); // LED off
Serial.print(adc_value, HEX); // output ADC value
Serial.print("\t");
Serial.print((float) adc_value*5./1024); // calculate voltage and output
Serial.println(" V\n");
}
void setup()
{
pinMode(LED, OUTPUT);
Serial.begin(19200);
Serial.println(PURPOSE);
}
void loop()
{
Serial.println("Bandgap Reference");
setADC(BANDGAP);
printResult();
delay(1000);
Serial.println("GND");
setADC(GND);
printResult();
delay(1000);
Serial.println("Temperature");
setADC(TEMPERATURE);
printResult();
delay(1000);
}
Listing 2 Source code free_running_adc.ino
The interrupt enable bits are located in the EIMSK register - the interrupt
flags in the EIFR register.
INTx Program Sample
For the handling of the interrupts INT0 and INT1, the
functions attachInterrupt(interrupt, function,
mode) and detachInterrupt(interrupt, function, mode) , which hide the register
handling, are already available in the Arduino language.
In the program example externalInterrupt.ino (Listing 3) the serial data
output is controlled by these two interrupts.
int idx;
void setup()
{
Serial.begin(19200);
pinMode(pLED, OUTPUT);
pinMode(pINT0, INPUT);
digitalWrite(pINT0, HIGH); // Pullup active
pinMode(pINT1, INPUT);
digitalWrite(pINT1, HIGH); // Pullup active
void loop()
{
if (iflag) Serial.println(idx); // iflag controls serial output
idx++;
delay(500);
}
void stop_serial()
{
iflag = false;
digitalWrite(pLED, HIGH);
}
void resume_serial()
{
iflag = true;
digitalWrite(pLED, LOW);
}
Listing 3 Source code externalInterrupt.ino
Interrupts INT0 and INT1 are fix assigned to the two inputs PD2 and PD3 of
the ATmega328 (Arduino Uno: Digital IO 2 and 3). The corresponding pins are
therefore constants.
In the setuproutine, these two pins are set as input with pull-up resistor
activated. The interrupt INT0 is used to link the routine stop_serial() , and
INT1 resume_serial() . The global interrupt is already enabled by the
initialization, so this does not have to be done explicitly.
The EICRA register shows the value 0x0A at the end of the setup, which
means that both inputs request a corresponding interrupt for a falling edge.
An index is incremented in the main loop of the program. The output of the
index value can be stopped by INT0 and resumed by INT1. The connected
LED signals the respective state.
Figure 10 shows the terminal output of the program example. At the
beginning, the initialization values of the registers involved are output to the
console. At the level of the index value of 1, the output was interrupted. When
the output was continued, the index value was already increased to 12.
// Title : PCINT
// Author : Claus Kuehnel <ckuehnel@gmx.ch>
// Date : 2017-05-10
// Id : PCInt.ino
// Tested w/ : Arduino 1.8.0
//
// DISCLAIMER:
// The author is in no way responsible for any problems or damage caused by
// using this code. Use at your own risk.
//
// LICENSE:
// This code is distributed under the GNU Public License
// which can be found at http://www.gnu.org/licenses/gpl.txt
//
// Definition of interrupt names
#include <avr/io.h>
// ISR interrupt service routine
#include <avr/interrupt.h>
int idx;
void setup()
{
Serial.begin(19200);
pinMode(pLED, OUTPUT);
digitalWrite(pLED, LOW);
pinMode(pPCINT8, INPUT);
digitalWrite(pPCINT8, HIGH); // Pullup active
pinMode(pPCINT9, INPUT);
digitalWrite(pPCINT9, HIGH); // Pullup active
void loop()
{
if (iflag) Serial.println(idx); // iflag controls serial output
idx++;
delay(500);
}
Listing 4 Source code PCInt.ino
The inputs PC0 (PCINT8) and PC1 (PCINT9) of ATmega328 (Arduino Uno:
Analog In 0 and 1) influence the terminal output of the main loop via the
corresponding interrupts.
Both pins are initialized as input with pull-up resistor activated. Both inputs
trigger an interrupt request from PCI1, which is why this group must be
enabled. In addition, the relevant bits must be set in the interrupt mask.
The interrupt service routine is started in both cases, so the ISR must request
the input that requested the interrupt. The iflag and the LED are set
accordingly.
In the main loop of the program example, an index is incremented again. The
output of the index value can be stopped by PCINT8 and resumed by PCINT9.
The connected LED signals the respective state.
Figure 11 shows the terminal outputs of this program example. At the
beginning, the initialization values of the registers involved are output to the
console. At the level of the index value of 4, output was interrupted. When the
output was continued, the index value was already increased to 14.
in which the counting range for Timer2 is limited to 0...255 and for Timer1
to 0...65537.
Registers for Timer2
Timer2 can generate three different interrupts. In the register TIMSK2, the two
Output Compare Match interrupts can be enabled via bits OCIE2B and
OCIE2A as well as the timer overflow interrupt via bit TOIE2.
In the case of the Output Compare Match Interrupt, the interrupt request
occur when the timer register TCNT2 has reached the value of the register
OCR2A or OCR2B. The timer overflow interrupt is set to 0 when the register
is overrun.
The configuration of Timer2 is performed via the registers TCCR2A and
TCCR2B according to Table 4 to Table 6.
In the case of the Output Compare Match Interrupts, the interrupt request is
made when the timer register TCNT1 has reached the value of the register
OCR1A or OCR1B. The timer overflow interrupt is set to 0 when the register
is overflowed from 0xFFFF.
Since Timer1 is a 16-bit timer/counter, the registers OCR1A and OCR1B are
16-bit registers, too.
The configuration of Timer1 is performed via the registers TCCR1A and
TCCR1B according to Table 7 to Table 9.
// Title : msecTimer
// Author : Claus Kuehnel <ckuehnel@gmx.ch>
// Date : 2017-05-10
// Id : msecTimer.ino
// Tested w/ : Arduino 1.8.0
//
// DISCLAIMER:
// The author is in no way responsible for any problems or damage caused by
// using this code. Use at your own risk.
//
// LICENSE:
// This code is distributed under the GNU Public License
// which can be found at http://www.gnu.org/licenses/gpl.txt
//
// Definition of interrupt names
#include <avr/io.h>
// ISR interrupt service routine
#include <avr/interrupt.h>
void setup()
{
Serial.begin(19200);
pinMode(pLED, OUTPUT);
digitalWrite(pLED, LOW);
cli();
TCCR0B = 0; // stop timer0
OCR2A = reload;
Serial.print("OCR2A: "); Serial.println(OCR2A, HEX);
TCCR2A = 1<<WGM21;
Serial.print("TCCR2A: "); Serial.println(TCCR2A, HEX);
TCCR2B = (1<<CS22) | (1<<CS21) | (1<<CS20);
Serial.print("TCCR2B: "); Serial.println(TCCR2B, HEX);
TIMSK2 = (1<<OCIE2A);
Serial.print("TIMSK2: "); Serial.println(TIMSK2, HEX);
sei();
Serial.println("Setup finished.");
}
void loop()
{
if (count == 50)
{
flash();
Serial.print(".");
count = 0;
}
}
void flash()
{
static boolean output = HIGH;
digitalWrite(pLED, output);
output = !output;
}
Listing 5 Source code msecTimer.ino
// Title : secTimer
// Author : Claus Kuehnel <ckuehnel@gmx.ch>
// Date : 2017-05-10
// Id : secTimer.ino
// Tested w/ : Arduino 1.8.0
//
// DISCLAIMER:
// The author is in no way responsible for any problems or damage caused by
// using this code. Use at your own risk.
//
// LICENSE:
// This code is distributed under the GNU Public License
// which can be found at http://www.gnu.org/licenses/gpl.txt
//
// Definition of interrupt names
#include <avr/io.h>
// ISR interrupt service routine
#include <avr/interrupt.h>
void setup()
{
Serial.begin(19200);
pinMode(pLED, OUTPUT);
digitalWrite(pLED, LOW);
cli();
TCCR1A = 0;
TCCR1B = 0; // Stop Timer1
OCR1A = reload;
TCCR1B = (1<<WGM12) | (1<<CS12); // CTC Mode Prescaler = 256
TIMSK1 = (1<<OCIE1A); // Timer1 CompareA Interrupt enable
sei(); // Global Interrupt enable
void loop()
{
Serial.println(count); // do anything
delay(200);
}
void flash()
{
static boolean output = HIGH;
digitalWrite(pLED, output);
output = !output;
}
Listing 6 Source code secTimer.ino
// Title : Watchdog
// Author : Claus Kuehnel <ckuehnel@gmx.ch>
// Date : 2017-05-10
// Id : watchdog.ino
// Tested w/ : Arduino 1.8.0
//
// DISCLAIMER:
// The author is in no way responsible for any problems or damage caused by
// using this code. Use at your own risk.
//
// LICENSE:
// This code is distributed under the GNU Public License
// which can be found at http://www.gnu.org/licenses/gpl.txt
//
// Definition of interrupt names
#include <avr/io.h>
// ISR interrupt service routine
#include <avr/interrupt.h>
int idx;
// Install the interrupt routine for Watchdog Interrupt
ISR(WDT_vect)
{
flash();
}
void setup()
{
Serial.begin(19200);
pinMode(pLED, OUTPUT);
digitalWrite(pLED, LOW);
cli();
wdt_reset();
WDTCSR |= (1<<WDCE) | (1<<WDE); // Start timed sequence
WDTCSR = (1<<WDIE) | (1<<WDP2) | (1<<WDP1); // Set new prescaler = 128K cycles
(~1 s)
sei();
Serial.print("WDTCSR: ");
Serial.println(WDTCSR, HEX);
Serial.println("Setup finished.");
}
void loop()
{
Serial.println(idx++); // do anything
delay(1500); // change argument to 1500 -> watchdog will be active
wdt_reset();
}
void flash()
{
static boolean output = HIGH;
digitalWrite(pLED, output);
output = !output;
}
Listing 7 Source code watchdog.ino
Figure 15 Terminal output watchdog.ino
Analog Comparator
The Analog Comparator compares the voltage values at pins PD6 and PD7
(Arduino Uno: Digital IO 6 and 7). If the voltage at PD6 is higher than at PD7,
then the output of the comparator is set. This output can be used to request an
interrupt. Figure 16 shows a block diagram of the analog comparator and the
circuit parts surrounding it.
The comparator can be switched off via bit ACD and the bandgap reference
can be connected to the comparator (A +) with ACBG. The bits ACIE and
ACIC enable the interrupt or the input capture. The interrupt configuration
takes place via the bits ACIS1 and ACIS0 according to Table 12.
// Title : ACOMP
// Author : Claus Kuehnel <ckuehnel@gmx.ch>
// Date : 2017-05-10
// Id : acomp.ino
// Tested w/ : Arduino 1.8.0
//
// DISCLAIMER:
// The author is in no way responsible for any problems or damage caused by
// using this code. Use at your own risk.
//
// LICENSE:
// This code is distributed under the GNU Public License
// which can be found at http://www.gnu.org/licenses/gpl.txt
//
// Definition of interrupt names
#include <avr/io.h>
// ISR interrupt service routine
#include <avr/interrupt.h>
int idx;
// Install the interrupt routine for ACOMP
ISR(ANALOG_COMP_vect)
{
if ( ACSR & (1<<ACO) ) // ACO is set?
{
iflag = false;
digitalWrite(pLED, HIGH);
}
else
{
iflag = true;
digitalWrite(pLED, LOW);
}
}
void setup()
{
Serial.begin(19200);
pinMode(pLED, OUTPUT);
digitalWrite(pLED, LOW);
pinMode(pAIN1, INPUT);
cli();
ADCSRA &= ~(1<<ADEN); // ADC disabled
ADCSRB |= ~(1<<ACME); // AMUX enabled
ACSR = (1<<ACBG) | (1<<ACIE); // ACOMP Interrupt enabled
DIDR1 = (1<<AIN1D) | (1<< AIN0D);
sei();
void loop()
{
if (iflag) Serial.println(idx); // iflag controls serial output
idx++;
delay(500);
}
Listing 8 Source code acomp.ino
The bits REFS1 and REFS0 set the reference voltage. After a reset, an
external reference voltage is expected at the AVREF connector. Table 13
shows the options selectable.
The ADLAR bit specifies whether the result of the AD conversion is left-
aligned (ADLAR = 1, xxxxxxxxxx000000) or right-aligned (ADLAR = 0,
000000xxxxxxxxxx) in the 16-bit result.
The MUX3:0 bits program the analog multiplexer. After reset, input ADC0 is
active. Table 14 shows the options selectable.
The bits ADTS2: 0 determine the trigger source for the AD conversion, if the
bit ADATE is set in the register ADCSR. Otherwise, they are not affected
(Table 16).
Table 16 Selection of Trigger Source for Auto-trigger
ADC Program Samples
As the register description has shown, the AD converter of the ATmega328
allows different operating modes and different reference voltages. In addition,
the various analog inputs can be routed through the analog multiplexer to the
AD converter.
For testing the different operating modes, I always used the internal bandgap
reference as the input voltage. In this way one knows the expected result and
can concentrate on configuration and initialization.
Software-triggered AD-Conversion
For Arduino the software-triggered AD conversion provides the
instruction analogRead(analogPin) .
By initialization, the AD converter is already enabled and the prescaler is
set to 128. The clock frequency for the AD conversion is 125 kHz at an
oscillator frequency of 16 MHz.After 80 s, an AD conversion is completed.
The voltage AVCC serves as a reference voltage.
Since we are dealing with the interrupt modes, this type of AD conversion is
not considered further below.
A detailed description of this AD conversion mode is available at
http://arduino.cc/en/Reference/AnalogRead.
Free-Running AD-Conversion
In Free Running Mode, the next AD conversion is automatically started after
the completion of preceding AD conversion.
Now we want to configure the ADC for the Free Running Mode to measure
the bandgap reference voltage.
The reference voltage and the input channel are selected via the ADMUX
register. The bits ADEN, ADATE and ADIE of the ADCSRA register are set,
which defines an interrupt-controlled auto-trigger function. The desired
interrupt source is selected with the bits ADTSx in register ADCSRB.
For the Free Running Mode, the default values after reset (ADTS2:0 = 000)
are valid, which is why you do not have to worry about this anymore. The
interrupt source is the Interrupt ADC Conversion Complete, which is signaled
by the ADIF interrupt flag.
A first result is available in the ADCH and ADCL registers with the start of the
second AD conversion. The second and each further AD conversion are started
by the interrupt request (ADIF) at the end of the previous AD conversion. Only
the first AD conversion is to be started as before by setting the bit ADS.
Listing 9 shows the source code for the program example adc2s.ino.
// Title : ADC2s
// Author : Claus Kuehnel <ckuehnel@gmx.ch>
// Date : 2017-05-10
// Id : ADC2s.ino
// Tested w/ : Arduino 1.8.0
//
// DISCLAIMER:
// The author is in no way responsible for any problems or damage caused by
// using this code. Use at your own risk.
//
// LICENSE:
// This code is distributed under the GNU Public License
// which can be found at http://www.gnu.org/licenses/gpl.txt
//
// Definition of interrupt names
#include <avr/io.h>
// ISR interrupt service routine
#include <avr/interrupt.h>
#define ADC0 0
#define TEMP 0b1000
#define VBG 0b1110
ISR(ADC_vect)
{
ADC_result = ADC;
}
void setup()
{
Serial.begin(19200);
pinMode(pLED, OUTPUT);
digitalWrite(pLED, LOW);
cli();
ADMUX = (0<<REFS1) | (1<<REFS0); // AVCC is reference
ADMUX |= VBG; // VBG selected
ADCSRA |= (1<<ADEN) | (1<<ADATE) | (1<<ADIE); // ADC enabled, prescaler
unchanged
ADCSRB = 0; // Free Running Mode
ADCSRA |= (1<<ADSC);
sei();
void loop()
{
cli();
ADC_result = ADC;
sei();
Serial.print("ADC: "); Serial.print(ADC_result,HEX);
voltage = ADC_result* VACC/1024;
Serial.print("\tVoltage: "); Serial.print(voltage,3);
Serial.println(" V");
delay(1000);
}
Listing 9 Source code ADC2s.ino
// Title : ADC3s
// Author : Claus Kuehnel <ckuehnel@gmx.ch>
// Date : 2017-05-10
// Id : ADC3s.ino
// Tested w/ : Arduino 1.8.0
//
// DISCLAIMER:
// The author is in no way responsible for any problems or damage caused by
// using this code. Use at your own risk.
//
// LICENSE:
// This code is distributed under the GNU Public License
// which can be found at http://www.gnu.org/licenses/gpl.txt
//
// Definition of interrupt names
#include <avr/io.h>
// ISR interrupt service routine
#include <avr/interrupt.h>
#define ADC0 0
#define TEMP 0b1000
#define VBG 0b1110
unsigned int reload = 0xFFFF - 0xF424; // TCNT1 Reload for one second@16 MHz clock
& prescaler 256
volatile unsigned int ADC_result;
volatile boolean ADC_flag = false;
float voltage;
void setup()
{
Serial.begin(19200);
pinMode(pLED, OUTPUT);
digitalWrite(pLED, LOW);
cli();
TCCR1A = 0;
TCCR1B = 0; // Stop Timer1
TCNT1 = reload;
TCCR1B = (1<<CS12); // Normal Mode, Prescaler = 256
TIMSK1 = (1<<TOIE1); // Timer1 Overflow Interrupt enable
Serial.println("Timer1 Configuration");
Serial.print("TCCR1A: "); Serial.println(TCCR1A, HEX);
Serial.print("TCCR1B: "); Serial.println(TCCR1B, HEX);
Serial.print("TIMSK1: "); Serial.println(TIMSK1, HEX);
void loop()
{
if (ADC_flag)
{
cli();
ADC_result = ADC;
sei();
Serial.println();
Serial.print("ADC: "); Serial.print(ADC_result,HEX);
voltage = ADC_result* VACC/1024;
Serial.print("\tVoltage: "); Serial.print(voltage,3); Serial.println(" V");
ADC_flag = false;
}
else
{
Serial.print(".");
delay(100);
}
}
void flash()
{
static boolean output = HIGH;
digitalWrite(pLED, output);
output = !output;
}
Listing 10 Source code ADC3s.ino
eMail: ckuehnel@gmx.ch
Website: www.ckuehnel.ch