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

时间:2017-04-03 09:21:57

标签: avr atmega atmel analog-digital-converter

如果我需要具体:我问的是ATmega328P芯片。该芯片上的模拟引脚位于PortC下。

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

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

3 个答案:

答案 0 :(得分:4)

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

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

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

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

如果您还有其他问题,我建议您在新问题中显示一些代码,并详细了解analogRead的哪些内容让您感到困惑。

答案 1 :(得分:2)

这是为了在这里偶然发现的未来访客...

作为mentioned by Rev1.0,Arduino C确实让你感觉太容易了。当你写一个简单的陈述analogRead()时,很多复杂的事情正在发生。但是一旦你明白它就不那么复杂了。你一定要读懂ADC。

作为mentioned by David Grayson,您一定要查看analogRead()的源代码。以下是datasheet of ATmega328Pinstruction set manual for ATmega328P,可帮助您了解正在发生的事情。

您可以阅读thisthis,了解如何准确编写代码。

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

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

答案 2 :(得分:0)

与我长期斗争之后,我调查了ATmega 328P的数据表和许多Google冲浪文章,简单实用的代码如下所示。

; 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