I am doing a home automation project with an Ardoino UNO. I need to use a light sensor, however since in assembly there is no analogRead function (), I have to program it. I already read the documentation of AVRand Atmel about the ADC, the MUX and its selection but it is not clear to me how it is programmed or how it works.
I could use an explanation of the following code that was passed to me by a colleague who tells me, that the values of a certain PIN are stored in ADCL and ADCH. My question is if someone would be so kind as to explain me the code and what is happening in the ADC MUX. It's a 328p
.equ F_CPU = 16000000;
.DEF rmp = R16
.DEF tmp = R17
.DEF tmp2 = R18
.DEF reg1 = r20
.DEF reg2 = r21
.EQU ALFA=250
.DSEG
.ORG 0X0100
.CSEG
.ORG $0000
jmp Main
Main:
ldi rmp, HIGH(RAMEND) ; Init MSB stack
out SPH,rmp
ldi rmp, LOW(RAMEND) ; Init LSB stack
out SPL,rmp
; Init Port B
ldi rmp,0xff ; DIRECCION DEL Port B
out DDRB,rmp
rcall ad ; Call ADC Initialization
; [Add all other init routines here]
ldi rmp,1<<SE ;
out MCUCR,rmp
sei
Loop:
rcall adcRead
out PORTB,r18
rjmp loop ; go back to loop
ad:
ldi rmp, (1<<REFS0)
sts ADMUX, rmp
ldi rmp, (1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)
sts ADCSRA, rmp
ret
adcRead:
lds rmp, ADCSRA
ori rmp, (1<<ADSC)
sts ADCSRA, rmp
loopx:
lds rmp, ADCSRA
sbrc rmp,ADSC
rjmp loopx
lds r17,ADCL
lds r18,ADCH
ret
The analog-to-digital converter is started by setting the ADSC
(ADc
Start Conversion) bit in the control register ADCSRA
to 1. This is
done by the lines
lds rmp, ADCSRA
ori rmp, (1<<ADSC)
sts ADCSRA, rmp
The bit stays at 1 as long as the conversion is in progress. Once the conversion is done, the ADC sets the bit to 0 to signal this fact.
The program then tests that bit in order to know when the conversion is
finished. This is the purpose of the loopx
loop:
loopx: ; start of loop
lds rmp, ADCSRA ; load ADCSRA into register rmp
sbrc rmp, ADSC ; conditionally skip next instruction
rjmp loopx ; jump back to the start of the loop
The sbrc
instruction (Skip if Bit in Register is Clear) test the bit 6
(that's the value of ADSC) of register rmp
. If that bit is zero, then
it skips the following rjmp
instruction, thus getting out of the loop.
This way the loop stops when the ADC conversion is completed.
There can be a couple of reasons this doesn't work in your setup. If you
are using an emulator, it could be that it doesn't properly emulate the
operation of the ADC. Then, once you set the ADSC
bit to 1 it stays at
1 forever, which makes the loop infinite.
Another possibility is that you didn't wait long enough. The first conversion after the ADC is switched on takes 3200 CPU cycles with the settings you have. That's 640 iterations of the loop. If you are doing single steps through the debugger, that may be too long for your patience.