mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Anfänger: 80C517A - Temp. Messung in asm


Autor: Thomas Waage (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
ich soll eine Temperaturmessung mit einem PT100 an einem 80517 bei 12 
Mhz realisieren.
Ich benutze den Internen ADC und die Umrechnung des 8bit Wertes in einen 
Temperaturwert ist durch eine Sprungtabelle realisiert. Der geringste zu 
erwartende Wert ist -20 C der einem ADC Wert von 0Dh entspricht.
Die AD-Wandlung soll (ungefähr) alle 2 Sekunden erfolgen. Dies 
realisiere ich in dem ich mit dem Timer0 im Autoreload-Modus (mit 6 
vorgeladen) zwei Variablen auf Null runterzählen lasse, so dass der 
Timer 8000 mal durchlaufen wird, wodurch ich auf ungefähr 2 sekunden 
komme.
Nach der Umrechnung des ADC-Wertes mache ich eine Abfrage nach der größe 
des Wertes, da ich in zwei Variablen den minimal und maximal Wert 
speichern will.

Leider kann ich das Programm erstmal nicht testen und würde gerne 
weitere Meinungen hören, da es mein erstes größeres Programm ist.
;------------------------------------------------------------------------------
$NOMOD51    ; disable predefined 8051 registers
$INCLUDE (REG517A.INC)  
;------------------------------------------------------------------------------
stack    SEGMENT  IDATA
datseg    SEGMENT  DATA
codseg    SEGMENT  CODE

; Stack
; =====
    RSEG  stack
    DS  6

; Daten
; =====
  RSEG  datseg  ; switch to this data segment
  adwert:   ds 1
  count1:   ds 1
  count2:   ds 1
  maxim:   ds 1
  minim:   ds 1
  aktuell: ds 1

;Einsprungadressen
;-----------------
    CSEG  AT  0  ; Sprung zum
    LJMP  main    ; Hauptprogramm (Resetvektor)
    CSEG  AT  0Bh  ; Timer 0 Interruptvektor
    LJMP  isr_timer0
    CSEG  AT   43h  ; ADC-Interruptvektor
    LJMP  isr_adc

; Programmcode
;-------------
          RSEG  codseg    ; switch to this code segment

    USING  0    ; state register_bank used
          ; for the following program code.  

main:
  MOV  SP,#STACK-1  ; assign stack at beginning

; ---- DMAC initialisieren ----------
  call   adc_init    ; zuerst dies


; ---- Timer0 initialisieren --------
  call  timer_init    ; zuletzt Timer starten !!

          ; Interrupt soll in loop-Schleife erfolgen
; ---- Hauptschleife ----------------
loop:    
    jmp  loop

    ; ----- Konvertierungstabelle

tabelle:  db  -20,-20,-19,-19,-19,-18,-18,-18,-18,-17
  db  -17,-17,-16,-16,-16,-15,-15,-15,-14,-14
  db  -14,-13,-13,-13,-12,-12,-12,-11,-11,-11
  db  -11,-10,-10,-10, -9, -9, -9, -8, -8, -8
  db   -7, -7, -7, -6, -6, -6, -5, -5, -5, -4
  db   -4, -4, -4, -3, -3, -3, -2, -2, -2, -1
  db   -1, -1,  0,  0,  0,  1,  1,  1,  2,  2
  db    2,  2,  3,  3,  3,  4,  4,  4,  5,  5
  db    5,  6,  6,  6,  7,  7,  7,  8,  8,  8
  db    9,  9,  9, 10, 10, 10, 11, 11, 11, 11
  db   12, 12, 12, 13, 13, 13, 14, 14, 14, 15
  db   15, 15, 16, 16, 16, 17, 17, 17, 17, 18
  db   18, 18, 19, 19, 19, 20, 20, 20, 21, 21
  db   21, 22, 22, 22, 23, 23, 23, 24, 24, 24
  db   25, 25, 25, 26, 26, 26, 27, 27, 27, 28
  db   28, 28, 29, 29, 29, 30, 30, 30, 30, 99
   db   99, 99, 99

;=======================================
; Unterprogramme
;=======================================

timer_init:

    mov 89h,#2     ;Timer autoreload
  mov TH0,#6
  mov TL0,#6      ;Reloadwert einstellen
  mov count1,#200
  mov count2,#40
  mov maxim,#2
  mov minim,#0
  mov aktuell,#0
  setb ET0     ;Timer0 Interrupt ein
  setb EAL    ;Interrupts ein
  setb TR0     ;Timer ein


    ret

; ---------------------------------------

adc_init:
 
  mov 0DCh,#00H    ;Pin7.0 als eingang, ADCL= 0 
  setb EADC     ;AD Converter Interrupt einschalten
  clr ADM        ;keine kontinuirliche Messung
  clr ADEX    ;external adc aus
    ret

; ---------------------------------------

wandel:
  clr C
  mov a,adwert
  subb a,#0dh
  mov dptr, #tabelle
  movc a,@a+dptr
  mov aktuell,a

  cjne a,maxim,wandeln2
  jmp m2
wandeln2:
  jc m2
  mov maxim,a
m2:
  cjne a,minim,wandeln3
  jmp m3

wandeln3:
  jnc m3
  mov minim,a
m3:
    ret

;========================================
; Interruptroutinen
; =======================================

; Timer-ISR
; =========
isr_timer0:  push  psw
            mov r7,a
      clr TF0
  
      DJNZ count1,m1
      mov count1,#200
  
      DJNZ count2,m1
      ;setb ADEX
      mov count2,#40
      mov ADDATL, #1    ;ADC starten

m1:
    mov a,r7
    pop  psw
    reti                         
; ---------------------------------------

; ADC-ISR
; =======
  
isr_adc:
    push  psw  
        mov r7,a
    clr  iadc      ; IRQ-Flag löschen
    mov  adwert, addath
    call  wandel
      mov a,r7
    pop  psw
    reti

; ---------------------------------------
    END        ; Programmende


Autor: ??? (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Google nach einem Simulator für 8051. Du kannst deinen Code dann 
zeilenweise ausführen und den Ablauf prüfen.

???

Autor: Thomas Waage (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich nutze µVision 4 und kann dort im Debuger auch sehen wie die 
Variablen runtergezählt werden. Aber unter Peripherals kann ich nur die 
Timer auswählen und kann deswegen den ADC nicht testen.

Autor: Ralf (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Aber unter Peripherals kann ich nur die Timer auswählen und kann deswegen
> den ADC nicht testen.
Dann hast du den falschen Controller in den Projektsettings, denn hier:
http://www.keil.com/dd/chip/2969.htm
steht, dass der ADC simuliert werden kann.

"Project -> Select Device for Target...", den passenden µC wählen, neu 
compilieren/linken und gucken, ob der ADC dann im Simulator auftaucht.

Ralf

Autor: Thomas Waage (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stimmt vielen dank, jetzt kann ich auch die ADC kontrollieren und habe 
einen Fehler gefunden.
Die Abfrage nach den minimal und maximal Werten funktioniert noch nicht 
wie gewollt, da die negativen Zahlen als große Zahlen gedeutet werden.

Autor: Yagan Ζ. Dongobar (yagan)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Thomas Waage schrieb:
> Die Abfrage nach den minimal und maximal Werten funktioniert noch nicht
> wie gewollt, da die negativen Zahlen als große Zahlen gedeutet werden.

Thomas,

das kann ja nicht funktionieren, da du beim Vergleich mit maxim und 
minim nur eine 'unsigned'-Auswertung machst (durch jc oder jnc).
Für eine vorzeichenbehaftete Auswertung muss noch das Overflow-Flag 
berücksichtigt werde. Dazu ist aber das cjne nicht geeignet, da es nur 
das Carry-Flag verändert.
Richtig funktioniert es nur bei Verwendung von subb.

Hier ein Beispielunterprogramm dazu (allerdings für 16-Bit-Zahlen):

;   Integers vergleichen über Subtraktion X - Y.

; Parameter:    R0      =   Zeiger auf Quelle X.
;               R1      =   Zeiger auf Quelle Y.
; Resultat:     C       =   Übertrag.
;               OV      =   Überlauf für Zweierkomplement.
;               F0      =   Übertrag Zweierkomplement ( OV^N ).
;               ACC     =   0: X == Y (JZ).
; Register:     B           wird zerstört.

; Folgende Vergleichsmöglichkeiten bestehen:
; Unsigned:     C==0                X >= Y      BHS.
;               C==1                X <  Y      BLO.
;               ACC==0              X == Y      BEQ.
; Signed:       F0==0               X >= Y      BGE.
;               F0==1               X <  Y      BLT.
;               ACC==0              X == Y      BEQ.

IntCmp:
            clr     C
            mov     A,@R0
            subb    A,@R1
            mov     B,A
            inc     R0
            inc     R1
            mov     A,@R0
            subb    A,@R1
            orl     B,A
            mov     ACC.6,C         ; C-Flag retten.
            mov     C,OV            ; OV ^ N bilden.
            jnb     ACC.7,IntCmp1
            cpl     C
IntCmp1:
            mov     F0,C
            mov     C,ACC.6         ; C-Flag restaurieren.
            mov     A,B
            dec     R0
            dec     R1
            ret


Ciao, Yagan

Autor: Ralf (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Die Abfrage nach den minimal und maximal Werten funktioniert noch nicht
> wie gewollt, da die negativen Zahlen als große Zahlen gedeutet werden.
Hm, kleiner Kurs in Zahleninterpretation von Computern/Controllern/etc.:
Die schnellste Methode für einen Computer/Controller, um mit Zahlen zu 
rechnen, ist einerseits die Verwendung von Variablen, deren Größe nicht 
über die Datenbreite des Computer/Controllers hinausgeht, wenn es nicht 
sein muss, das heisst, ein 8-Bit Controller rechnet am schnellsten mit 
8-Bit-Werten, ein 16-Bitter mit 16-Bit-Werten, usw. Computerprozessoren 
unterstützen je nachdem Befehle, um kleinere Datenbreiten effektiv zu 
verarbeiten, beispielsweise 8/16-Bit-Werte auf einem 32/64-Bitter.
Was ebenfalls hinzukommt, ist das Rechnen mit 
vorzeichenlosen/-behafteten Werten. Ist eine Variable in einer 
Hochsprache vorzeichenlos, kann es keinen negativen Wert geben. Ist sie 
vorzeichenbehaftet, signalisiert ein gesetztes höchstwertigstes Bit eine 
negative Zahl.
Das ist der Grund, warum sich die minimalen/maximalen Werte von 
vorzeichenlosen/-behafteten Variablen um jeweils die Hälfte verschieben:
8 Bit:
VL: 0 bis 255 -> 00000000 ... 11111111
VB: -128 bis 127 00000000 ... 01111111 (positiver Bereich)
                 10000000 ... 11111111 (negativer Bereich)
16 Bit:
...
...

Da ich jetzt nicht weiss, WO und WIE du deine Werte anzeigt, heisst das 
für dich, dass du für die Wertberechnung das höchstwertigste Bit für den 
Wert ignorierst, aber wenn das Bit gesetzt ist, eins dazu addierst und 
den negativen Wert hast.

Soweit klar? :)

Ralf

Autor: Thomas Waage (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja hat mir schon viel geholfen, Danke.
Sobald dieser Teil des Programms funktioniert will ich das Programm um 
eine LCD Ausgabe erweitern.
Aber ich werde zunächst versuchen die komplette minimal/maximal Abfrage 
umzustricken auf subtraktions Befehle und das kann bei mir etwas dauern 
:).

Autor: Thomas Waage (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bevor ich das Programm komplett ändere ist mir folgende Idee gekommen:
wandel:
  clr C
  mov a,adwert
  subb a,#0dh
  mov dptr, #tabelle
  movc a,@a+dptr
  mov aktuell,a

  add a, #20
  cjne a,maxim+20,wandeln2
  jmp m2
wandeln2:
  jc m2
  subb a, #20
  mov maxim,a
m2:
  cjne a,minim+20,wandeln3
  jmp m3

wandeln3:
  jnc m3
  subb a, #20
  mov minim,a
m3:
    ret

Durch das Addieren mit 20 komme ich ja aus den negativen Zahlen raus und 
es müsste reichen wenn ich nur das Carry Flag abfrage. Leider 
funktioniert es trotzdem nicht vorallem die minimal abfrage scheint gar 
nichts zu machen.
Sieht jemand den oder die Fehler?

Autor: Kelvin (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Thomas Waage

verwende für deine Temperatur doch Kelvin, ist immer positiv :-)

Autor: Yagan Ζ. Dongobar (yagan)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Thomas,

die Idee mit dem 20-Grad-Offset, damit der Temperaturwert positiv 
bleibt, ist schon in Ordnung.

Nur die Schreibweise:

  cjne a,maxim+20,wandeln2
  cjne a,minim+20,wandeln3

ist nicht das, was du haben willst.
Es wird hier keine 20 zum Wert von maxim bzw. minim addiert, sondern 
zur Adresse. Es ist besser, überall mit einem um 20 erhöhten Wert zu 
arbeiten, und erst bei der Display-Ausgabe wieder 20 zu subtrahieren.

Der Vorschlag von Kelvin ist natürlich genial, hat aber den Nachteil, 
dass der Temperaturwert nicht mehr in ein Byte passt.

Ciao, Yagan

Autor: Thomas Waage (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dir auch nochmal vielen dank.
Die min/max Abfrage habe ich inzwischen gelöst in dem ich jeweils eine 
2. Variable angelegt habe, die den Offset enthält und anschließend mache 
ich die Umwandlung.

Inzwischen arbeite ich an der LCD-Ausgabe, bzw. ich suche nach 
Beispielen für die Initialisierung und Ausgabe bei einem 2x16 Display im 
8 Bit Modus mit HD44780 und vorallem suche ich nach möglichkeiten die 
Umrechnung der teilweise 3 Stelligen (wegen Vorzeichen) Dezimalzahl in 
den Zeichensatz des Displays.
Falls da jemand was hat würde ich mich freuen.

Thomas

Autor: Ralf (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> ich suche nach Beispielen für die Initialisierung und Ausgabe bei einem
> 2x16 Display im 8 Bit Modus mit HD44780
Also da wirst du mindestens hier im Forum zig-tausende Beiträge finden 
:)

> und vorallem suche ich nach möglichkeiten die Umrechnung der teilweise 3
> Stelligen (wegen Vorzeichen) Dezimalzahl in den Zeichensatz des Displays.
Basierend auf dem, was ich weiter oben über die interne Darstellung von 
Zahlen (höchstwertigstes Bit = Vorzeichen) geschrieben habe:

Du nimmst eine Bitvariable, in die du das höchstwertigste Bit kopierst 
und dann aus dem Wert löschst. In Abhängigkeit des Bits gibst du ein 
Leer bzw. Minuszeichen aus.
Ist das Bit gesetzt, inkrementierst du den Wert um eins.
Dann teilst du ihn durch 10, das Ergebnis gibst du als Zehnerstelle aus, 
den Rest als Einer. Falls du auch die Hunderter mit einbeziehen willst, 
musst du halt anfangs erstmal durch 100 teilen.

Ist es das, was du gemeint hast?

Ralf

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.