Forum: Mikrocontroller und Digitale Elektronik Programmierung eines 80C552 mit Assembler


von JoE (Gast)


Lesenswert?

Hallo zusammen,

ich bin neu hier in diesem Forum und benötige Eure Hilfe !!!

Ich habe im Rahmen einer Projektarbeit folgendes vor:

2 verschiedene, analoge Signale (Messwerte), mit einem MC 80C552 A/D zu 
wandeln und einen digitalen Wert dann an eine 2stellige 7- Segment 
Anzeige und das andere digitale Signal an LED oder ähnlichem (als 
Richtungsanzeige) auszugeben.

Dies stelle ich mir wie folgt vor:

Die Analogkanäle 2 und 4 möchte ich für die Eingangssignale wählen.

die Digitalports 2 und 4 möchte ich als Ausgangsports verwenden.

Ich möchte die Abfrage der Eingangssignale, der A/D Wandlung un der 
Ausgabe der Digitalsignal über den internen Taktgeber des MC steuern.

Um die A/D Umsetzzeit zu 'überbrücken', möchte ich jeweils einen 
Interrupt setzten.

Die Programmierung möchte ich mit Assembler durchführen und das Programm 
mit Keil u Vision 3 schreiben.

Nun meine Fragen an das Forum:
Kann mir jemand sagen, ob ich auf dem richtigen Weg bin ?
Wie kann ich das Interruptsystem geziehlt dazu einsetzen.

- Ganz davon ab, ich bin (noch) nicht der MC- Spezialist !!!-

Ich bedanke mich im Vorraus für Eure Hilfe und warte auf Eure Antworten 
!

Grüße,
JoE

von Helmut L. (helmi1)


Lesenswert?

JoE schrieb:
> Die Programmierung möchte ich mit Assembler durchführen und das Programm
> mit Keil u Vision 3 schreiben.

Ich wuerde dir die Programmierung in C empfehlen da du schon den 
Compiler dafuer hast.

von Peter D. (peda)


Lesenswert?

JoE schrieb:
> Um die A/D Umsetzzeit zu 'überbrücken', möchte ich jeweils einen
> Interrupt setzten.

Kann man machen, aber einfacher für nen Anfänger ist Pollen.
Oder warte eine feste Zeit.
Dein Programm hat ja nicht viel zu tun.

Schalte den PC aus, nimm Dir Papier und Bleistift und erstelle einen 
Programmablaufplan.


Peter

von JoE (Gast)


Lesenswert?

