Full Version : How to Setup High Precicion ADC (AVR ASM)
avr >>TECHNICAL & HARDWARE >>How to Setup High Precicion ADC (AVR ASM)


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

CODE

;**** A P P L I C A T I O N   N O T E   A V R 4 0 1 ************************
;*
;* Title:  8-bit precision A/D converter
;* Version:  1.03
;* Last Updated: 97.07.17
;* Target:  AT90Sxxxx (All AVR Devices with analog comparator)
;*
;* Support E-mail: avr@atmel.com
;*
;* DESCRIPTION
;* This Application note shows how to perform dual-slope-alike
;* A/D conversion utilizing the on-chip analog comparator and a few
;* external components. Included is a test program that performs
;* conversions in a eternal loop, outputting the result to eight LEDs.
;*
;***************************************************************************

;***** Registers used by mpy9u multiplication routine

.def mc9u =r0;multiplicand used by multiplication routine
.def mp9u =r1;multiplier used by multiplication routine
.def m9uL =r1;result Low byte
.def m9uH =r2;result High byte

;***** Registers used by div17u division routine

.def didL =r1;Dividend
.def didH =r2
.def dresL =r1;Holds the result of the division
.def dresH =r2
.def divL =r3;Divisor
.def divH =r4
.def remL =r5;Reminder variables used by division routine
.def remH =r6

.def TinH =r14;Time to reach input voltage
.def TinL =r15
.def Tref =r16;Time to reach reference voltage
.def TH =r17;Timer variable

.def Vref =r18;Computed Vref

.def temp =r19
.def temp2 =r20


;Port B pins
.equ AIN0 =0
.equ AIN1 =1
.equ Ref1 =2
.equ Ref2 =3
.equ LED =4
.equ T =7

.equ PRESC =2;Timer clocked at CK/8
.equ VrefAddr=0;EEPROM Address holding Vref


.include "1200def.inc"

.cseg
.org 0
 rjmp reset ;Reset handler
 reti  

.org OVF0addr
;** Timer/counter 0 overflow interrupt ******************************
T0_int:  inc TH  ;Increase timer high-byte
 reti


;*** Reset handler **************************************************
reset:  sbi DDRB,LED ;PB4 and
 ser temp ;Port D as output, used to
 out DDRD,temp ;drive LEDs

 ldi temp,(1<<TOIE0);Enable timer interrupt
 out TIMSK,temp

 sei  ;Enable global interrupt

 sbi PORTB,T ;Turn on pull-up on T-pin
 rcall delay

 sbic PINB,T ;If pin not pulled low
 rjmp main ; jump to main
   ;else
calibrate: sbis PINB,T ; wait for pin release
 rjmp calibrate

 cbi PORTB,T ;Turn off pull-up on T-pin
 rcall delay ;Let calibration voltage stabilize

 rcall reference ;Measure Tref
 rcall delay
 rcall input ;Measure Tcal

 clc
 mov mp9u,Tref ;Tref -> multiplier
 ldi temp,128 ;128  -> multiplicand ( = 2.5 volts)
 mov mc9u,temp
 rcall mpy9u ;Tref x 128

 clr divH ;(Tref x 128)
 mov divL,TinL ; -----------
 rcall div17u ;    Tcal

 ldi temp,VrefAddr;Store Vref
 out EEAR,temp
 out EEDR,dresL
 sbi EECR,EEWE

calibrate1: sbic EECR,EEWE
 rjmp calibrate1



;Main program
main:  cbi PORTB,T ;Turn off pull-up on T-pin

 ldi temp,VrefAddr;Read Vref from EEPROM
 out EEAR,temp
 sbi EECR,EERE
 in Vref,EEDR


loop:  rcall reference ;Measure Tref
 rcall delay ;A small delay to let
   ;     the capacitor discharge,
 rcall input ;Measure Tin

 brts error ;If Vin > Vcc
 

calc:  lsr TinH               ;TinH -> C (multiplier)
 mov mp9u,TinL          ;TinL -> multiplier
 mov mc9u,Vref          ;Tref -> multiplicand
 rcall mpy9u            ;Tin x Tref

 clr divH               ;(Tin x Vref)
 mov divL,Tref          ;------------
 rcall div17u           ;    Tref

 tst dresH
 breq write

error:  ldi temp,255 ; Vin = 255
 mov dresL,temp


write:  com dresL ;Show the value on the LEDs
 rcall long_delay
 rcall long_delay
 rcall long_delay

 out PORTD,dresL
 rol dresL
 brcs wr1
 cbi PORTB,LED
 rjmp loop

