Forum: Mikrocontroller und Digitale Elektronik Arduino Assembler Daten seriell einlesen, schreiben


von Werner J. (werner_j997)


Lesenswert?

Hallo zusammen,
Ich muss die CPU-platine einer uralten SPS ersetzen.
Die I/O-Platinen werden über einen Bus angeschlossen.
Als CPU nutze ich einen Arduino-Mega, der in Assembler programmiert 
wird. Den Logikteil des Programms habe ich fertig.
Aber bei der I/O Anbindung habe ich einen Knoten im Hirn.

Ich lege eine Adresse auf den Bus und erhalte den Zustand eines Eingangs 
auf einer Portleitung. Dann wird der Bus incrementiert und das nächste 
Bit abgefragt. Ausgabe dito.

Wie kriege ich die einzelnen Bits jetzt in der richtigen Reihenfolge 
byteweise abgespeichert?

Kann mir da jemand einen Tip geben? Wie gesagt, soll in Assembler sein.

Bin für jeden Rat dankbar.

Werner

von Sebastian S. (amateur)


Lesenswert?

>Den Logikteil des Programms habe ich fertig.

Bist Du Dir da sicher?

Im Übrigen: Die ATMegas haben's nicht so mit Speicher (RAM). Da ist sehr 
schnell Schluss.

von Karl M............................................ (Gast)


Lesenswert?

Werner,

warum nimmst Du keine Hochsprache ?

Ohne Schaltplan wird man dir, bzgl. der Hardware, nicht 100% antworten 
können!

Und ohne Programm, Ablaufsteuerung etc. entsprechend auch nichts 
korrigieren.

von _Gast (Gast)


Lesenswert?

Hm,

ist den das ganz in irgendeiner Form sicherheitsrelavant?

Wenn ja, würde ich da ganz schnell die Finger davon lassen...


mfg
Gast

von Norbert T. (atos)


Lesenswert?

Bin mir nicht ganz sicher, ob ich dich richtig verstanden habe, d. h. du 
bekommst an einem Port-Pin, z. B PA0 ein Bit geliefert, z. B. PA0=1, 
dann kommt PA0=0, dann PA0=1 usw. ...und du möchtest die einzelnen Bits 
in einem Byte  zusammenfassen(?) Eigentlich ganz trivial, vor allem in 
Asm: Portzustand in ein Register einlesen, überprüfen ob das DatenBit 0 
oder 1 ist, dieses ins Carry reinschreiben, dann das Carry ins 
Byteregister reinschieben. Dann das ganze noch sieben mal wiederholen, 
so dass alle Bits nacheinander ins Byteregister reingeschoben wurden. 
Beispiel:
1
;********************************************************************
2
;******* 8 Bits zu 1 Byte *******************************************
3
;********************************************************************
4
;***** Es wird angenommen, dass die Daten am Port A ankommen, *******
5
;***** am Pin PA0; der Zustand des Ports A wird nach DatenBit *******
6
;***** eingelesen; nur niedrigwerteste Bit des Port A ist hier ******
7
;***** von Bedeutung => PA0 kann nur 0 oder 1 annehmen, Pin 1 *******
8
;***** bis Pin 7 werden nicht beachtet; der Zustand von PA0 *********
9
;***** wird von links nach rechts ins DatenByte  über das ************
10
;***** Carry Flag eingeschoben **************************************
11
;********************************************************************
12
8bit_1byte:
13
    clr    DatenByte
14
    ldi    tmp1,0x08        ;Zähler für 8 Bits
15
loop1:lds    DatenBit,PortA_In    ;Port A wird eingelesen
16
    sbrc  DatenBit,0        ;Prüfen ob PA0 1 oder 0 => Wenn PA0=0 nächstes Kommando überspringen
17
    rjmp  loop3          ;PA0=1 => daher zu sprinegn
18
    clc                ;Datenbit=0, dieses Bit ins Carry schreiben => Carry Flag löschen
19
loop2:ror    DatenByte        ;Carry ins Datenbyte reinschreiben (verschieben nach rechts)
20
    dec    tmp1          ;Zähler um 1 verkleinern
21
    brne  loop1          ;Nächstes Bit reinholen
22
    ret                ;...und Zurück zum Hauptprogramm
23
loop3:sec                ;Datenbit=1, dieses Bit ins Carry schreiben => Carry Flag setzen
24
    rjmp  loop2          ;
