ADC converter in assembly using atmega328p MCU

Go To Last Post
28 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello guys, I need your help to convert ADC in assembler language.
The MCU that I used is atmega328p

;
; ********************************************
; * [Add Project title here]                 *
; * [Add more info on software version here] *
; * (C)20xx by [Add Copyright Info here]     *
; ********************************************
;
; Included header file for target AVR type
.NOLIST
.INCLUDE "m328Pdef.inc" ; Header for ATMEGA328P
.LIST
;
; ============================================
;   H A R D W A R E   I N F O R M A T I O N   
; ============================================
;
; [Add all hardware information here]
;
; ============================================
;      P O R T S   A N D   P I N S 
; ============================================
;
; [Add names for hardware ports and pins here]
; Format: .EQU Controlportout = PORTA
;         .EQU Controlportin = PINA
;         .EQU LedOutputPin = PORTA2
.equ F_CPU = 16000000;
;
; ============================================
;    C O N S T A N T S   T O   C H A N G E 
; ============================================
;
; [Add all constants here that can be subject
;  to change by the user]
; Format: .EQU const = $ABCD
;
; ============================================
;  F I X + D E R I V E D   C O N S T A N T S 
; ============================================
;
; [Add all constants here that are not subject
;  to change or calculated from constants]
; Format: .EQU const = $ABCD
;
; ============================================
;   R E G I S T E R   D E F I N I T I O N S
; ============================================
;
; [Add all register names here, include info on
;  all used registers without specific names]
; Format: .DEF rmp = R16

.DEF rmp = R16 ; Multipurpose register
.DEF tmp = R17
.DEF tmp2 = R18
.DEF reg1 = r20 
.DEF reg2 = r21 
;
; ============================================
;       S R A M   D E F I N I T I O N S
; ============================================
;
.DSEG
.ORG  0X0100
; Format: Label: .BYTE N ; reserve N Bytes from Label:
;
; ============================================
;   R E S E T   A N D   I N T   V E C T O R S
; ============================================
;
.CSEG
.ORG $0000
	jmp Main ; Reset vector
	reti ; Int vector 1
	nop
	reti ; Int vector 2
	nop
	reti ; Int vector 3
	nop
	reti ; Int vector 4
	nop
	reti ; Int vector 5
	nop
	reti ; Int vector 6
	nop
	reti ; Int vector 7
	nop
	reti ; Int vector 8
	nop
	reti ; Int vector 9
	nop
	reti ; Int vector 10
	nop
	reti ; Int vector 11
	nop
	reti ; Int vector 12
	nop
	reti ; Int vector 13
	nop
	reti ; Int vector 14
	nop
	reti ; Int vector 15
	nop
	reti ; Int vector 16
	nop
	reti ; Int vector 17
	nop
	reti ; Int vector 18
	nop
	reti ; Int vector 19
	nop
	reti ; Int vector 20
	nop
	reti ; Int vector 21
	nop
	reti ; Int vector 22
	nop
	reti ; Int vector 23
	nop
	reti ; Int vector 24
	nop
	reti ; Int vector 25
	nop
;
; ============================================
;     I N T E R R U P T   S E R V I C E S
; ============================================
;
; [Add all interrupt service routines here]
;
; ============================================
;     M A I N    P R O G R A M    I N I T
; ============================================
;
Main:
; Init stack
	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 ; Direction Port B
	out DDRB,rmp
	rcall ad ; Call ADC Initialization
; [Add all other init routines here]
	ldi rmp,1<<SE ; enable sleep
	out MCUCR,rmp
	sei
	
	
;
; ============================================
;         P R O G R A M    L O O P
; ============================================
;
Loop:

	
	rcall adcRead
	out PORTB,r18
	rjmp loop ; go back to loop
;
; End of source code
;
ad:   ;ADC Initialization
	ldi rmp, (1<<REFS0)
	sts ADMUX, rmp
	ldi rmp, (1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)
	sts ADCSRA, rmp
ret 