wr1:  sbi PORTB,LED
 rjmp loop

;*** Subroutine delay ******************************************************
delay:  ldi temp,$FF
d1:  dec temp
 brne d1
 ret


long_delay: ser temp2
ld1:  rcall delay
 dec temp2
 brne ld1
 ret


;*** Subroutine reference **************************************************
;* Measures Tref

reference: sbi DDRB,AIN0 ;Discharge the capacitor

 sbi DDRB,Ref1 ;Turn on Vref
 sbi PORTB,Ref1  
 sbi DDRB,Ref2

 rcall delay ;Let the capacitor discharge completely

 clr TH  ;Reset timer
 out TCNT0,TH

 cbi DDRB,AIN0 ;AIN0 as input

 ldi temp,PRESC ;Start timer
 out TCCR0,temp

 sbi DDRB,T ;Turn on the transistor


ref_wait: sbic ACSR,ACO  ;If Capacitor voltage > reference voltage
 rjmp ref_ok ; conversion conplete
 cpi TH,1 ;Continue if timer overflow
 brlo ref_wait

ref_ok:  in Tref,TCNT0 ;Store Tref

 clr temp ;Stop timer
 out TCCR0,temp

 cbi DDRB,T ;Turn off transistor
 sbi DDRB,AIN0 ;Discharge capacitor

 cbi PORTB,Ref1 ;Turn off Vref
 cbi DDRB,Ref1  
 cbi DDRB,Ref2

 ret




;*** subroutine input **************************************************
;* Measures Tin
;* Returns with the T-flag set if timer overflow (i.e. Vin > Vcc)

input:  cbi DDRB,AIN0 ;Tri-state AIN0

 clt  ;Clear error flag
 clr TH  ;Clear timer
 out TCNT0,TH

 ldi temp,PRESC ;Start timer
 out TCCR0,temp

 sbi DDRB,T ;Turn on transistor

input_wait: sbic ACSR,ACO  ;If Capacitor voltage > Vin
 rjmp input_ok ; charging complete
 cpi TH,2
 brlo input_wait
 set  ;T=1 indicates Vin > Vcc

input_ok: in TinL,TCNT0 ;Store Tin
 mov TinH,TH

input_exit: clr temp ;Stop timer
 out TCCR0,temp

 cbi DDRB,T ;Turn off transistor
 sbi DDRB,AIN0 ;Discharge capacitor

 ret



;********************************************************************
;*
;* This routine divides a 17 bit number (carry:didH:didLL) on
;* a 16 bit number (divH:divL).
;* The result is placed in (dresH:dresL)
;*
;* The carry flag must contain the 17th bit of the divident before
;* the routine is executed.
;*
;* The routine is based on the div16u - 16/16 Bit Unsigned Division
;* routine found in the avr200.asm application note file
;*
;********************************************************************


div17u:  clr remL ;clear remainder Low byte
 clr remH ;clear remainder High byte
 ldi temp,17 ;init loop counter

d17u_1:  rol remL ;shift dividend into remainder
 rol remH
 sub remL,divL;remainder = remainder - divisor
 sbc remH,divH;
 brcc d17u_2 ;if result negative
 add remL,divL;    restore remainder
 adc remH,divH
 clc  ;    clear carry to be shifted into result
 rjmp d17u_3 ;else

d17u_2:  sec
d17u_3:  rol didL ;shift left dividend
 rol didH
 dec temp ;decrement counter
 brne d17u_1 ;if done
 ret  ;    return with value in didL



;***************************************************************************
;*
;* "mpy9u" - 9x8 Bit Unsigned Multiplication
;*
;* This subroutine multiplies the two register variables (carry:mp9u) and mc9u.
;* The result is placed (carry:m8uH:m8uL)
;*  
;* Number of words :11 (return included)
;* Number of cycles :   (return included)
;* Low registers used :3 (mp9u,mc9/m9uL,m9uH)
;* High registers used  :1 (temp)
;*
;* Note: Result Low byte and the multiplier share the same register.
;* This causes the multiplier to be overwritten by the result.
;*
;***************************************************************************

mpy9u:  clr m9uH ;clear result High byte
 ldi temp,9 ;init loop counter
 ror mp9u

m9u_1:  brcc m9u_2 ;if bit 0 of multiplier set
 add m9uH,mc9u ;    add multiplicand to result High byte

m9u_2:  dec temp ;decrement loop counter
 brne m9u_3 ;if not done, loop more
 ret

m9u_3:  ror m9uH ;shift right result High byte
 ror m9uL ;rotate right result L byte and multiplier
 rjmp m9u_1



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