Sharing an advanced tutorial about adding a second analogue input and use the ADC Conversion Complete interrupt. Look at the following circuit and here ATmega168A microcontroller is used. Seeing more details,please refer to the datasheet of ATmega168A.
The code is given below:
1 #include <avr/io.h>
2 #include <avr/interrupt.h>
3 #include "hd44780.h"
4
5 volatile uint16_t adc[]={0,0};
6 uint8_t requested_adc_channel=0;
7
8 void ReadADC_Request(uint8_t __channel)
9 {
10 if (bit_is_set(ADCSRA,ADSC))
11 {
12 //If another ADC read is in progress, display a message and halt processing
13 lcd_goto(0);
14 lcd_puts("ADC Error");
15 abort();
16 }
17 else
18 {
19 requested_adc_channel = __channel; //We'll need this when reading the value
20
21 ADMUX = (ADMUX & 0x11110000) | __channel; //Channel selection
22 ADCSRA |= _BV(ADSC); //Start conversion
23 }
24 }
25
26 void adc_init()
27 {
28 //Enable ADC, set 128 prescale and enable the interrupt
29 ADCSRA = _BV(ADEN) | _BV(ADPS2) | _BV(ADPS1) | _BV(ADPS0) | _BV(ADIE);
30 sei(); //Enable interrupts
31 }
32
33 ISR(ADC_vect,ISR_NOBLOCK)
34 {
35 adc[requested_adc_channel]=ADC; // Store the resulting value to the adc results array
36 }
37
38
39 int main (void)
40 {
41 lcd_init();
42 adc_init();
43
44 unsigned long count=0;
45 char buffer[16];
46 while (1)
47 {
48 ReadADC_Request(count % 2);
49 //Uncomment the line below to generate an error in ReadADC_Request
50 //ReadADC_Request(count % 2);
51
52 count++;
53 sprintf(buffer,"%u ", count);
54 lcd_goto(40);
55 lcd_puts(buffer);
56
57 //The lcd_puts command is pretty slow (>1ms) so by the time we get
58 //here the AD conversion would have already occurred and the
59 //interrupt service routine called.
60
61 sprintf(buffer,"%4u %4u", adc[1], adc[0]);
62 lcd_goto(0);
63 lcd_puts(buffer);
64 }
65
66 return(0);
67 }
When setting the prescaler to 128,it takes 1644-3200 clock cycles to read the analogue input.Whilst this is occuring we could be doing other things.
On line 48 we initiate an AD Converter read. Because we can only read one analogue input at a time we pass “count % 2” as the channel number. This evaluates to a 0 or 1 depending on the odd or even value of count. Whilst the analogue value is being read, we output count to the LCD display. The reason for this is to simulate the system being busy doing something. In a real system you would be doing something much more interesting than outputting a count.
The interrupt service routine reads in the ADC value and stores it in adc[0] or adc[1]. By the time we get to line 61, one of these values has been updated and we are ready to output it to the LCD display.
Best regards~