adcRead:
	ldi rmp, (1<<ADSC)
	sts ADCSRA, rmp
loopx: 
	lds rmp,ADCSRA
	sbrs rmp,ADIF
	rjmp loopx	
	ldi rmp, (1<<ADIF)
	sts ADCSRA, rmp
	lds r17,ADCL
	lds r18,ADCH
ret

I would to reading potensiometer in ADC0 and show out the value in PORTB by led on it.
But my code still doesnot return any value of reading.
Anyone can help me to fix the code...?
thanks

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Can a adc conversion wakeup a sleeping MCU ? Regardless, I suggest commenting out the sleep stuff for now, it's just a complication while debugging ( Hmm, you don't do "sleep" cmd. yet so it ought to be okay ). My code is better since you won't have to clear ADIF. Also, when you are clearing ADIF, you're clearing EVERY other bit in ADCSRA ( 1<< ADIF, gets converted to a hex value where the other 7 bits = 0 ) . Same when you set ADSC :

adcRead: 
   lds rmp, ADCSRA    // Read
   ori rmp, (1<<ADSC) // Modify
   sts ADCSRA, rmp    // Write

loopx:
   lds  rmp, ADCSRA
   sbrc rmp,ADSC
   rjmp loopx     
   lds r17,ADCL 
   lds r18,ADCH 
   ret

These are routines you can use in other app., so I suggest something like "adc_init" instead of "ad", since it's descriptive and helps YOU remember what it's doing just by looking at the name in the program.
You're only returning 2 adc bits ( adcH ), and you should return adcL.

Make sure your Vref is connected according to your REF bits and ALL the MCU adc pins are connected like they should be.

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
loopx:
   lds rmp,ADCSRA
   sbrs rmp,ADIF
   rjmp loopx   
   ldi rmp, (1<<ADIF)
   sts ADCSRA, rmp
   lds r17,ADCL
   lds r18,ADCH
ret 

LDS .. Loads one byte from the data space to a register
STS .. Stores one byte from a Register to the data space

ADCL/H, ADCSRA and ADMUX are not data space.

You're using the wrong instructions. Should be In & Out

Last Edited: Fri. Jun 24, 2011 - 03:31 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
ADCL/H and ADCSRA are not data space

ALL of I/O space is part of data space. When a register is > 0x3F, you MUST use STS/LDS and < 0x3F can still use those and related ones OR IN/OUT .

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

indianajones11 wrote:
When a register is > 0x3F, you must use STS/LDS .

Yes .. I already know that.
So, why didn't I put 2 + 2 together ?
Because I'm fxxxn stupid.
My Bad!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

Can a adc conversion wakeup a sleeping MCU ?

Read about "noise cancelling"
Quote:
You're only returning 2 adc bits ( adcH ), and you should return adcL

Eh? Unless OP edited his post (BBS doesn't say he did) then it's clearly returning both ADCL and ADCH in R18:R17? True he's only actually using R18 after he returns so activity is only likely on the bottom 2 bits of PORTB.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
Read about "noise cancelling"
Will do, thanks . By return I meant in the "C" sense of what's getting used after the subroutine call, r18.

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

indianajones11 wrote:
Can a adc conversion wakeup a sleeping MCU ? Regardless, I suggest commenting out the sleep stuff for now, it's just a complication while debugging ( Hmm, you don't do "sleep" cmd. yet so it ought to be okay ). My code is better since you won't have to clear ADIF. Also, when you are clearing ADIF, you're clearing EVERY other bit in ADCSRA ( 1<< ADIF, gets converted to a hex value where the other 7 bits = 0 ) . Same when you set ADSC :

adcRead: 
   lds rmp, ADCSRA    // Read
   ori rmp, (1<<ADSC) // Modify
   sts ADCSRA, rmp    // Write

loopx:
   lds  rmp, ADCSRA
   sbrc rmp,ADSC
   rjmp loopx     
   lds r17,ADCL 
   lds r18,ADCH 
   ret

