Wie programmier ich das elegant in C

Gast #2045462
Lesenswert?

Ich habe hier diesen Schaltplan gemacht.
Ich nenne das mal einen Bus-Koppler bis mir ein besserer Name einfält.
Mit dem 74HC245 kann ich ein Byte vom ATmega8 auf den rechten Bus 
transportieren. (Write_Bus)
Mit dem 74HC574 kann ich von dem rechten Bus ein Byte zum ATmega8 
transportieren. (Read_Bus)
Die CPU auf dem rechten Bus ist der Master, er steuert alle Funktionen.
Der ATmega8 ist nur der Slave.

Ich brauche von dem ATmega8 PD0(RxD) und PD1(TxD) für eine RS232 
Schnittstelle. PB6 und PB7 brauche ich für den Quarz.
Deshalb sind die Bits der Bytes schön auf Port B, C und D verteilt.
Im Platinen-Layout sieht das aber ganz gut aus ;-)

Wie kann ich in C die beiden Funktionen
1
unsigned char Read_Bus(void);
2
void         Write_Bus(unsigned char);
ohne viel Bitpopelei elegant schreiben?
Angehängte Dateien:
Gast #2045472
Lesenswert?

Eine andere Antwort: Nimm Dir als erstes nicht Eleganz zum Ziel sondern 
die Funktion. Hauptsache Du verstehst wie es funktioniert und es geht. 
Die "Eleganz", wie immer man das definiert, kommt dann mit den Jahren.
Gast #2045477
Lesenswert?

Huch schrieb:
> Eine andere Antwort: Nimm Dir als erstes nicht Eleganz zum Ziel sondern
> die Funktion. Hauptsache Du verstehst wie es funktioniert und es geht.
> Die "Eleganz", wie immer man das definiert, kommt dann mit den Jahren.
Sehr richtig, zumal C gerade für "Bitpopeleien" sehr gut geeignet ist.

(Das heisst aber nicht dass C nur für solche Sachen gut ist! (Nur 
dass jetzt keiner ankommt...))
#2045498
Lesenswert?

Warum du die Daten nicht einfach in den USART deines Host-Controllers 
schreibst, will ich jetzt gar nicht wissen.

Aber das, was du da bauen willst, wird so nie funktionieren. Denn woher 
soll der Client wissen, daß gültige Daten am Port anliegen?
Woher soll der Host wissen, daß der Client Daten für ihn hat?

Ein Bus benötigt immer Steuerleitungen. In deinem Fall Strobe und 
Busy/Acknowledge für jeweils beide Busse.

Um nochmal auf meinen ersten Satz zurückzukommen: Lass' den Quatsch und 
nimm den USART vom Host. Ist wesentlich weniger aufwendig und schneller.

mfg.
#2045536
Lesenswert?

Warum nicht mit Port C und B direkt auf den Bus gehen?
Oder einer sonstigen Kombination aus den Ports, um dann INT0 und INT1 
freizuhalten, welche dann als ¬READ und ¬WRITE fungieren.
Oder einen Mega48/88/168 hernehmen, der beherrscht Pinchange-Interrupts 
auf allen Pins. Oder sind 20MHz bzw. die entsprechenden Zeiten, um in 
die Interruptroutine zu springen, zu langsam?

Fragen nebenher:
Wieviele Takte braucht man zum Program Counter ablegen und Sprung?
Nach wievielen Takten bin ich in der Routine drin?

mfg mf

PS: Bitpopelei sehr gut im AVR-GCC-Tutorial beschrieben.
Gast #2046381
Lesenswert?

[IRONIE]
Danke für die Hilfe.
[/IRONIE]

Ich baue für ein über 20 Jahre altes Gerät ein nicht mehr lieferbares 
Interface quasi nach.

Ich hatte gehofft, das man statt Bitpopelei da was in der Art
1
struct status {
2
  unsigned char b0:1;
3
  unsigned char b1:1;
4
  unsigned char b2:1;
5
  unsigned char b3:1;
6
  unsigned char b4:1;
7
  unsigned char b5:1;
8
  unsigned char b6:1;
9
  unsigned char b7:1;
10
};
mit einer struct machen könnte.
Gast #2046392
Lesenswert?

Zerspannungsmechaniker schrieb:
> Ich brauche von dem ATmega8 PD0(RxD) und PD1(TxD) für eine RS232
> Schnittstelle. PB6 und PB7 brauche ich für den Quarz.
> Deshalb sind die Bits der Bytes schön auf Port B, C und D verteilt.

Ja klar. Ein bisschen nachschauen was man eigentlich braucht und man 
würde z.B. einen mega16 nehmen. Der hat mehrere komplette (!) 
8-Bit-Ports. Das würde sich die ganze Bitschieberei auf Null reduzieren.
#2046512
Lesenswert?

Zerspannungsmechaniker schrieb:

> Ich hatte gehofft, das man statt Bitpopelei da was in der Art
>
1
> struct status {
2
>   unsigned char b0:1;
3
>   unsigned char b1:1;
4
>   unsigned char b2:1;
5
>   unsigned char b3:1;
6
>   unsigned char b4:1;
7
>   unsigned char b5:1;
8
>   unsigned char b6:1;
9
>   unsigned char b7:1;
10
> };
11
>
> mit einer struct machen könnte.

ist genauso Bitpopelei

Wo liegt den das Problem.

Schreib dir deine Ausgangslage hin

     PD3 PD2 PC5 PC4 PC3 PC2 PC1 PC0

und überleg dir welche Bitblöcke du beim Einlesen wie schieben musst, 
damit genau diese Bitfolge rauskommt. Ist doch kein wirkliches Problem.

Du liest von PIND ein, dann hast du

     PD7 PD6 PD5 PD4 PD3 PD2 PD1 PD0

interessiert (in Ergebnis nachsehen) bist du an PD3 und PD2. Also setzt 
du gezielt erst mal alle anderen Bits auf 0. Dann hast du

      0   0  0   0  PD3 PD2 0 0

Jetzt schaust du wieder aufs Ergebnis und vergleichst. Wenn du dein 
0-gesetztes Zwischenergebnis um 4 Stellen nach links schiebst, sind die 
beiden Bits dort wo sie sein sollen.

      PD3 PD2 0 0 0 0 0 0

und sind fertig um ins Ergebnis übernommen zu werden.

Und jetzt im ganzen C-Satz:


    uint8_t bitsD = PIND;

    bitsD &= ~( 1 << PD3 | 1 << PD2 );          // auf 0 setzen
    bitsD <<= 4;

fertig zum Zusammenführen mit den Bits vom C-Port.

Beim Schreiben genau anders rum. Du hast 8 Bit und musst du nach diesem 
Schema auf die Portbits verteilen. Auch da gibt es wieder Bitblöcke die 
gemeinsam behandelt werden können.
#2046517
Lesenswert?

Zerspannungsmechaniker schrieb:
> Ich baue für ein über 20 Jahre altes Gerät ein nicht mehr lieferbares
> Interface quasi nach.

Bevor Du anfängst zu programmieren, denke erstmal über das Timing nach.
Wenn der AVR memory mapped dran hängt, muß er ja die Lese- und 
Schreibzeiten einhalten können. Es könnte also ein CPLD oder FPGA 
notwendig werden.

Vermutlich brauchst Du auch noch einige Adreßleitungen, d.h. es wird 
knapp mit den Pins des ATmega8.


Peter

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren