AVR Embedded Tutorial - Analog Read
This code is for an Atmega328/Arduino runnning at 16MHz. How to control the UART can be found here:
The ATmega328 can measure with 10-bit accuracy, so a value between 0..1023 is output.
Configure analog reading. AVcc is used as the reference voltage, this is the easiest way. This must be configured with ADMUX.
The following reference voltages can be configured with ADMUX:
|Bit 7||Bit 6||Description|
The converter is started with ADCSRA.
procedure ADC_Init; begin ADMUX := (1 shl REFS); // Use AVcc for reference ADCSRA := (1 shl ADEN) or %111; // Switch on converter, divider 128 end;
The procedure for measuring is as follows.
- Specify the port.
- Wait until the measurement is complete.
- Read out the measured value.
With ADMUX you have to enter the reference voltage again because it shares the register with the reference. You could also do an OR operation with ADMUX .
function ADC_Read(Port : byte) : integer; begin ADMUX := (1 shl REFS) or (Port and $0F); // Specify port ADCSRA := ADCSRA or ( 1 shl ADSC ); // Start measuring while (ADCSRA and (1 shl ADSC)) <> 0 do // Wait until measured begin end; Result := ADC; // Read out the measured value end;
If you always read in from the same port, you only have to call up the ADMUX line once. You can also start measuring directly after the while loop which saves a few clock cycles.
Output via UART
Buffer variables for the measurement data.
var Data : integer; s : string;
The measurement data is then output in an endless loop.
begin // Initialize UART UARTInit; // Initialize ADC ADC_Init; // Allow interrupt asm Sei end; // output measured values. repeat Data := ADC_Read(0); str(Data : 6, s); UARTSendString(s); until 1 = 2; end.
The advantage of the interrupt-controlled method is that you do not have to wait until the measurement is finished, so you have time for other things.
- With ADMUX you enter the input port at the beginning.
- At ADCSRA you have to start the first measurement with ADSC.
- With ADIE you communicate that the conversion interrupt is controlled.
procedure ADC_Init; const Port = 0; begin ADMUX := (1 shl REFS) or (Port and $0F); ADCSRA := %111 or (1 shl ADEN) or (1 shl ADSC) or (1 shl ADIE); end;
Output measured value in the interrupt
procedure ADC_Ready public name 'ADC_ISR'; interrupt; var Data : integer; s : string; begin Data := ADC; ADCSRA := ADCSRA or (1 shl ADSC); str(Data : 6, s); UARTSendString(s); end;
Since the measurement is interrupt-controlled, the main loop remains empty. It is important to switch on the interrupts.
begin // Initialize UART UARTInit; // ADC ADC_Init; // Allow interrupt asm Sei end; // main loop repeat // Do something until 1 = 2; end.
- AVR Embedded Tutorials - Overview