www.mikrocontroller.net

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


Autor: JoE (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Helmut Lenzen (helmi1)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: JoE (Gast)
Datum:

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

Autor: JoE (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Peter,
was ist pollen ?

Autor: 12345 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Helmut Lenzen (helmi1)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: JoE (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Bernd N. (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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.

Autor: Toni (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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)

Autor: JoE (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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

Autor: Bernd N. (Gast)
Datum:

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

Autor: JoE (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Toni (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Bernd N. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also, folgen wir mal deinem Programmablaufplan.

1. Einlesen Analogwert / AD Wandler

adc_10bit:  mov adcon,#00001100b    ;select channel p5.4 & start adc
read_eoc:   mov a,adcon             ;check end of conversion
            jnb acc.4,read_eoc      ;read eoc
            mov a,adch              ;get adc result / upper 8 BIT
            mov b,#00h              ;clear B
            clr c                   ;clear carry
            rlc a                   ;move BIT 10 into carry
            jnc no_bit_10           ;If there is a BIT 10 then
            setb b.1                ;store into B b.1
            clr c                   ;clear carry
no_bit_10:  rlc a                   ;else move BIT 9 into carry
            jnc no_bit_9            ;If there is a bit 9 then
            setb b.0                ;store into B b.0
            clr c                   ;clear carry
no_bit_9:   mov adc_high_byte,b     ;save BIT 9 & 10 in adc highbyte
            mov adc_low_byte,a      ;save BIT 8-2 in adc lowbyte
            mov a,adcon             ;read adcon BIT 0 & 1
            anl a,#11000000b        ;get BIT 0 & 1
            rl a                    ;move them to LSB position
            rl a                    ;
            orl a,adc_low_byte      ;move them together with BIT 8-2
            mov adc_low_byte,a      ;save adc lowbyte
            ret                     ;


2. Berechnen des ADC Wertes:

bin_bcd:    mov r4,#16d             ;16 bit to convert     >24<
bin2bcd:    mov r0,#41h             ;get data @ adress 42h,>42h<,40h
            mov r3,#02h             ;3 bytes to convert    >03h<
            clr c                   ;
sort:       mov a,@r0               ;
            rlc a                   ;red marked values are
            mov @r0,a               ;variables / change them if 
            dec r0                  ;you like to make a 16/24/32 bit
            djnz r3,sort            ;routine
            mov r0,#32h             ;result adress 33h-30h >33h<
            mov r3,#03h             ;loop count 8x digits  >04h<
mul_x2:     mov a,@r0               ;
            addc a,@r0              ;use blue values for a 24 bit
            da a                    ;routine
            mov @r0,a               ;
            dec r0                  ;
            djnz r3,mul_x2          ;
            djnz r4,bin2bcd         ;

; sort packed bcd result to seperate memory locations

            mov r0,#30h             ;load r0 with adress of BCD
            mov r1,#40h             ;load r1 with result adress
            mov r2,#03h             ;loop count 4x digits  >04h<
bcd_to_ram: mov a,@r0               ;get BCD
            swap a                  ;low Nibble <-> high Nibble
            xchd a,@r1              ;
            inc r1                  ; 
            swap a                  ;  
            xchd a,@r1              ;   
            inc r0                  ;    1000 in   " "  45
            inc r1                  ;     100 in   " "  44
            djnz r2,bcd_to_ram      ;      10 in   " "  43
            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.

Autor: Pieter (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Bernd N. (Gast)
Datum:

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

Das sieht dann so aus.

Nun dein Code:
            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

Wo fragst du EndOfConversion ab ?

Autor: Bernd N. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nun den 8 BIT Wert in Ziffern zerlegen:
hex_to_dec:  mov b,#10d      ;convert hex to decimal
             div ab          ;divide twice by 10 dec.
             mov 42h,b       ;save result in 42h int. ram
             mov b,#10d      ;
             div ab          ;
             mov 40h,a       ;save result in 40h int. ram
             mov 41h,b       ;save result in 41h int. ram
             ret             ;

Jetzt dein Code:
mov r1,ADCH     Digitales Signal an Register 1

mov r1,a        Messwertadresse steht in r1   <---- hier wird r1 überschrieben!!!
mov a,@r1       gewählter Messwert steht in a
mov b, #5h      skalieren
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

Vertiefe dich nochmal in dein Programm und überlege mal.

Autor: Toni (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Jobst M. (jobstens-de)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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

Autor: JoE (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.
/************* Hauptprogramm*******************************/
/************A/D Wandlung Flow*********************************/
Flow:    mov adcon, #00001000b  
Warte1:  mov a, adcon          
    anl a, #00010000b
    orl a, #11101011b
    cpl a
    jnz  Warte1
    mov r1, adch      
/***********Vergleicher 3er  Wertebereiche***********************************/
Start:    clr c          
    mov r0, #00h      
Next13:  mov  a, r1      
    subb a, r0      
    jz A33      
    mov a, r0    
    cjne a, #04d, N1  
    sjmp Next23

N1:  inc r0      
    sjmp Next13

Next23:  mov  a, r1      
    subb a, r0      
    jz A66        
    mov a, r0      
    cjne a, #09d, N2  
    sjmp Next33
          
N2:    inc r0        
    sjmp Next23

Next33:  mov a, r1      
    subb a, r0      
    jz A99        
    mov a, r0      
    cjne a, #14d, N3  
    sjmp Next33
          
N3:    inc r0        
    sjmp Next33

A33:    mov P4,#00110011b
    jmp Richtung

A66:    mov P4,#01000100b
    jmp Richtung

A99:    mov P4,#11111111b
    jmp Richtung

/************A/D Wandlung Richtung*****************************************/
Richtung:  mov adcon, #00001000b  
Warte2:  mov a, adcon        
    anl a, #00010000b
    orl a, #1110100b
    cpl a
    jnz  Warte2
    mov r2, adch

/***********Vergleicher 2er Wertebereiche********/
Start1:    clr c
    mov r0, #00h    

NextLinks:  mov a, r2      
    subb a, r0      
    jz A_links      
    mov a, r0      
    cjne a, #04d, N5  
    sjmp NextRechts

N5:    inc r0        
    sjmp NextLinks

NextRechts:  mov  a, r1      
    subb a, r0    
    jz A_rechts      
    mov a, r0      
    cjne a, #09d, N6  
    sjmp Next33
        
N6:    inc r0        
    sjmp NextLinks        
          
A_links:  mov P1,#00000001b
    jmp pause

A_rechts:  mov P1,#00001000b
    jmp Pause

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

End

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

Grüße,
JoE

Autor: Pieter (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Stephan (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Jobst M. (jobstens-de)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stephan schrieb:
> spart wenigsten etwas Tipparbeit.

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


Gruß

Jobst

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.