Forum: Mikrocontroller und Digitale Elektronik adc vergleichen


von frank (Gast)


Lesenswert?

ich habe mir das Beispiel von:
http://www.mikrocontroller.net/articles/AVR-Tutorial:_ADC

auf meinen Atmega8 geflasht das haut auch alles hin,
nun wollte ich den adc-Wert vergleichen
mit
;   Ergebnis nach adlow und adhigh kopieren
;   damit die temp Register frei werden

    mov     adlow, temp3
    mov     adhigh, temp4

 ldi temp,high(4883)          ;
 cpi temp3,low(4883)        ;Wert gleich 4883
 cpc temp4,temp
 breq ok             ;ja,
 led_aus
 rjmp no_ok

ok:
led_an

no_ok:



die led leuchtet auch wenn der adc-pin nicht belegt ist


vielleicht könnte mir jemand weiterhelfen

danke
mfg

von Jonathan S. (joni-st) Benutzerseite


Lesenswert?

Hast Du den ADC-Wert noch mit irgendwas multipliziert? Der geht nämlich 
eigentlich nur von 0 - 1023. Oder hast Du das ADLAR-Register gesetzt? 
Den ADC-Pin darfst Du übrigens auch nicht offen lassen, denn dann 
bekommst Du zufällige Spannungen, und nicht 0V. Außerdem kann dein 
ADC-Wert gar keine ungerade Zahl werden, wenn Du ADLAR gesetzt hast. 
Deshalb sollte deine LED garnicht leuchten. Hast Du die LED vielleicht 
falschrum angeschlossen? Und an dem kleinen Codeschnipsel kann man nicht 
viel sehen, poste doch mal deinen ganzen Code...

von frank (Gast)


Lesenswert?

so hier ist der komplette code,

.include "m8def.inc"

.def z0        = r1          ; Zahl für Integer -> ASCII Umwandlung
.def z1        = r2
.def z2        = r3
.def z3        = r4
.def temp1     = r16         ; allgemeines Register, zur kurzfristigen 
Verwendung
.def temp2     = r17         ; Register für 24 Bit Addition, 
niederwertigstes Byte (LSB)
.def temp3     = r18         ; Register für 24 Bit Addition, mittlerers 
Byte
.def temp4     = r19         ; Register für 24 Bit Addition, 
höchstwertigstes Byte (MSB)
.def adlow     = r20         ; Ergebnis vom ADC-Mittelwert der 256 
Messungen
.def adhigh    = r21         ; Ergebnis vom ADC-Mittelwert der 256 
Messungen
.def messungen = r22         ; Schleifenzähler für die Messungen
.def zeichen   = r23         ; Zeichen zur Ausgabe auf den UART
.def temp5     = r24
.def temp6     = r25

; Faktor für Umrechung des ADC-Wertes in Spannung
; = (Referenzspannung / 1024 ) * 100000
; = 5V / 1024 * 1.000.000
.equ Faktor = 4883

.equ F_CPU = 4000000                            ; Systemtakt in Hz
.equ BAUD  = 9600                               ; Baudrate

; Berechnungen
.equ UBRR_VAL   = ((F_CPU+BAUD*8)/(BAUD*16)-1)  ; clever runden
.equ BAUD_REAL  = (F_CPU/(16*(UBRR_VAL+1)))     ; Reale Baudrate
.equ BAUD_ERROR = ((BAUD_REAL*1000)/BAUD-1000)  ; Fehler in Promille

.if ((BAUD_ERROR>10) || (BAUD_ERROR<-10))       ; max. +/-10 Promille 
Fehler
  .error "Systematischer Fehler der Baudrate grösser 1 Prozent und damit 
zu hoch!"
.endif

; RAM
.dseg
.org 0x60
Puffer: .byte 10

; hier geht das Programm los
.cseg
.org 0

    ldi     temp1, LOW(RAMEND)                  ; Stackpointer 
initialisieren
    out     SPL, temp1
    ldi     temp1, HIGH(RAMEND)
    out     SPH, temp1

    sbi DDRB, PB0                  ;Led an Port B0




