如何在AVR汇编语言中做analogRead()?



如果我需要具体一点:我问的是ATmega328P芯片。模拟引脚在此芯片上PortC

我了解到digitalWrite可以使用out来完成,digitalRead可以使用in来完成。
但是我该怎么做analogRead呢?请解释一下。我是新手。

额外:如果你也展示analogWrite会很有帮助(在PWM的意义上)。

您可以从 Arduino 环境中读取analogRead的源代码:

https://github.com/arduino/ArduinoCore-avr/blob/master/cores/arduino/wiring_analog.c

重要的是找到它从特殊函数寄存器 (SFR) (SFR) (如 ADMUX) 读取或写入的所有位置,然后确保在汇编代码中执行相同的操作。

您还应该查看 ATmega328P 数据表,其中定义了所有这些 SFR,以此来仔细检查您是否在做正确的事情。

如果你有进一步的麻烦,我建议你问一个新问题,你显示一些代码,并具体说明analogRead的哪个部分让你感到困惑。

这是给在这里偶然发现的未来游客的......


正如Rev1.0所提到的,Arduino C确实让你的事情变得太容易了。当你写一个简单的语句时,引擎盖下会发生很多复杂的事情analogRead().但一旦你理解了它,它就没有那么复杂了。您绝对应该阅读ADC。

正如大卫格雷森所提到的,你绝对应该看看analogRead()的源代码。以下是 ATmega328P 的数据表和 ATmega328P 的指令集手册,可帮助您了解正在发生的事情。

您可以阅读此内容和本文以了解有关如何准确编写代码的一些想法。


现在,这是我为项目中的用例想出的
粗体字是为了告诉您,这段代码不是为一般用例编写的。复制粘贴这很可能不起作用。
你在这篇文章中看到了很多链接吗?阅读所有这些。下面仅供参考,以防您遇到困难,这可能会有所帮助。

adcInit:
ldi r16, 0b01100000   ; Voltage Reference: AVcc with external capacitor at AREF pin
sts ADMUX, r16        ; Enable ADC Left Adjust Result
; Analog Channel: ADC0
ldi r16, 0b10000101   ; Enable ADC
sts ADCSRA, r16       ; ADC Prescaling Factor: 32
ret
adcRead:
ldi r16, 0b01000000   ; Set ADSC flag to Trigger ADC Conversion process
lds r17, ADCSRA       ;
or  r17, r16          ;
sts  ADCSRA, r17      ;
ret
adcWait:
lds r17, ADCSRA       ; Observe the ADIF flag, it gets set by hardware when ADC conversion completes
sbrs r17, 4           ;
jmp adcWait           ; Keep checking until the flag is set by hardware
ldi r16, 0b00010000   ; Set the flag again to signal 'ready-to-be-cleared' by hardware
lds r17, ADCSRA       ;
or  r17, r16          ;
sts  ADCSRA, r17      ;
ret

它是这样用的:

call adcInit
mainLoop:
call adcRead
call adcWait
lds r18, ADCL  ; Must read ADCL first, and ADCH after that
lds r19, ADCH

经过长时间的挣扎,我调查了ATmega 328P的数据表和许多谷歌冲浪文章,简单可行的代码如下。

; UNO_asmADCapp.asm
; revised by bsliao: 2020/5/12 下午 03:39:20, TEST OK 2020/05/13, 11:33
; Reference: 
; https://stackoverflow.com/questions/38972805/
; [1] how-to-code-an-adc-for-an-atmega328p-in-assembly
;    Author : Dario, Created: 8/14/2016 7:34:43 AM
; [2] https://robotics.ee.uwa.edu.au/courses/des/labprep/
; LabPrep%205%20-%20Timers%20and%20ADC%20in%20ATMEL.pdf
; [3] https://www.avrfreaks.net/forum/adc-converter-assembly-using-atmega328p-mcu
;  AD0 --- uno A0
;  value ADCH (b9 b8) ADCL (b7- b0) <Internal> --- PB1(uno d9) PB0 (d8), PD7-PD0 (uno D7 -D0)
#define  F_CPU 16000000UL
.def  temp =r16
; Replace with your application code
.include "./m328Pdef.inc"
.org 0x000
rjmp start
;   .org 0x002A
;   rjmp ADC_conversion_complete_Handler
start:
eor r1, r1
out SREG, r1
ldi temp, HIGH(RAMEND)
out SPH, r16
ldi temp, LOW(RAMEND)
out SPL, r16
setup:
ldi temp, 0xFF ; set r16 = 1111 1111
out ddrb, temp ; set all d pins as output
out ddrd, temp ; set all b pins as output
configADC0:
;------initialize ADC0 -------  Set ADMUX and ADCSRA: 
;REF1 REFS0 ALLAR - (MUX3 MUX2 MUX1 MUX0 )=(0000)  
;Aref=5.0 V is used, default right-adjust result,  analog in at AIN0 (ADC0)  
LDI temp, 0x00
STS ADMUX, temp
;ADcENable, (ADPS2 ADPS1 ADPS0 )=(000) : division factor=128 16Mhz/128: ADC0 is applied.
LDI temp, (1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)
STS ADCSRA, temp 
andi temp, 0b11011111 
STS ADCSRA, temp 
; the first conversion  
LDS temp,ADCSRA
ori temp, (1<<ADSC);
STS ADCSRA, temp
LOOP:
; start the next single conversion on ADCn, here n=0
LDS temp,ADCSRA
ori temp, (1<<ADSC);
STS ADCSRA, temp
adc_read_loop:
// while (bit_is_set(ADCSRA, ADSC));
lds temp,ADCSRA
sbrc temp,ADSC   ;after ADC0 conversion over, the bit ADSC in the ADCSRA is set to zero and the bit ADIF is set to one.
rjmp adc_read_loop
read_ADC_value: 
lds r24,ADCL
lds r25,ADCH 
display_ADC_value:
andi r25, 0x03
out PORTB, r25    ; LEDs active high, PORTB most significant byte
com r24           ; LEDs active low
out PORTD, r24    ; PORTD less significant byte
call one_sec_delay
rjmp LOOP
one_sec_delay:
ldi     r20, 20
ldi     r21, 255
ldi     r22, 255
delay:  dec     r22
brne    delay
dec     r21
brne    delay
dec     r20
brne    delay
ret

相关内容

  • 没有找到相关文章

最新更新