Danke Helmut,
leide haben sich unsere Projektlehrer auf diese Prorgammierung 
festgelegt,
so dass ich es halt in Assembler machen muss. :-(

von JoE (Gast)


Lesenswert?

Hallo Peter,
was ist pollen ?

von 12345 (Gast)


Lesenswert?

JoE schrieb:
> Hallo Peter,
> was ist pollen ?
Pollen sind die Dinger die für laufende Nasen und hatschi Nießanfälle 
sorgen, nicht zu verwechseln mit Polen (das sind die die Autos klauen).

SCNR

Guckst du http://de.wikipedia.org/wiki/Polling_%28Informatik%29

von Helmut L. (helmi1)


Lesenswert?

JoE schrieb:
> was ist pollen ?

Das regelmaesige Nachfragen ob sich schon was getan hat und wenn ja dann 
die Aktion ausfuehren.

JoE schrieb:
> leide haben sich unsere Projektlehrer auf diese Prorgammierung
> festgelegt,
> so dass ich es halt in Assembler machen muss. :-(

Naja die ewig gestrigen Lehrer :=)

Kenne ich auch noch von frueher. Du kannst ja versuchen sie zu 
ueberreden.

von Peter D. (peda)


Lesenswert?

JoE schrieb:
> so dass ich es halt in Assembler machen muss. :-(

Ist auch kein Beinbruch, der 8051 Assembler ist ja sehr komfortabel.
Mit dem DIV Befehl kannst Du den Wert in Einer und Zehner zerlegen.
Und mit MOVC A, @A+DPTR die Ziffer in den 7-Segment Code umwandeln.


Peter

von JoE (Gast)


Lesenswert?

Hallo Peda,
danke aber ich glaube ich habe da irgendwo das Denken eingestellt, bzw. 
habe da eine Blockade :-((.

Wie die Befehle sind, weiß ich (glaube ich), aber irgendwie bekomme ich 
kein zusammengehöriges, komplettes Programm zusammen.
ich weiß nicht, wie ich die einzelnen Programme verschachtel.

Grüße, JoE

von Bernd N. (Gast)


Angehängte Dateien:

Lesenswert?

Laaaange her, das sollte gehen. Der AD Wert wird hier auf einem Display 
ausgegeben. Dieses wird über ein Schieberegister angesteuert. Damit 
solltest du dann schon zurechtkommen.

von Toni (Gast)


Lesenswert?

Hallo JoE,

nimm wie schon weiter oben geschrieben ein Blatt Papier
und zeichne einen Programmablaufplan, "wann soll der µC
was machen, was kommt wann als nächstes".
Ist schon mehr als die Hälfte der Arbeit.
Hier interessier noch nicht mal der Typ des µC besonders.

Dann erst die einzelnen Schritte in C oder Assembler, umsetzen,
die "Dienstvorschrift" schreiben.
Wenn C nicht erlaubt, dann halt Assembler, ist bei derr 8051
Family recht komfortabel, auch das "mischen" von C usd ASM
geht mit dem Keil-Tool sehr gut. (kenne den Vorgänger µVision2)

von JoE (Gast)


Angehängte Dateien:

Lesenswert?

Hallo Toni,
Du und die Anderen hier im Forum, Ihr schreibt als wäre Assembler zu 
programmieren das einfachste der Welt !- Für mich irgendwie nicht :-((

Ich habe da mal ein PDF angenängt, welches zeigt, ei ich mir einen 
Ablaufplan vorstelle.
Ws würde mich freuen, wenn Ihr mir weiter helfen könntet.

Grüße,
JoE

von Bernd N. (Gast)


Lesenswert?

Was hast du denn bereits an Code geschrieben ? Kannst du mit dem 
Beispielcode was anfangen, ihn lesen und verstehen ?

von JoE (Gast)


Lesenswert?

Also, habe als Teilprogramme folgendes:

***********Programm 1 = A/D Wandel des ersten Wertes 
***********************
Start 1:  mov ADCON, #00000001  Rücksetzen des Busy- Flag (ADCS = 0)
     mov ADCON, #00001001  Setze Busy- Flag (ADCS = 1), Kanal 1
    mov  r1,ADCH    Digitales Signal an Register 1
                                        ausgeben
************************************************************************ 
****

******** Binär / BCD- Codierung *******************************
mov r1,a    Messwertadresse steht in r1
mov a,@r1               gewählter Messwert steht in a
mov b, #5h          skallieren
div ab
r1 a            Anzeigewert steht als Dualzahl in a
mob b,#10          Codewandeln in BCD
swap a
orl a,b            Anzeigewert steht in BCD in a
mov aus5, a          Ausgabe Anzeigewet

********************************Timer 01*******
Start   :   clr tr0
            clr tf0
-----------------------------------------------
mit_t0      anl tmod, # 11110000 b
      anl tmod, # 11111100 b
      orl tmod, # 00000001 b
      mov tl0,  # 10101111 b
      mov tho,  # 00111100 b
----------------------------------------------------------------
set b      et0
set b      ea0
orl      ip1, # 02 h
orl      ip0, # 02 h
----------------------------------------------------------------
set b      tr0
jmp Start


**************Erstellen Tabelle 
*****************************************
;  TABELLE 

TABELLE:

AJMP stat_00
AJMP stat_08
AJMP stat_10
AJMP stat_18
AJMP stat_20
AJMP stat_28
AJMP stat_30
AJMP stat_38

von Toni (Gast)


Lesenswert?

Fürs erste ist der Ablaufplan schon mal ganz gut.
Einen Fehler habe ich gefunden, die Verzweigung über
"BCD-Zahl Ausgeben".
Bei welcher Bedingung gehts zu "BCD-Zahl Ausgeben",
wann zum Rest des Ablaufs?

Die Teil-Programme sind für mich schon etwas konfus..

Wenn du schon Keils µVision verwendest solltest du mal
in die Beispiele für die 8051 schauen.
Bei der µVision2 (auch in der Demo-Version) sind sehr
viele gute Beispiele dabei.

Beim Programieren sollte man schon wissen was der Befehl
im einzelnen "tut". Besonders bei Assembler.
Ich gebe zu, daß ich auch immer mal wieder nachsehe,
wenn ich mir bei einem Detail nicht ganz sicher bin
(trotz > 25 Jahre Erfahrung).

Nimm ein einfaches Beispiel wie "LED einschalten"
Was passiert das alles hintereinander?
Ruhig mal auch mit Papier und Bleistift "nachspielen"
das erleichtert das Verständnis ungemein.

von Bernd N. (Gast)


Lesenswert?

Also, folgen wir mal deinem Programmablaufplan.

1. Einlesen Analogwert / AD Wandler
1
adc_10bit:  mov adcon,#00001100b    ;select channel p5.4 & start adc
2
read_eoc:   mov a,adcon             ;check end of conversion
3
            jnb acc.4,read_eoc      ;read eoc
4
            mov a,adch              ;get adc result / upper 8 BIT
5
            mov b,#00h              ;clear B
6
            clr c                   ;clear carry
7
            rlc a                   ;move BIT 10 into carry
8
            jnc no_bit_10           ;If there is a BIT 10 then
9
            setb b.1                ;store into B b.1
10
            clr c                   ;clear carry
11
no_bit_10:  rlc a                   ;else move BIT 9 into carry
12
            jnc no_bit_9            ;If there is a bit 9 then
13
            setb b.0                ;store into B b.0
14
            clr c                   ;clear carry
15
no_bit_9:   mov adc_high_byte,b     ;save BIT 9 & 10 in adc highbyte
16
            mov adc_low_byte,a      ;save BIT 8-2 in adc lowbyte
17
            mov a,adcon             ;read adcon BIT 0 & 1
18
            anl a,#11000000b        ;get BIT 0 & 1
19
            rl a                    ;move them to LSB position
20
            rl a                    ;
21
            orl a,adc_low_byte      ;move them together with BIT 8-2
22
            mov adc_low_byte,a      ;save adc lowbyte
23
            ret                     ;

2. Berechnen des ADC Wertes:
1
bin_bcd:    mov r4,#16d             ;16 bit to convert     >24<
2
bin2bcd:    mov r0,#41h             ;get data @ adress 42h,>42h<,40h
3
            mov r3,#02h             ;3 bytes to convert    >03h<
4
            clr c                   ;
5
sort:       mov a,@r0               ;
6
            rlc a                   ;red marked values are
7
            mov @r0,a               ;variables / change them if 
8
            dec r0                  ;you like to make a 16/24/32 bit
9
            djnz r3,sort            ;routine
10
            mov r0,#32h             ;result adress 33h-30h >33h<
11
            mov r3,#03h             ;loop count 8x digits  >04h<
12
mul_x2:     mov a,@r0               ;
13
            addc a,@r0              ;use blue values for a 24 bit
14
            da a                    ;routine
15
            mov @r0,a               ;
16
            dec r0                  ;
17
            djnz r3,mul_x2          ;
18
            djnz r4,bin2bcd         ;
19
20
; sort packed bcd result to seperate memory locations
21
22
            mov r0,#30h             ;load r0 with adress of BCD
23
            mov r1,#40h             ;load r1 with result adress
24
            mov r2,#03h             ;loop count 4x digits  >04h<
25
bcd_to_ram: mov a,@r0               ;get BCD
26
            swap a                  ;low Nibble <-> high Nibble
27
            xchd a,@r1              ;
28
            inc r1                  ; 
29
            swap a                  ;  
30
            xchd a,@r1              ;   
31
            inc r0                  ;    1000 in   " "  45
32
            inc r1                  ;     100 in   " "  44
33
            djnz r2,bcd_to_ram      ;      10 in   " "  43
34
            ret                     ;       1 in   " "  42

Nun steht dein Wandlerergebnis im internen RAM an Speicherstelle 45 - 42 
in einzelne Ziffern aufgedröselt und das in 10 BIT, 4 Ziffern.

Diese gibtst du nun an ein Display aus. Das kann dein 7-Segement oder 
ein beliebeiges anderes sein.

Deine Sprungtabelle kannst du nun dazu nutzen jede einzelne Zahl nach 7 
Segment zu codieren.

Noch ein Tipp, dein PAP sollte eine große Schleife sein und das ist auf 
deinem Bild nicht so, da gibt es einen Abzweig. Willst du den 2ten Kanal 
messen dann gehört das mit in den endless loop.

von Pieter (Gast)


Lesenswert?

moin moin,

>>Du und die Anderen hier im Forum, Ihr schreibt als wäre Assembler zu
>>programmieren das einfachste der Welt !- Für mich irgendwie nicht :-((

@JoE
nicht verzagen, das ist reine Übungs- und Gewohnheitssache.

Meine Fräsensteuerung ist in MacroAssembler geschrieben und das sind so 
ca. 20kB binär. Durch die Macros sind auch 10.000 Zeilen (nicht an einem 
Tag geschrieben) noch gut lesbar. Da das selbe Programm auch in Delphi 
existiert, kann man auch experimentieren.
Du könntest das Programm ja "erstmal" in C schreiben und testen. Als 2. 
Schritt übersetzt DU das Programm in Assembler. Das ist einfacher als 
gedacht. Mit einer solchen Vorlage (in C) geht das wirklich gut.

Mit Gruß
Pieter

von Bernd N. (Gast)


Lesenswert?

Habe mal ne 8 BIT Wandlung gemacht.
1
adc_8bit:   mov adcon,#00001011b        ;select channel p5.3 & start adc
2
read_eoc:   mov a,adcon                 ;check end of conversion
3
            jnb acc.4,read_eoc          ;read eoc
4
            mov a,adch                  ;result into acc

Das sieht dann so aus.

Nun dein Code:
1
            mov ADCON, #00000001  ;Rücksetzen des Busy- Flag (ADCS = 0)
2
            mov ADCON, #00001001  ;Setze Busy- Flag (ADCS = 1), Kanal 1
3
            mov r1,ADCH           ;Digitales Signal an Register 1

Wo fragst du EndOfConversion ab ?

von Bernd N. (Gast)


Lesenswert?

Nun den 8 BIT Wert in Ziffern zerlegen:
1
hex_to_dec:  mov b,#10d      ;convert hex to decimal
2
             div ab          ;divide twice by 10 dec.
3
             mov 42h,b       ;save result in 42h int. ram
4
             mov b,#10d      ;
5
             div ab          ;
6
             mov 40h,a       ;save result in 40h int. ram
7
             mov 41h,b       ;save result in 41h int. ram
8
             ret             ;

Jetzt dein Code:
1
mov r1,ADCH     Digitales Signal an Register 1
2
3
mov r1,a        Messwertadresse steht in r1   <---- hier wird r1 überschrieben!!!
4
mov a,@r1       gewählter Messwert steht in a
5
mov b, #5h      skalieren
6
div ab
7
r1 a            Anzeigewert steht als Dualzahl in a
8
mob b,#10       Codewandeln in BCD
9
swap a
10
orl a,b         Anzeigewert steht in BCD in a
11
mov aus5, a     Ausgabe Anzeigewet

Vertiefe dich nochmal in dein Programm und überlege mal.

von Toni (Gast)


Lesenswert?

Mit Keil's µVision geht C->ASM kinderleicht:

Man muß nur den ASM-Output "anfordern".
Wenn es nicht verboten ist liefere den ASM Code so,
sage es aber auch dazu.

Achtung:
Der entstandene ASM-Code wird sofort als aus
"C" entstanden erkannt, weil
 - Sprungmarken/Labels einfach durchnumeriert sind
   ein Programmierer nimmt "sprechende" Labels

 - der ASM Code machmal sehr seltsam ist, es kann am
   optimieren liegen, muß aber nicht.

Beispiel: Der 8051 kennt jump-Befehle auf Flags,
"jbs label". In ASM kein Problem. Der Compiler
(wenigstens bei dem µVision2) macht unnötigerweise
daraus: mov c,bit
        jc label
Copiert das Bit ins Carry und springt dann.

Will damit sagen, daß man sehr wohl erkennen kann
woher der ASM-Code stammt.

von Jobst M. (jobstens-de)


Angehängte Dateien:

Lesenswert?

JoE, an Deiner Stelle würde ich jetzt warten, bis Bernd N. das Programm 
fertig hat ...

;-)

Folgende Anmerkungen habe ich noch zu dem Ablaufplan - siehe Bild.


Gruß

Jobst

von JoE (Gast)


Lesenswert?

Mahlzeit,

ich habe mich nun entschlossen, die ganze Geschichte über abfragen zu 
machen.
Jetzt stehe ich vor dem Problem, wie teile ich dem AD Wandler mit, dass 
das analoge Signal z.B. 2,5 V  und 1,5 V betragen und er diese mit zwei 
Wertebereichen vergleichen soll.
Das unten stehende Programm ist für zwei analoge eingangswerte gedacht.
Eins möchte ich über P4 an einer 2fache 7 Segmentanzeige anzeigen und 
ein Signal über 2 LEDs.
1
/************* Hauptprogramm*******************************/
2
/************A/D Wandlung Flow*********************************/
3
Flow:    mov adcon, #00001000b  
4
Warte1:  mov a, adcon          
5
    anl a, #00010000b
6
    orl a, #11101011b
7
    cpl a
8
    jnz  Warte1
9
    mov r1, adch      
10
/***********Vergleicher 3er  Wertebereiche***********************************/
11
Start:    clr c          
12
    mov r0, #00h      
13
Next13:  mov  a, r1      
14
    subb a, r0      
15
    jz A33      
16
    mov a, r0    
17
    cjne a, #04d, N1  
18
    sjmp Next23
19
20
N1:  inc r0      
21
    sjmp Next13
22
23
Next23:  mov  a, r1      
24
    subb a, r0      
25
    jz A66        
26
    mov a, r0      
27
    cjne a, #09d, N2  
28
    sjmp Next33
29
          
30
N2:    inc r0        
31
    sjmp Next23
32
33
Next33:  mov a, r1      
34
    subb a, r0      
35
    jz A99        
36
    mov a, r0      
37
    cjne a, #14d, N3  
38
    sjmp Next33
39
          
40
N3:    inc r0        
41
    sjmp Next33
42
43
A33:    mov P4,#00110011b
44
    jmp Richtung
45
46
A66:    mov P4,#01000100b
47
    jmp Richtung
48
49
A99:    mov P4,#11111111b
50
    jmp Richtung
51
52
/************A/D Wandlung Richtung*****************************************/
53
Richtung:  mov adcon, #00001000b  
54
Warte2:  mov a, adcon        
55
    anl a, #00010000b
56
    orl a, #1110100b
57
    cpl a
58
    jnz  Warte2
59
    mov r2, adch
60
61
/***********Vergleicher 2er Wertebereiche********/
62
Start1:    clr c
63
    mov r0, #00h    
64
65
NextLinks:  mov a, r2      
66
    subb a, r0      
67
    jz A_links      
68
    mov a, r0      
69
    cjne a, #04d, N5  
70
    sjmp NextRechts
71
72
N5:    inc r0        
73
    sjmp NextLinks
74
75
NextRechts:  mov  a, r1      
76
    subb a, r0    
77
    jz A_rechts      
78
    mov a, r0      
79
    cjne a, #09d, N6  
80
    sjmp Next33
81
        
82
N6:    inc r0        
83
    sjmp NextLinks        
84
          
85
A_links:  mov P1,#00000001b
86
    jmp pause
87
88
A_rechts:  mov P1,#00001000b
89
    jmp Pause
90
91
/************Timer************/
92
Timer:    clr tr0        
93
    clr  tf0        
94
    mov  tmod, #0001b   
95
    mov  tl0, #10101111b  
96
    mov th0, #00111100b  
97
    setb tr0
98
    ret
99
/************Warte*******************************/
100
Pause:    call timer
101
    call timer
102
    call timer
103
    call timer
104
    jmp Flow
105
106
End

Ich würde mich freuen, möglichst bald von Euch zu hören.

Grüße,
JoE

von Pieter (Gast)


Lesenswert?

moin moin,

>>Jetzt stehe ich vor dem Problem, wie teile ich dem AD Wandler mit, dass
>>das analoge Signal z.B. 2,5 V  und 1,5 V betragen und er diese mit zwei
>>Wertebereichen vergleichen soll.

wo steht den im DB das man dem ADW so etwas mitteilen kann?
Der wandelt bloss. Vergleichen musst Du schon selber.

************Timer************/
Timer:    clr tr0
    clr  tf0
    mov  tmod, #0001b
    mov  tl0, #10101111b
    mov th0, #00111100b
    setb tr0
    ret
/************Warte*******************************/
Pause:    call timer

der Timer wird eventuell gestartet, ich sehe mal nicht nach ob das so 
geht...
...nur der wird nicht warten, denn da fehlt eine Abfrage ob er hat 
fertig.
so wie
  JB RunTimer0, $
ist dann aber auch nur ein Hammer zum Zeit-tot-schlagen.

Überarbeite erstmal Deinen PAP und gehe dann in die Programmierung.


Mit Gruß
Pieter

von Stephan (Gast)


Lesenswert?

> /************Warte*******************************/
> Pause:    call timer
>     call timer
>     call timer
>     call timer
>     jmp Flow


Alternative für Sinnloses Warten:


# Pause#
       Mov b,#4
loop1: call Timer
       djnz b,loop1

spart wenigsten etwas Tipparbeit.

von Jobst M. (jobstens-de)


Lesenswert?

Stephan schrieb:
> spart wenigsten etwas Tipparbeit.

Copy/Paste ist bei Dir noch nicht angekommen? ;-)


Gruß

Jobst

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.