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


von Thomas Waage (Gast)


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.
1
;------------------------------------------------------------------------------
2
$NOMOD51    ; disable predefined 8051 registers
3
$INCLUDE (REG517A.INC)  
4
;------------------------------------------------------------------------------
5
stack    SEGMENT  IDATA
6
datseg    SEGMENT  DATA
7
codseg    SEGMENT  CODE
8
9
; Stack
10
; =====
11
    RSEG  stack
12
    DS  6
13
14
; Daten
15
; =====
16
  RSEG  datseg  ; switch to this data segment
17
  adwert:   ds 1
18
  count1:   ds 1
19
  count2:   ds 1
20
  maxim:   ds 1
21
  minim:   ds 1
22
  aktuell: ds 1
23
24
;Einsprungadressen
25
;-----------------
26
    CSEG  AT  0  ; Sprung zum
27
    LJMP  main    ; Hauptprogramm (Resetvektor)
28
    CSEG  AT  0Bh  ; Timer 0 Interruptvektor
29
    LJMP  isr_timer0
30
    CSEG  AT   43h  ; ADC-Interruptvektor
31
    LJMP  isr_adc
32
33
; Programmcode
34
;-------------
35
          RSEG  codseg    ; switch to this code segment
36
37
    USING  0    ; state register_bank used
38
          ; for the following program code.  
39
40
main:
41
  MOV  SP,#STACK-1  ; assign stack at beginning
42
43
; ---- DMAC initialisieren ----------
44
  call   adc_init    ; zuerst dies
45
46
47
; ---- Timer0 initialisieren --------
48
  call  timer_init    ; zuletzt Timer starten !!
49
50
          ; Interrupt soll in loop-Schleife erfolgen
51
; ---- Hauptschleife ----------------
52
loop:    
53
    jmp  loop
54
55
    ; ----- Konvertierungstabelle
56
57
tabelle:  db  -20,-20,-19,-19,-19,-18,-18,-18,-18,-17
58
  db  -17,-17,-16,-16,-16,-15,-15,-15,-14,-14
59
  db  -14,-13,-13,-13,-12,-12,-12,-11,-11,-11
60
  db  -11,-10,-10,-10, -9, -9, -9, -8, -8, -8
61
  db   -7, -7, -7, -6, -6, -6, -5, -5, -5, -4
62
  db   -4, -4, -4, -3, -3, -3, -2, -2, -2, -1
63
  db   -1, -1,  0,  0,  0,  1,  1,  1,  2,  2
64
  db    2,  2,  3,  3,  3,  4,  4,  4,  5,  5
65
  db    5,  6,  6,  6,  7,  7,  7,  8,  8,  8
66
  db    9,  9,  9, 10, 10, 10, 11, 11, 11, 11
67
  db   12, 12, 12, 13, 13, 13, 14, 14, 14, 15
68
  db   15, 15, 16, 16, 16, 17, 17, 17, 17, 18
69
  db   18, 18, 19, 19, 19, 20, 20, 20, 21, 21
70
  db   21, 22, 22, 22, 23, 23, 23, 24, 24, 24
71
  db   25, 25, 25, 26, 26, 26, 27, 27, 27, 28
72
  db   28, 28, 29, 29, 29, 30, 30, 30, 30, 99
73
   db   99, 99, 99
74
75
;=======================================
76
; Unterprogramme
77
;=======================================
78
79
timer_init:
80
81
    mov 89h,#2     ;Timer autoreload
82
  mov TH0,#6
83
  mov TL0,#6      ;Reloadwert einstellen
84
  mov count1,#200
85
  mov count2,#40
86
  mov maxim,#2
87
  mov minim,#0
88
  mov aktuell,#0
89
  setb ET0     ;Timer0 Interrupt ein
90
  setb EAL    ;Interrupts ein
91
  setb TR0     ;Timer ein
92
93
94
    ret
95
96
; ---------------------------------------
97
98
adc_init:
99
 
100
  mov 0DCh,#00H    ;Pin7.0 als eingang, ADCL= 0 
101
  setb EADC     ;AD Converter Interrupt einschalten
102
  clr ADM        ;keine kontinuirliche Messung
103
  clr ADEX    ;external adc aus
104
    ret
105
106
; ---------------------------------------
107
108
wandel:
109
  clr C
110
  mov a,adwert
111
  subb a,#0dh
112
  mov dptr, #tabelle
113
  movc a,@a+dptr
114
  mov aktuell,a
115
116
  cjne a,maxim,wandeln2
117
  jmp m2
118
wandeln2:
119
  jc m2
120
  mov maxim,a
121
m2:
122
  cjne a,minim,wandeln3
123
  jmp m3
124
125
wandeln3:
126
  jnc m3
127
  mov minim,a
128
m3:
129
    ret
130
131
;========================================
132
; Interruptroutinen
133
; =======================================
134
135
; Timer-ISR
136
; =========
137
isr_timer0:  push  psw
138
            mov r7,a
139
      clr TF0
140
  
141
      DJNZ count1,m1
142
      mov count1,#200
143
  
144
      DJNZ count2,m1
145
      ;setb ADEX
146
      mov count2,#40
147
      mov ADDATL, #1    ;ADC starten
148
149
m1:
150
    mov a,r7
151
    pop  psw
152
    reti                         
153
; ---------------------------------------
154
155
; ADC-ISR
156
; =======
157
  
158
isr_adc:
159
    push  psw  
160
        mov r7,a
161
    clr  iadc      ; IRQ-Flag löschen
162
    mov  adwert, addath
163
    call  wandel
164
      mov a,r7
165
    pop  psw
166
    reti
167
168
; ---------------------------------------
169
    END        ; Programmende

von ??? (Gast)


Lesenswert?

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

???

von Thomas Waage (Gast)


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.

von Ralf (Gast)


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

von Thomas Waage (Gast)


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.

von Yagan Ζ. D. (yagan)


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

von Ralf (Gast)


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

von Thomas Waage (Gast)


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 
:).

von Thomas Waage (Gast)


Lesenswert?

Bevor ich das Programm komplett ändere ist mir folgende Idee gekommen:
1
wandel:
2
  clr C
3
  mov a,adwert
4
  subb a,#0dh
5
  mov dptr, #tabelle
6
  movc a,@a+dptr
7
  mov aktuell,a
8
9
  add a, #20
10
  cjne a,maxim+20,wandeln2
11
  jmp m2
12
wandeln2:
13
  jc m2
14
  subb a, #20
15
  mov maxim,a
16
m2:
17
  cjne a,minim+20,wandeln3
18
  jmp m3
19
20
wandeln3:
21
  jnc m3
22
  subb a, #20
23
  mov minim,a
24
m3:
25
    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?

von Kelvin (Gast)


Lesenswert?

@ Thomas Waage

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

von Yagan Ζ. D. (yagan)


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

von Thomas Waage (Gast)


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

von Ralf (Gast)


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

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.