Code ist für XMEGA, muss also füe MEGA angepasst werden, d. h. Einlesen 
des Port A.
BTW: Was für brillante Antworten hast du bis jetzt bekommen...

von Wolfgang (Gast)


Lesenswert?

Werner J. schrieb:
> Wie kriege ich die einzelnen Bits jetzt in der richtigen Reihenfolge
> byteweise abgespeichert?

Erstmal musst du die Bits zu einem Byte zusammen bauen. Zu Zeiten vom 
6502 hat man dafür gesorgt, dass im Carry der Eingangszustand war und 
dann mit Rotate Right oder Left dieses Bit in den Akku rein geschoben. 
Falls dein Arduino das nicht kann, helfen natürlich Bitmanipulationen, 
um direkt das Bit durch maskieren zu löschen oder durch or zu setzen.

von Norbert T. (atos)


Lesenswert?

Ja, das macht immer noch so, sowohl beim 6502 als auch beim AVR :) 
Hochsprache... dass ich nicht lache ;)
Ich müsste eigentlich mal wieder den Brotkasten rausholen :P

von Thomas F. (igel)


Lesenswert?

Norbert hat ja schon eine Lösung präsentiert.

Wenn das Input-Bit an Bit 0 oder 7 steht geht auch noch:

Per ROL oder ROR das eingelesene Bit erst mal ins Carry schieben.
Gleich danach nochmal mit ROL oder ROR das Bit dann in das Datenregister 
schieben.

von spess53 (Gast)


Lesenswert?

Hi

>Wenn das Input-Bit an Bit 0 oder 7 steht geht auch noch:

Mit bld/bst kann man beliebige Bits von beliebigen Registern hin und her 
schieben.

MfG Spess

von Kaj (Gast)


Lesenswert?

Sebastian S. schrieb:
> Die ATMegas haben's nicht so mit Speicher (RAM). Da ist sehr
> schnell Schluss.
mega2560 ->  8k RAM
mega1284 -> 16k RAM
Nur mal so...

Verallgemeinerte Aussagen sind allgemein scheisse.

von peter (Gast)


Lesenswert?

Arudino DUE 512KB Flash....96KB SRAM.
SRAM mit Arduino-IDE durchgehend nutzbar ohne eine 64KB-Grenze für den 
Nutzer als Hürde.

von Peter D. (peda)


Lesenswert?

Werner J. schrieb:
> Ich lege eine Adresse auf den Bus und erhalte den Zustand eines Eingangs
> auf einer Portleitung. Dann wird der Bus incrementiert und das nächste
> Bit abgefragt. Ausgabe dito.

Du hast wirklich einen Bus mit z.B. 16 Adreßleitungen und nur einer 
Datenleitung?
Wer kommt denn auf solche abstrusen Ideen?

Zeig man den Schaltpan der IO-Anbindung. Dann müssen wir nicht mehr 
sinnlos rumrätseln.

von Thomas F. (igel)


Lesenswert?

Wozu braucht man 8k, 16k oder 96k RAM wenn man eine handvoll Bits 
einlesen will?

Wo bleibt der Vorschlag doch gleich einen RPi2 zu nehmen?

von Werner J. (werner_j997)


Lesenswert?

Vielen Dank an Alle die sinnvolle Antworten gepostet haben, allen voran 
Norbert.
Ist ja wirklich trivial (wie gesagt: Knoten im Hirn).
Zu: Speicher zu klein
Ich muss ja nur die 128 Ein- und 96 Ausgänge und ca. 100 Merkerbits als 
Prozessabbild im RAM halten. Das schafft selbst ein Arduino One. Den 
Mega brauche ich nur wegen des größeren Flash (für den Logikteil brauche 
ich ca. 10.000 Zeilen Assembler-Code).

@Peter: Ja, ist ein 13Bit-Bus mit einer Datenleitung. Es handelt sich um 
eine Siemenssteuerung von 1980, steuert eine NC-Drehmaschine.

@Karl: Keine Hochsprache wegen der Geschwindigkeit. Damit schaffe ich 
den Durchlauf des Logikteils in < 10ms.

von Peter D. (peda)


Lesenswert?

Werner J. schrieb:
> Keine Hochsprache wegen der Geschwindigkeit. Damit schaffe ich
> den Durchlauf des Logikteils in < 10ms.

Du hast falsche Vorstellungen von Hochsprachen, 10ms sind eine riesige 
Zeit.