These are routines you can use in other app., so I suggest something like "adc_init" instead of "ad", since it's descriptive and helps YOU remember what it's doing just by looking at the name in the program.
You're only returning 2 adc bits ( adcH ), and you should return adcL.

Make sure your Vref is connected according to your REF bits and ALL the MCU adc pins are connected like they should be.

It works, thanks to all.
But right now, i want to return 10 bit of ADC value, is there any suggestion?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
But right now, i want to return 10 bit of ADC value
You have it right there in r17 and r18.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Koshchi wrote:
Quote:
But right now, i want to return 10 bit of ADC value
You have it right there in r17 and r18.

Maybe the question being asked is "How do I use all 10 bits that are in r17 and r18?". I know, it is only conjecture.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"void transmigratus(void) {transmigratus();} // recursio infinitus" - larryvc

"It's much more practical to rely on the processing powers of the real debugger, i.e. the one between the keyboard and chair." - JW wek3

"When you arise in the morning think of what a privilege it is to be alive: to breathe, to think, to enjoy, to love." -  Marcus Aurelius

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

larryvc wrote:
Koshchi wrote:
Quote:
But right now, i want to return 10 bit of ADC value
You have it right there in r17 and r18.

Maybe the question being asked is "How do I use all 10 bits that are in r17 and r18?". I know, it is only conjecture.

Yes, u'r right larryvc. Sorry for my bad english.
I wanna use 10 bits in r17 and r18, I means i wanna compare if the the value has rich 1023.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I am definitely not an expert when it comes to assembly code on AVRs, but I think something like this will work:

;compare low and high bytes 

;Do the CP on the two lower half registers then the CPC on the two upper half registers.
 
   ldi r22, 0xFF
   ldi r23, 0x03
   clc
 
   cp r17,r22 
   cpc r18, r23
   brcs compare_exit      ; If less than 1023 branch

I have to give credit to Cliff (clawson) for that routine.

I would like to see other ways of doing this.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"void transmigratus(void) {transmigratus();} // recursio infinitus" - larryvc

"It's much more practical to rely on the processing powers of the real debugger, i.e. the one between the keyboard and chair." - JW wek3

"When you arise in the morning think of what a privilege it is to be alive: to breathe, to think, to enjoy, to love." -  Marcus Aurelius

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
#define   ADC_COMPARE   1023 // Easy to change compare value
.
.
.
subi  r17, low( ADC_COMPARE )
sbci  r18, high( ADC_COMPARE )
brne  compare_exit
// gets here if =

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Nice Indy. That should take care of daffi_gusti's question.

The code I posted was originally for an integer compare where the values were already in two register pairs.

Some day I'll take the time to look over the instruction set more thoroughly. I used to like to program in assembly particularly on the 6502.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"void transmigratus(void) {transmigratus();} // recursio infinitus" - larryvc

"It's much more practical to rely on the processing powers of the real debugger, i.e. the one between the keyboard and chair." - JW wek3

"When you arise in the morning think of what a privilege it is to be alive: to breathe, to think, to enjoy, to love." -  Marcus Aurelius

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

thanks larryvc & indianajones11, it's really helpful.
Thanks for your reply.
I wanna ask some more about returning ADC value to numeric value, in this case is I use lm35z temp sensor.
I wanna print out the the 10 bits value to LCD or Uart COmmunication...
Sorry for many questions, I am very newbie in Assembly. I am just learning.
Thanks

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

larry wrote:
I used to like to program in assembly particularly on the 6502.
C programming spoils us quickly and thoroughly . I need a cigarette every time I do something ( complete dev. cycle ) in C that would take ALOT longer to do in asm. And I DON'T smoke ! :D

daffi_gusti , do you know how to code for an LCD or UART ? If not go to the tutorial forum here and you'll be schooled . Up to you which one you learn first, if you don't already know.

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

indianajones11 wrote:

daffi_gusti , do you know how to code for an LCD or UART ? If not go to the tutorial forum here and you'll be schooled . Up to you which one you learn first, if you don't already know.