;UART Initalisierung

    ldi     temp1, LOW(UBRR_VAL)                ; Baudrate einstellen
    out     UBRRL, temp1
    ldi     temp1, HIGH(UBRR_VAL)
    out     UBRRH, temp1

    sbi     UCSRB, TXEN                         ; TX einschalten

; ADC initialisieren: Single Conversion, Vorteiler 128
; Kanal 0, interne Referenzspannung AVCC

    ldi     temp1, (1<<REFS0)
    out     ADMUX, temp1
    ldi     temp1, (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0)
    out     ADCSRA, temp1

Hauptschleife:
    clr     temp1
    clr     temp2
    clr     temp3
    clr     temp4

    ldi     messungen, 0        ; 256 Schleifendurchläufe

; neuen ADC-Wert lesen  (Schleife - 256 mal)

adc_messung:
    sbi     ADCSRA, ADSC        ; den ADC starten

adc_warten:
    sbic    ADCSRA, ADSC        ; wenn der ADC fertig ist, wird dieses 
Bit gelöscht
    rjmp    adc_warten

; ADC einlesen:

    in      adlow, ADCL         ; immer zuerst LOW Byte lesen
    in      adhigh, ADCH        ; danach das mittlerweile gesperrte High 
Byte

; alle 256 ADC-Werte addieren
; dazu wird mit den Registern temp4, temp3 und temp2 ein
; 24-Bit breites Akkumulationsregister gebildet, in dem
; die 10 Bit Werte aus adhigh, adlow aufsummiert werden

    add     temp2, adlow        ; addieren
    adc     temp3, adhigh       ; addieren über Carry
    adc     temp4, temp1        ; addieren über Carry, temp1 enthält 0
    dec     messungen           ; Schleifenzähler MINUS 1
    brne    adc_messung         ; wenn noch keine 256 ADC Werte -> 
nächsten Wert einlesen

; Aus den 256 Werten den Mittelwert berechnen
; Bei 256 Werten ist das ganz einfach: Das niederwertigste Byte
; (im Register temp2) fällt einfach weg
;
; allerdings wird der Wert noch gerundet

    cpi     temp2,128           ; "Kommastelle" kleiner als 128 ?
    brlo    nicht_runden        ; ist kleiner ==> Sprung

; Aufrunden
    subi    temp3, low(-1)      ; addieren von 1
    sbci    temp4, high(-1)     ; addieren des Carry

nicht_runden:

;   Ergebnis nach adlow und adhigh kopieren
;   damit die temp Register frei werden

    mov     adlow, temp3
    mov     adhigh, temp4

 ldi temp,high(4883)          ;
 cpi temp3,low(4883)        ;Wert gleich 4883
 cpc temp4,temp
 breq ok             ;ja,
 cbi PORTB, PB0      ;Led aus
 rjmp no_ok

ok:
sbi PORTB, PB0        ;Led an
no_ok:

; in Spannung umrechnen

    ldi     temp5,low(Faktor)
    ldi     temp6,high(Faktor)
    rcall   mul_16x16

; in ASCII umwandeln

    ldi     XL, low(Puffer)
    ldi     XH, high(Puffer)
    rcall   Int_to_ASCII

;an UART Senden

    ldi     ZL, low(Puffer+3)
    ldi     ZH, high(Puffer+3)
    ldi     temp1, 1
    rcall   sende_zeichen       ; eine Vorkommastelle ausgeben

    ldi     zeichen, ','        ; Komma ausgeben
    rcall   sende_einzelzeichen

    ldi     temp1, 3            ; Drei Nachkommastellen ausgeben
    rcall   sende_zeichen

    ldi     zeichen, 'V'        ; Volt Zeichen ausgeben
    rcall   sende_einzelzeichen

    ldi     zeichen, 10         ; New Line Steuerzeichen
    rcall   sende_einzelzeichen

    ldi     zeichen, 13         ; Carrige Return Steuerzeichen
    rcall   sende_einzelzeichen

    rjmp    Hauptschleife