Norbert T. schrieb:
> 8bit_1byte:
>     clr    DatenByte
>     ldi    tmp1,0x08        ;Zähler für 8 Bits
> loop1:lds    DatenBit,PortA_In    ;Port A wird eingelesen
>     sbrc  DatenBit,0        ;Prüfen ob PA0 1 oder 0 => Wenn PA0=0
> nächstes Kommando überspringen
>     rjmp  loop3          ;PA0=1 => daher zu sprinegn
>     clc                ;Datenbit=0, dieses Bit ins Carry schreiben =>
> Carry Flag löschen
> loop2:ror    DatenByte        ;Carry ins Datenbyte reinschreiben
> (verschieben nach rechts)
>     dec    tmp1          ;Zähler um 1 verkleinern
>     brne  loop1          ;Nächstes Bit reinholen
>     ret                ;...und Zurück zum Hauptprogramm
> loop3:sec                ;Datenbit=1, dieses Bit ins Carry schreiben =>
> Carry Flag setzen
>     rjmp  loop2          ;

Schon das kann ein C-Compiler aber besser:
1
uint8_t serin( void )
2
{
3
  uint8_t val = 0;
4
  for( uint8_t i = 8; i; i--){
5
    val >>= 1;
6
    if( PIN_A0 )
7
       val |= 0x80;
8
  }
9
  return val;
10
}
ergibt:
1
 102:  98 e0         ldi  r25, 0x08  ; 8
2
 104:  80 e0         ldi  r24, 0x00  ; 0
3
 106:  86 95         lsr  r24
4
 108:  00 99         sbic  0x00, 0  ; 0
5
 10a:  80 68         ori  r24, 0x80  ; 128
6
 10c:  91 50         subi  r25, 0x01  ; 1
7
 10e:  d9 f7         brne  .-10       ; 0x106 <serin+0x4>
8
 110:  08 95         ret

von c-hater (Gast)


Lesenswert?

Werner J. schrieb:

> Ist ja wirklich trivial.

Ja, ist es.

> Zu: Speicher zu klein
> Ich muss ja nur die 128 Ein- und 96 Ausgänge und ca. 100 Merkerbits als
> Prozessabbild im RAM halten. Das schafft selbst ein Arduino One. Den
> Mega brauche ich nur wegen des größeren Flash (für den Logikteil brauche
> ich ca. 10.000 Zeilen Assembler-Code).

Da könnte man sehr wahrscheinlich noch ganz erheblich "aufräumen".

> @Karl: Keine Hochsprache wegen der Geschwindigkeit. Damit schaffe ich
> den Durchlauf des Logikteils in < 10ms.

Hmm. 10.000 Zeilen in 10ms bedeutet, dass du entweder den AVR nur mit 
ca. 1..2MHz laufen läßt oder EXTREMST ineffizienten Code schreibst. Im 
ersteren Fall fragt man sich dann, warum du diesen geringen Takt gewählt 
hast und im zweiteren Fall, warum du Assembler gewählt hast, beherrschen 
tust du die Sprache dann ja offensichtlich nicht, das kann nämlich jeder 
gängige AVR-C-Compiler offensichtlich weitaus besser als du...

> @Peter: Ja, ist ein 13Bit-Bus mit einer Datenleitung.

Diese Information hätte ganz selbstverständlich in's OP gehört, 
idealerweise sogar noch mehr Details über den Bus.

Hier steckt nämlich sehr wahrscheinlich noch erhebliches 
Optimierungspotential bezüglich der Busanbindung drin. Insbesondere auch 
die Möglichkeit, die (De-)Serialisierung, an der sich dein Hirn 
verknotet hat, ganz oder teilweise in Hardware zu realisieren und damit 
die Dauer des IO-Zyklus auf einen Bruchteil der Zeit zu reduzieren, die 
mit Software-(De-)Serialisierung nötig ist.

von MCUA (Gast)


Lesenswert?

> .. Ja, ist ein 13Bit-Bus mit einer Datenleitung.

Für jedes einzelne Bit ein completter Zyklus.
Ganz schön seltsam.
Ob das so richtig übernommen wurde?
Frequenz?


>Hier steckt nämlich sehr wahrscheinlich noch erhebliches
>Optimierungspotential
bloss, dass da Optimierung keinen Sinn (mehr) macht.
Die Steuerung hat ja so (wohl mit sehr wenigen bps) schon Jahre lang 
gelaufen.

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.