Full Version : How to Setup Cheap ADC (AVR ASM)
avr >>BEGINNER UTILITIES >>How to Setup Cheap ADC (AVR ASM)


AVR_Admin- 05-17-2006
How to Setup Cheap ADC (AVR ASM)

CODE

;**** A P P L I C A T I O N   N O T E   A V R 4 0 0 ************************
;*
;* Title:  Low Cost A/D Converter
;* Version:  1.0
;* Last updated: 97.07.18
;* Target:  AT90Sxxxx (All AVR Devices)
;*
;* Support E-mail: avr@atmel.com
;*
;* Code Size  :37 words
;* Low Register Usage :0
;* High Register Usage :2
;* Status Flag Usage  :1 (t flag)
;* Interrupt usage :Timer/Counter0 overflow interrupt,
;*    Analog comparator interrupt
;*
;* DESCRIPTION
;*
;* This application note shows how you can make a A/D converter using a AVR
;* device, one external resistor and one external capacitor. This solution
;* uses the Timer/Counter0 overflow interrupt in addition to the Analog
;* comparator interrupt. The usage of interrupts free's the MCU while
;* conversion is taking place.
;*
;* To minimize the usage of external components, this A/D converter uses
;* the charging of a capacitor (controlled by port D pin 2)through a
;* resistor while converting.
;* The voltage across the capacitor will follow an exponential curve of
;* voltage versus time. By constricting the voltage range of
;* the converter to 2/5Vdd, the exponential curve is a good approximation
;* of a straight line. This makes it possible to simply measure the time
;* it takes before the voltage across the capacitor equals the voltage which
;* is to be converted. To do this we use the analog comparator. The
;* comparator will give an interrupt when the voltage across the capacitor
;* rises above the measurement voltage. The output is divided into 64
;* different levels.
;*
;* To ensure correct timing the time constant of the RC-network must
;* satisfie   512*(1/f)=-R*C*ln(1-2/5).
;* For the A/D converter to operate properly, the capacitor must be  
;* completly discharged between each conversion. This is done by allowing
;* the discharging to take a minimum of 200us.
;*  
;*
;* *** Initialization
;*
;*  1. Call convert_init
;*  2. Enable global interrupts (with sei)
;*
;* *** A/D conversion
;*
;*  1. Call AD_convert
;*  2. Wait for conversion complete (t to be set) (less than 521 cycles)
;*  3. Read data from result
;**************************************************************************


.include "1200def.inc"

;***** Constants

.equ preset=192  ;T/C0 Preset constant (256-64)

;***** A/D converter Global Registers

.def result=r16  ;Result and intermediate data
.def temp=r17  ;Scratch register




;**************************************************************************
;*
;*   PROGRAM START - EXECUTION STARTS HERE
;*
;**************************************************************************
.cseg


.org $0000
rjmp RESET     ;Reset handle
.org OVF0addr
rjmp ANA_COMP  ;Timer0 overflow handle
.org ACIaddr
rjmp ANA_COMP  ;Analog comparator handle



;**************************************************************************
;*
;* ANA_COMP - Analog comparator interrupt routine
;*
;*
;* DESCRIPTION
;* This routine is executed when one of two events occur:
;* 1. Timer/counter0 overflow interrupt
;* 2. Analog Comparator interrupt
;* Both events signals the end of a conversion. Timer overflow if the signal
;* is out of range, and analog comparator if it is in range.
;* The offset will be corrected, and the t'flag will be set.
;* Due to the cycles needed for interruption handling, it is necessary
;* to subtract 1 more than was added previously.
;*
;*
;* Total numbers of words  : 7
;* Total number of cycles  : 10
;* Low register usage   : 0
;* High register usage   : 2 (result,temp)
;* Status flags    : 1 (t flag)
;*
;**************************************************************************
ANA_COMP:       in      result,TCNT0   ;Load timer value

        clr     temp    ;Stop timer0
 out     TCCR0,temp        

 subi    result,preset+1;Rescale A/D output

 cbi     PORTD,PD2      ;Start discharge
 set  ;Set conversion complete flag
 
 reti                   ;Return from interrupt


;**************************************************************************
;*
;* convert_init - Subroutine for A/D converter initialization
;*
;*
;* DESCRIPTION
;* This routine initializes the A/D converter. It sets the timer and the
;* analog comparator. The analog comparator interrupt is being initiated by  
;* a rising edge on AC0. To enable the A/D converter the global interurrupt
;* flag must be set (with SEI).
;*
;* The conversion complete flag (t) is cleared.
;*
;* Total number of words  : 6
;* Total number of cycles  : 10
;* Low register usage   : 0
;* High register usage   : 1 (result)
;* Status flag usage   : 0
;*
;**************************************************************************
convert_init:
        ldi     result,$0B   ;Initiate comparator
 out     ACSR,result ;and enable comparator interrupt

 
 ldi     result,$02     ;Enable timer interrupt
 out     TIMSK,result
 
 sbi     PORTD,PD2      ;Set converter charge/discharge
   ;as output

 ret  ;Return from subroutine



;**************************************************************************
;*
;* AD_convert - Subroutine to start an A/D conversion
;*
;* DESCRIPTION
;* This routine starts the conversion. It loads the offset value into the
;* timer0 and starts the timer. It also starts the charging of the
;* capacitor.
;*
;*
;* Total number of words  : 7
;* Total number of cycles  : 10
;* Low register usage   : 0
;* High register usage   : 1 (result)
;* Status flag usage   : 1 (t flag)
;*
;**************************************************************************
AD_convert:
 ldi     result,preset  ;Clear counter
 out     TCNT0,result   ;and load offset value
 
 clt  ;Clear conversion complete flag (t)

 ldi result,$02;Start timer0 with prescaling f/8
 out     TCCR0,result    
 sbi     PORTB,PB2      ;Start charging of capacitor
 

 ret  ;Return from subroutine


;**************************************************************************
;*
;* Example program
;*
;* This program can be used as an example on how to set up the A/D
;* converter properly.
;* NOTE! To ensure proper operation, make sure the discharging period
;* of the capacitor  is longer than 200us in front of each conversion.  
;* The results of the conversion is presented on port B.
;* To ensure proper discharging we have added a delay loop. This loop is
;* 11 thousand cycles. This will give a 550us delay with a 20MHz oscillator
;* (11ms with a 1MHz oscillator).
;*
;**************************************************************************

RESET:
 rcall convert_init;Initialize A/D converter
 sei  ;Enable global interrupt
 ldi result,$ff;set port B as output
 out DDRB,result
Delay:  clr result ;Clear temp counter 1
 ldi temp,$f0;Reset temp counter 2
loop1:  inc result ;Count up temp counter 1
 brne loop1 ;Check if inner loop is finished
 inc  temp ;Count up temp counter 2
 brne  loop1 ;Check if delay is finished

 rcall AD_convert;Start conversion
Wait:  brtc Wait ;Wait until conversion is complete
 out PORTB,result;Write result on port B

 rjmp Delay ;Repeat conversion



Forumer™ is Voted #1 Free Forum Hosting provider
Build your own community today with the largest message board hosting company.