Thanks for your suggestion.

I already know the code for LCD and UART, I only need to return value from reading temp sensor in Numeric of 10 bits. Later I will convert the value to Celcius or Fahrenheit.

The only one that I need is returning value in numeric to UART or LCD, how could the register will set in returning them.

:(
:cry:

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think you are asking:

Quote:
How do I take the integer value in the register pair and convert it to an ascii string that will display in a terminal or on an LCD?

Are you a masochist daffi? Do you really want to do this in assembly language?

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"void transmigratus(void) {transmigratus();} // recursio infinitus" - larryvc

"It's much more practical to rely on the processing powers of the real debugger, i.e. the one between the keyboard and chair." - JW wek3

"When you arise in the morning think of what a privilege it is to be alive: to breathe, to think, to enjoy, to love." -  Marcus Aurelius

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Larry's on to something THERE, that's why you ought to know( learn ) C ( see my last post about SMOKING ) . That's option #1 or option# 2: You can start a C pjt. in studio/ Winavr and your main would be JUST like in asm.

So main: // instead of int main(void){ }

/*
all asm code here just like in your post ( but you won't have to write the interrupt table stuff either ) AND you can call C library/ module functions
too !!
So when ready to print you could use itoa() to convert adc_value to a string then just give THAT to comm.
*/

Option #3 is someone has the asm routines to give you. I think in the long run, option #1 is best .

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

larryvc wrote:
I think you are asking:
Quote:
How do I take the integer value in the register pair and convert it to an ascii string that will display in a terminal or on an LCD?

Are you a masochist daffi? Do you really want to do this in assembly language?

yes, That was i asked.
I have to do in Assembly, because this is the requirement from my University.
I am doing thesis right now.

indianajones11 wrote:
Larry's on to something THERE, that's why you ought to know( learn ) C ( see my last post about SMOKING ) . That's option #1 or option# 2: You can start a C pjt. in studio/ Winavr and your main would be JUST like in asm.

So main: // instead of int main(void){ }

/*
all asm code here just like in your post ( but you won't have to write the interrupt table stuff either ) AND you can call C library/ module functions
too !!
So when ready to print you could use itoa() to convert adc_value to a string then just give THAT to comm.
*/

Option #3 is someone has the asm routines to give you. I think in the long run, option #1 is best .

Since this is my requirement to do in assembly, I will choose Option #3, is there any asm routines regarding to this problem?

Thanks, indianajones11 & larryvc for your quick reply.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

But since it's part of a THESIS, you OUGHT to choose option #4, which is do it yourself ! Isn't that what your advisor(s) would say ? Doing either in asm is not too bad and something one at your level HAS to be able to do . I've done it for an LCD on my own AFTER graduating and all I have is a Bachelor's degree. BUT there must be asm versions of BOTH types of comm here and on the 'net . You should be able to at least track them down BY YOURSELF, "Mr. goin' for a Master's/Ph.D" . Come on, stop being so lazy, it's disgraceful .

This is a perfect example of why I need to give less code, when the issue's easy enough, and more hints generally. I wouldn't have given you ANY of what I did if I'd known, so you got OVER, friend !

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

daffi_gusti wrote:

I have to do in Assembly, because this is the requirement from my University.
I am doing thesis right now.
indianajones11 wrote:
Option #3 is someone has the asm routines to give you. I think in the long run, option #1 is best .

Since this is my requirement to do in assembly, I will choose Option #3, is there any asm routines regarding to this problem?

Thanks, indianajones11 & larryvc for your quick reply.


daffi_gusti, I certainly hope your degree is in Business Management and not Engineering or Computer Science. You have learned very well how to delegate to others, that is a great management skill.

To not do the project on your own, when it certainly is your responsibility and is a requirement, is not OK. Asking for help is OK, as long as you are forthcoming about your requirement. You should have mentioned "requirement from my University" in your first post.

We still would have helped you, albeit with guidance as opposed to just providing the answers for you.

Remember to cite the AVRfreaks forum as a resource in your paper.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"void transmigratus(void) {transmigratus();} // recursio infinitus" - larryvc

"It's much more practical to rely on the processing powers of the real debugger, i.e. the one between the keyboard and chair." - JW wek3

"When you arise in the morning think of what a privilege it is to be alive: to breathe, to think, to enjoy, to love." -  Marcus Aurelius

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

thanks larryvc & indianajones11, thanks 4 u'r suggestion.
I'll try to do by my Self.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I suppose that it's not important, but the stack doesn't need to be initialized on the Mega328 since it gets RAMEND loaded into it on reset/power-on.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

USART is MUCH easier than an LCD, I'd suggest going to the tutorial forum and read "abcminiuser" tut. on the uart, he has 2. You could copy what you need IN C to a pjt. and try it. Once it's working, you go to the *.lss file and copy that into your own asm versions . If you get stuck, you'll get help here. 8)

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello, I get stuck on using ADC Interrupt,
This my code,

;
; ********************************************
; * [Add Project title here]                 *
; * [Add more info on software version here] *
; * (C)20xx by [Add Copyright Info here]     *
; ********************************************
;
; Included header file for target AVR type
.NOLIST
.INCLUDE "m328Pdef.inc" ; Header for ATMEGA328P
.LIST
;
; ============================================
;   H A R D W A R E   I N F O R M A T I O N   
; ============================================
;
; [Add all hardware information here]
;
; ============================================
;      P O R T S   A N D   P I N S 
; ============================================
;
; [Add names for hardware ports and pins here]
; Format: .EQU Controlportout = PORTA
;         .EQU Controlportin = PINA
;         .EQU LedOutputPin = PORTA2
.equ BAUD  = 115200; Baudrate
.equ F_CPU = 16000000;
.equ UBRR_VAL   =  (((F_CPU/BAUD)/12) - 5) / 2; Clever runden
.equ second = 16000000 / 5
;
; ============================================
;    C O N S T A N T S   T O   C H A N G E 
; ============================================
;
; [Add all constants here that can be subject
;  to change by the user]
; Format: .EQU const = $ABCD
;
; ============================================
;  F I X + D E R I V E D   C O N S T A N T S 
; ============================================
;
; [Add all constants here that are not subject
;  to change or calculated from constants]
; Format: .EQU const = $ABCD
;
; ============================================
;   R E G I S T E R   D E F I N I T I O N S
; ============================================
;
; [Add all register names here, include info on
;  all used registers without specific names]
; Format: .DEF rmp = R16

.DEF rmp = R16 ; Multipurpose register
.DEF tmp = R17
.DEF tmp2 = R18
.DEF reg1 = r20 
.DEF reg2 = r21 
.def D0 = R17
.def D1 = R18
.def D2 = R19
;
; ============================================
;       S R A M   D E F I N I T I O N S
; ============================================
;
.DSEG
.ORG  0X0100
; Format: Label: .BYTE N ; reserve N Bytes from Label:
;
; ============================================
;   R E S E T   A N D   I N T   V E C T O R S
; ============================================
;
.CSEG
.ORG $0000
	rjmp Main ; Reset vector
.ORG ADCCaddr
	rjmp ADC_interrupt
	
;


; ============================================
;     I N T E R R U P T   S E R V I C E S
; ============================================
;
; [Add all interrupt service routines here]
;

ADC_interrupt:
	push r16
	in r16, SREG
	push r16
	push r17
 
	rcall adcRead
	out PORTB,r17

	pop r17
	pop r16
	out SREG, r16
	pop r16
reti


; ============================================
;     M A I N    P R O G R A M    I N I T
; ============================================
;
Main:
; Init stack
	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 ; Direction Port B
	out DDRB,rmp
	rcall adc_init
	rcall Serial_Init
; [Add all other init routines here]
	ldi rmp,1<<SE ; enable sleep
	out MCUCR,rmp
	sei
	
	
;
; ============================================
;         P R O G R A M    L O O P
; ============================================
;
Loop:

	
	//rcall adcRead
	//out PORTB,r17
	//CPI R17,0x75
	//brge sendValue
	//rcall delay5msec
	rjmp loop ; go back to loop
;
; End of source code
;


sendValue:
	ldi zl,low(2*string) 
    ldi zh,high(2*string) 
	lpm 
load: lpm 
	mov reg2,r0
	cpi reg2,0 
	breq done 
	rcall Serial_Send 
	inc zl 
	rjmp load 
	ldi reg2,0x0A
	rcall Serial_Send
	rjmp loop
ret
done: rjmp loop 
string: .db "Knock..!!", 0x0A,0

;***********************************; 
; Intilize Serial Port ; 
;***********************************; 

Serial_Init: 
	ldi R16,0x00 
	sts UCSR0A,r16 
	ldi R16, (1<<RXEN0)|(1<<TXEN0) 
	sts UCSR0B,r16 
	ldi R16,0x86 
	sts UCSR0C,R16 
	ldi R16,0x00 
	sts UBRR0H,R16 
	ldi R16,25 ;baud rate set 
	sts UBRR0L,R16 ret 


;***********************************; 
; Send a Character To Serial Port ; 
;***********************************; 

Serial_Send: 
	lds reg1,UCSR0A 
	sbrs reg1,UDRE0 
	rjmp Serial_Send 
	sts UDR0,reg2 
	ret 


;*******************************; 
; Read Serial Port Character ; 
;*******************************; 


Serial_Read: 
	lds reg1,UCSR0A 
	sbrs reg1,7 
	rjmp Serial_Read 
	lds reg2,UDR0 
	ret 

adc_init:
	ldi rmp, (1<<REFS0)
	sts ADMUX, rmp
	ldi rmp, (1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)|(1<<ADIE)|(1<<ADATE)
	sts ADCSRA, rmp
ret 

adcRead: 
   lds rmp, ADCSRA    // Read 
   ori rmp, (1<<ADSC) // Modify 
   sts ADCSRA, rmp    // Write 

loopx: 
   lds  rmp, ADCSRA 
   sbrc rmp,ADSC 
   rjmp loopx      
   lds r17,ADCL 
   lds r18,ADCH 
   ret

/*******************************************************************
*Delay Routines, can go all the way to 26 clock cycles if speed is very important
*Must be enough to give ADC enough time to do conversion
*******************************************************************/
wait_38us:
CLR R22
LDI R22, 10

wait_38us_:
DEC R22
BRNE wait_38us_
RET


delaysecond:
	ldi D2, byte3(second)
	ldi D1, high(second)
	ldi D0, low(second)
 	subi D0, 1
	sbci D1, 0
	sbci D2, 0
	brcc pc-3
	ret

delay5msec:		; 80 * 4 * 255 =~ 80000 cycles
	ldi zh, 80
    outerloop:
	ldi zl, 255
    innerloop:
	dec zl
	nop
	brne innerloop
	dec zh
	brne outerloop	
	ret


This code cannot work with ADC Interrupt.
what's wrong with my code?

Anyone, can help me?
thanks.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You don't ever set ADSC to start the first conversion and start the free-running that you selected by ADATE. But if it had started interrupting then you are using a polling routine in the ISR to actually read the thing - which does not make any sense. In free running mode you set ADSC once and it never changes from then on. When a reading is ready ADIF will be set and it then vectors to the ISR. ALL the ISR then has to do is pickup the ADCL/ADCH value.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

done, thanks.
My code like this.

ad_Init:
	cli
	ldi rmp, (1<<REFS0)
	sts ADMUX, rmp
	ldi rmp, (1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)|(1<<ADIE)|(1<<ADATE)
	sts ADCSRA, rmp
	lds rmp, ADCSRA    // Read 
    ori rmp, (1<<ADSC) // Modify 
    sts ADCSRA, rmp    // Write 
ret