; Ende des Hauptprogramms

; Unterprogramme

 ; ein Zeichen per UART senden

sende_einzelzeichen:
    sbis    UCSRA,UDRE          ; Warten, bis UDR bereit ist ...
    rjmp    sende_einzelzeichen
    out     UDR, zeichen        ; und Zeichen ausgeben
    ret

; mehrere Zeichen ausgeben, welche durch Z adressiert werden
; Anzahl in temp1

sende_zeichen:
    sbis    UCSRA,UDRE          ; Warten, bis UDR bereit ist ...
    rjmp    sende_zeichen
    ld      zeichen, Z+         ; Zeichen laden
    out     UDR, zeichen        ; und Zeichen ausgeben
    dec     temp1
    brne    sende_zeichen
    ret

; 32 Bit Zahl in ASCII umwandeln
; Zahl liegt in temp1..4
; Ergebnis ist ein 10stelliger ASCII String, welcher im SRAM abgelegt 
wird
; Adressierung über X Pointer
; mehrfache Subtraktion wird als Ersatz für eine Division durchgeführt.

Int_to_ASCII:

    push    ZL                      ; Register sichern
    push    ZH
    push    temp5
    push    temp6

    ldi     ZL,low(Tabelle*2)       ; Zeiger auf Tabelle
    ldi     ZH,high(Tabelle*2)
    ldi     temp5, 10               ; Schleifenzähler

Int_to_ASCII_schleife:
    ldi     temp6, -1+'0'           ; Ziffernzähler zählt direkt im 
ASCII Code
    lpm     z0,Z+                   ; Nächste Zahl laden
    lpm     z1,Z+
    lpm     z2,Z+
    lpm     z3,Z+

Int_to_ASCII_ziffer:
    inc     temp6                   ; Ziffer erhöhen
    sub     temp1, z0               ; Zahl subrahieren
    sbc     temp2, z1               ; 32 Bit
    sbc     temp3, z2
    sbc     temp4, z3
    brge    Int_to_ASCII_ziffer     ; noch kein Unterlauf, nochmal

    add     temp1, z0               ; Unterlauf, eimal wieder addieren
    adc     temp2, z1               ; 32 Bit
    adc     temp3, z2
    adc     temp4, z3
    st      X+,temp6                ; Ziffer speichern
    dec     temp5
    brne    Int_to_ASCII_schleife   ; noch eine Ziffer?

    pop     temp6
    pop     temp5
    pop     ZH
    pop     ZL                      ; Register wieder herstellen
    ret

; Tabelle mit Zahlen für die Berechung der Ziffern
; 1 Milliarde bis 1
Tabelle:
.dd 1000000000, 100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 
10, 1

; 16 Bit Wert in Spannung umrechnen
;
; = 16Bitx16Bit=32 Bit Multiplikation
; = vier 8x8 Bit Multiplikationen
;
; adlow/adhigh * temp5/temp6

mul_16x16:
    push    zeichen
    clr     temp1                   ; 32 Bit Akku löschen
    clr     temp2
    clr     temp3
    clr     temp4
    clr     zeichen                 ; Null, für Carry-Addition

    mul     adlow, temp5            ; erste Multiplikation
    add     temp1, r0               ; und akkumulieren
    adc     temp2, r1

    mul     adhigh, temp5           ; zweite Multiplikation
    add     temp2, r0               ; und gewichtet akkumlieren
    adc     temp3, r1

    mul     adlow, temp6            ; dritte Multiplikation
    add     temp2, r0               ; und gewichtet akkumlieren
    adc     temp3, r1
    adc     temp4, zeichen          ; carry addieren

    mul     adhigh, temp6           ; vierte Multiplikation
    add     temp3, r0               ; und gewichtet akkumlieren
    adc     temp4, r1

    pop     zeichen
    ret

von Human Reader (Gast)


Lesenswert?

frank schrieb:
> so hier ist der komplette code,

Funktioniert das bei dir mit den Anhängen nicht?

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.