www.mikrocontroller.net

Forum: Projekte & Code mehrere MC seriell über Datenbus verbinden (1Draht)


Autor: Peter Dannegger (peda)
Datum:
Angehängte Dateien:

Bewertung
1 lesenswert
nicht lesenswert
Manchmal will man mehrere MC verbinden, ohne großen Aufwand.

Das hier ist ein sehr einfacher Bus, sogar ein ATtiny13 kann ihn 
implementieren.
Der CPU-Takt muß auch nicht quarzstabil sein, ein Fehler von +-15% ist 
zulässig.

Ich nenne ihn 124Bus, weil die Pulse 1, 2 oder 4 Zeiten lang sind.
Die Pulse haben folgende Bedeutung:
1 * T: 0-Bit
2 * T: 1-Bit
4 * T: Synchronisationsbit

Es wird nur ein Pin benötigt. Man kann aber auch 2 Pins nehmen, wenn man 
z.B. die MCs über Optokoppler galvanisch trennen will.

Es ist ein Single-Master Bus. Nimmt man das erste Byte als Adresse, 
können 256 Slaves angeschlossen werden.

Empfang und Senden erfolgen bequem im Hintergrund über Interrupts. Das 
Main muß also nur die Empfangspakete auswerten und die Sendepakete in 
den Puffer stellen.

Die Bitrate hängt davon ab, wieviel Zeit andere Interrupts benötigen.
Das Beispiel benutzt 10kHz bei 8MHz CPU-Takt.
50kHz habe ich auch erfolgreich getestet, aber für andere Interrupts ist 
dann kaum Zeit übrig.

Die Beispiele sind für den AVR geschrieben, es gehen aber auch beliebig 
andere MCs.

Zum Test wurde ein STK500 mit 3 AVRs verwendet.
Für den ATmega48 gibt es noch ein 2.Beispiel, wo der Timer für den 
124Bus noch gleichzeitig eine PWM macht.
Beim ATtiny261 habe ich auch eine Fallgrube entdeckt.


Peter Dannegger

Autor: sum (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Peter,

danke für das Teilen Deines Codes. Ich finde Deine Idee, das mit dem PWM 
Modus zu "modulieren" sehr interessant. Vielleicht sollte ich meinen Bus 
(Autopilot, siehe suart) auch mal darauf umstellen. Das spart die 
Hälfte aller Interrupts ;-) weil man nicht auschalten braucht...

Schöne Grüße,
 Clemens

Autor: chris (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Peter,

mit der Kommunikation über einen Pin habe ich mich auch schon 
beschäftigt:

Beitrag "Re: Unidirektionale Datenübertragung, 1 Leitung, kein Quarz"

Gruß,
chris

Autor: Knut Ballhause (Firma: TravelRec.) (travelrec) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter Dannegger schrieb:
> Ich nenne ihn 124Bus, weil die Pulse 1, 2 oder 4 Zeiten lang sind.
> Die Pulse haben folgende Bedeutung:
> 1 * T: 0-Bit
> 2 * T: 1-Bit
> 4 * T: Synchronisationsbit

Habe so etwas Ähnliches auch als Debugschnittstelle laufen, ist aber 
eher ein 123-Bus, da das Sync-Bit 3 0-Bit-Längen entspricht ;-)

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Knut Ballhause schrieb:
> Habe so etwas Ähnliches auch als Debugschnittstelle laufen, ist aber
> eher ein 123-Bus, da das Sync-Bit 3 0-Bit-Längen entspricht ;-)

Das verringert aber die erlaubte Toleranz der Taktfrequenz.

Ich habe deshalb auch die Schwelle auf die relative Mitte (1,4) gelegt 
und nicht auf die arithmetische Mitte.


Peter

Autor: chris (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bei meinem BUS-Protokoll war das Entwicklungsziel eine möglichst 
schnelle Datenübertragung zu realisieren. Ursprünglich wollte ich 
1Mbit/s erreichen.
Ich habe ein Ping-Pong-Verfahren zwischen den zwei Prozessoren 
implementiert: Es wird ein Byte vom Master zum Slave gesendet und als 
Antwort sendet der Slave ein Byte zum Master. Damit hat man automatisch 
eine bidirektionale Kommunikation realisert.
Die Geschwindigkeit für ein PING-PONG lag schließlich bei 10-20KHz ( bei 
16 effektiv übertragenen Bits also max ca. 360KBit/s).

Welche Datenrate wird bei euren Verfahren erreicht?

Autor: Blackbird (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So ähnlich ist der Sony Control A1 Bus  (oder (S-Link) aufgebaut:
600µs, 1200µs und 2400µs Pasuse auf einer 1-Draht-Leitung.

Wer also Sony-Audio-Geräte mit Control- A1-Bus hat, kann damit einen 
Konverter zum PC bauen und seine Geräte per PC/Notebook steuern, 
abfragen, usw.


Blackbird

Autor: Manuel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Peter!

Ich verwende deinen 124BUS und habe eine Frage.

wenn ich rx_init() ausführe, wird doch der nächste Timerinterrupt auf 
4*T gesetzt ( Also auf Startbit )

Wenn man nun in dem Timerinterrupt nachschaut, kann man erkennen, dass 
er in die Abfrage " if( rx_idx != DATA_SIZE * 8 )  // receive successful 
" hineingeht, und er somit meint, die Übertragung ist schon fertig.

Gehe ich recht in der Annahme, oder habe ich einen kleinen Kniff 
übersehen?
Aufgrund dessen dass der Ruhepegel bei dir immer + ist, wird ja nur das 
Stopbit ausgeführt, und das Startbit existiert ja eigentlich nicht, 
deshalb könnte ich das nicht auswirken, stimmt das?

Danke

Lg
Manuel

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Manuel schrieb:
> Wenn man nun in dem Timerinterrupt nachschaut, kann man erkennen, dass
> er in die Abfrage " if( rx_idx != DATA_SIZE * 8 )  // receive successful
> " hineingeht, und er somit meint, die Übertragung ist schon fertig.

Nur wenn vorher genau die richtige Anzahl an Datenbits gelesen wurde, 
bedeutet das Sync-Bit auch das Ende des Empfangs.
Ansonsten ist es eben nur ein Sync-Bit und setzt den Bitzähler zurück.


Peter

Autor: Manuel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo!

Ok das heißt also, egal ob ein Startbit kommt oder ein Stopbit, das ist 
erstmal egal.

Es würde rein theoretisch auch ohne gehen richtig?

Ich brauche nämlich zwecks der Datenübertragung per Optokoppler ein low 
als Ruhezustand, dabei habe ich im Timer Interrupt einfach eine Abfrage 
auf Low gemacht, passt oder?

Lg
Manuel

Autor: Manuel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Oder wäre es besser einfach den Optokoppler gegen + als gegen Masse zu 
schalten?

Ansonsten ist ja einiges am Programm zu ändern, dass der Ruhepegel 0 
ist.

Was meinst du ist besser ?

Danke
Lg
Manuel

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Manuel schrieb:
> Oder wäre es besser einfach den Optokoppler gegen + als gegen Masse zu
> schalten?

Ja, dem Optokopller dürfte es egal sein.
Allerdings solltest Du bei einem Optokoppler 2 Leitungen benutzen, da 
der ja nicht bidirektional ist. Und dann ist der Ruhepegel egal, man muß 
nicht mehr zwischen Senden und Empfang umschalten.


Peter

Autor: Manuel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo!

Ja ich verwende natürlich zwei!

Naja der Ruhepegel ist insofern nicht egal, als dass ich mehrere 
Optokoppler parallel betreibe, und die somit im Ruhezustand immer Strom 
verbrauchen würden, würde bei einigen Parallel schon einiges ergeben, 
und das muss ja nicht sein.

Ich habe jetzt folgendes geändert:

Statt Set on Compare hab ich überall Clear on Compare.
Danach die Abfrage, dass er solange ein High ist noch nicht die 
Interrupt deaktiviert.

Zusätzlich da ich ja jetzt 2 Pins verwende, habe ich die Abfrage bei 
tx_init auf das warten des Pins bis es high ist weggelassen.

Und ich habe eine neue variable eingeführt, um zu erkennen, ob der Timer 
Interrupt fürs Senden oder fürs Empfangen ist ( War ja vorher direkt per 
DATA_DDR abgefragt)

Hab ich das einigermaßen richtig gemacht?

Danke dir!
Lg
Manuel

Autor: Manuel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo nochmal!

Kann es sein, dass die Slaves es nicht mögen, wenn der Master zu schnell 
hintereinander sendet? Es kommen immer viele Timeouts zustande, wenn ich 
den Master direkt nach dem empfangen & abarbeiten senden lasse, wenn ich 
allerdings 100ms Abstand lasse, geht es besser.

Trotz dessen gibt es noch häufig Time Outs, wie ist das zu erklären?

Danke!

Lg
Manuel

Autor: Manuel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo nochmal!

Ich habe mittlerweile herausgefunden, dass die Slaves immer senden ( 
also antworten )

Der Master aber auf einmal ein Timeout einleitet. Woran das liegt ist 
mir schleierhaft, das Programm ist genau deines!

Hast du eine Idee wie das sein kann ?

Lg
Manuel

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vielleicht braucht eine andere Routine sehr viel Zeit oder blockiert die 
Interrupts. Geh mal mit der Datenrate runter.

Oder ist vielleicht bei einem das Cal-Byte zerstört und der liegt total 
daneben. Laß mal auf beiden eine 1s Blink-LED laufen und prüfe mit ner 
Stoppuhr. Oder setze beim Master die CLK-OUT Fuse und takte damit den 
Slave.

Wenn nichts hilft, poste mal den kompletten Code von Master/Slave (als 
ZIP).


Peter

Autor: Manuel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo!

also nachdem ich in den PCINT1 Interrupt Aufruf ein "ISR_NOBLOCK" 
geschrieben habe, funktioniert alles einwandfrei!

Woran kann das liegen, ein Interrupt kann nur durch ein 4T ausgeführt 
werden, kommt aber nie vor?

Komisch ist auch, wenn ich den Code lasse wie bei dir, aAntworten die 
Slaves schneller als wenn ich den Code invertiere ( mit Clear on Compare 
und so ) aber ich seh da keinen logischen Grund außer, dass das 
Synchronisationsbit am Schluss statt am Anfang eines Frames kommt.

Lg
Manuel

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Manuel schrieb:
> Woran kann das liegen

Was erwartest Du, ohne den kompletten Code zu zeigen?
Im Hellseherlehrgang habe ich ne 6 gekriegt.


Peter

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

Bewertung
0 lesenswert
nicht lesenswert
Hallo!

Tut mir Leid.

Habs angehängt, die Änderungen sollten für dich eh gut sichtbar sein!

Lg
Manuel

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Manuel schrieb:
> also nachdem ich in den PCINT1 Interrupt Aufruf ein "ISR_NOBLOCK"
> geschrieben habe, funktioniert alles einwandfrei!

Ich habs ja auch so in mein Beispiel geschrieben. Die Datenrate ist 
recht hoch, da können andere Interrupts zu lang sein. Brauchst Du 
wirlich diese hohe Datenrate?


Peter

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Manuel schrieb:
> Habs angehängt, die Änderungen sollten für dich eh gut sichtbar sein!

Man postet immer ein compilierbares File und keine Schnipselchen!
Welches Target überhaupt?
    TCCR0A = 1<<COM0B1;// | 1<<COM0B0;             // set on compare
///////////////////////////////////////////////////////////////////////////////////////////
  if( DATA_PIN == 1 )
      return;


Dann hast Du nur eine Sache geändert, kann also nicht gehen.
Nimm besser erstmal das Beispiel mit 2 Timern, die sind etwas einfacher 
zu verstehen.
Und setze die Datenrate runter.



Peter

Autor: Manuel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo!

Ja ich weiß. Es ist für einen AtMega644

Ja die hohe Datenrate brauche ich.

auch wenn ich
if( DATA_PIN == 0 )

mache, funktioniert es kein Stück besser.
Das meintest du doch hoffentlich oder ?

Aber könntest du mir noch bitte sagen, wieso ein anderer Interrupt 
dazwischenfunken sollte ? Es sind doch keine anderen aktiv, lediglich 
der PCINT und der für 2.8*T, selbiger kann nicht auslösen. Und den PCINT 
wollen wir doch.

Danke für deine Hilfe!

Lg
Manuel

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Manuel schrieb:
> Ja ich weiß. Es ist für einen AtMega644

Na dann kannst Du doch 2 getrennte Compare eines Timers benutzen und 
mußt nicht zwischendurch umschalten (Slave1.c).


Manuel schrieb:
> Ja die hohe Datenrate brauche ich.

Welche und bei welcher Frequenz?


Peter

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du mußt aufhören, Programme als großen monolithischen Block zu 
betrachten.
Wenn etwas nicht funktioniert, mußt Du debuggen. Dazu muß man das 
Programm in einzelne Teile zerlegen und diese testen. Z.B. beide 
Datenrichtungen getrennt testen. Auch kann man erstmal kritische Timings 
runter setzen.

Die Routine (slave1a.c) mit nur einem Compareregister ist durch die 
Umschaltung komplexer und benötigt auch mehr CPU-Zeit. Sie sollte man 
wirklich nur auf dem ATtiny13 einsetzen, wenn der Timer noch anderes 
machen soll.
Beim ATmega644 ist dieser Geiz mit Timern aber nicht nötig.


Peter

Autor: Manuel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo nochmal Peter!

Also auf dem Master, dem AtMega644 verwende ich ja auch deine Master 
Software mit den getrennten Timer Compare.

Trotzdem funktioniert es ausschließlich einwandfrei ( Ohne oft einen 
TimeOut zu bekommen ) Wenn ich "ISR_NOBLOCK" einfüge.

ISR_NOBLOCK heißt ja, dass der Interrupt durch einen anderen Interrupt 
unterbrochen werden darf, da direkt am start ein "sei()" eingefügt wird.

Das heißt also entweder COMPA oder COMPB wird ausgeführt.

Da beim empfangen der COMPA nicht verwendet wird, existieren also nur 
der PCINT und COMPB, COMPB wird allerdings nur beim Synchronisationsbit 
ausgeführt. Deshalb sollte der COMPB den PCINT ja überhaupt nicht stören 
und es sollte keinen Unterschied machen, ob ich "ISR_NOBLOCK" beim PCINT 
Interrupt hinzufüge oder nicht.

Bin ich auf dem Holzweg?

Liebe Grüße
Manuel

Autor: Manuel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Peter !

Ich habe den Fehler herausgefunden, wie ich es lösen kann zwar noch 
nicht, aber ich möchte dir mal den Fehler erklären.

Undzwar ist es die zeit zwischen PCINT aufruf und dem TCNT0=0.

Wenn dazwischen hier ein Interrupt aufgerufen wird, der eigentlich das 
Synchronisationsbit detektieren soll, stimmt die Zählung nichtmehr. 
Nachdem im PCINT Interrupt rx_idx auf 0 gesetzt wurde, also als start, 
geht gleich darauf der COMPB Interrupt an, und setzt rx_idx wieder auf 
255, womit beim nächsten Aufruf von PCINT wieder bei 0 angefangen wird, 
und somit alles falsch ist.

Kannst du verstehen was ich meine?
Hast du eventuell eine Idee selbiges zu umgehen?

Lg
Manuel

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Manuel schrieb:
> Kannst du verstehen was ich meine?

Nein.

Nochmal, ich weiß nicht, welchen Code auf welchen AVRs Du benutzt.
Ich kann nicht hellsehen.

Und hör auf, Deine Codeänderungen beschreiben zu wollen, damit kann 
keiner was anfangen.

Wenn eine Änderung eine Wirkung hat, die Dir unklar ist, dann mach 2 
komplette Projekte, einmal mit und einmal ohne die Änderung.
Oder ein Projekt, wo die Änderung mit einem Define umgeschaltet wird.

Und dann kannst Du auch darauf Bezug nehmen (folgende Änderung in File 
x.c, Zeile y habe ich gemacht ...).


Peter

P.S.:
Target, Taktfrequenz, Compilerversion, Compileroptionen, 
Anschlußbelegung usw. gehören selbstverständlich zu den Angaben, die im 
Projekt enthalten sein müssen.

Autor: Manuel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo nochmal!

Ich habe mich echt bemüht dir zu erklären wo der Fehler liegt.

Ich kann dir auch sagen, wieso der Fehler bei dir nie aufgetreten ist, 
aber bei mir schon, dennoch hilft es nichts wenn ich den kompletten Code 
einfüge. Aber ich werde es einmal Versuchen.

Original:
ISR( TIMER0_COMPB_vect )                // sync received
{ if( rx_idx == DATA_SIZE * 8)          // receive successful
  {  PCMSK1 = 0;      // disable further receive
  }
  rx_idx = 255;                         // detect sync transition
  if( rx_timeout ){            // timeout answer from slave
    rx_timeout--;
    TCNT0 = 0;
  }
}

Testcode:
ISR( TIMER0_COMPB_vect )                               
{ if( rx_idx == DATA_SIZE * 8 || rx_idx == DATA_SIZE * 8 - 1) 
  {  PCMSK1 = 0;                      
  }
  rx_idx = 255;                       
  if( rx_timeout ){            
    rx_timeout--;
    TCNT0 = 0;
  }
}

So beim Testcode schaltet er ebenfalls ab, wenn einmal eine Flanke 
gefehlt hat ( Eben wenn besagter Fehler auftritt ), dann tritt nie ein 
Timeout auf!

Ich habe es mit dem Oszilloskop überprüft ob es tatsächlich daran liegt, 
und es liegt daran.

In der Zeit zwichhen dem
ISR( PCINT1_vect )
 Aufruf und
TCNT0 = 0;
 kommmt ein Timer0 Compare B Interrupt und setzt rx_idx NACH BEDINGUNG 
des Pin Change Interrupts fälschlicherweiße auf 255.

Erklärung warum bei dir der Fehler nicht auftritt:
Bei deinen Slaves kommt das Synchronisationsbit am Anfang, das heißt 
zuerst 4T und danach die Daten, bei mir ist es Programmtechnisch 
umgekehrt, zuerst die Daten dann das Synchronisationsbit, aus diesem 
Grund kann der Fehler bei dir nicht auftreten, bei mir aber schon.

Erklärung warum es bei hinzufügen von
ISR_NOBLOCK
 bei der
ISR ( PCINT1_vect )
 Routine zu keinem Fehler kommt:
Nachdem der Compiler ja als bald als möglich den Interrupt mit
sei()
 wieder frei gibt, hat der
ISR( TIMER0_COMPB_vect )
 Interrupt in der kritischen Phase eine Eingriffsmöglichkeit, und somit 
kann fast kein Fehler mehr auftreten, der Aufgrund der Wartezeit vom 
Compare B Interupt auftritt.

Peter, ich hoffe, dass ich es ausführlich, verständlich und genau 
erklärt habe. Ich weiß, dass ich hier nichts von Compilerversion, Target 
etc. geschrieben habe, da es in diesem Fall keine Auswirkung hat. Ich 
hoffe, dass du damit einverstanden bist, wenn nicht, bitte sag es mir 
nochmal ich werde versuchen die Erklärung zu verbessern, auch wenn ich 
momentan keine Ahnung habe wie ich es noch verbessern sollte.

Dankesehr Peter!

Lg
Manuel

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Manuel schrieb:
> Bei deinen Slaves kommt das Synchronisationsbit am Anfang, das heißt
> zuerst 4T und danach die Daten, bei mir ist es Programmtechnisch
> umgekehrt, zuerst die Daten dann das Synchronisationsbit,

Warum sagst Du denn nicht gleich, daß Du am Master-Code rumgefriemelt 
hast?
Das kann ja nicht funktionieren!

Du brauchst zu Anfang eine Flanke und die ist eben das Ende des 
Sync-Bits und der Start des 1.Datenbits.
Ich kann Dir versichern, ich habe mir dabei was gedacht, es so zu machen 
und nicht anders.

Du kannst Dir natürlich ein anderes Protokoll ausdenken, aber dann 
kannst Du meinen Code nicht mehr verwenden.


Peter

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

Bewertung
0 lesenswert
nicht lesenswert
Hallo Peter!

Tut mir Leid, ich habe es so verstanden, dass es egal ist, ob das 
Synchronisationsbit am Anfang oder am Ende kommt. Danke dass du mir das 
jetzt erklärt hast.

Im Anhang befindet sich meine Testdatei.

Ziel ist ein Attiny13, selbiger soll nur Aussenden.
Ich verwende AVR Studio mit AVR-GCC die neueste Version.

Da ich Sendeleitung und Empfangsleitung getrennt habe, gibt es ein 
kleines Problem und zwar hier:
void tx_data( uint8_t addr, uint8_t data )
{
  PCMSK = 0;            // disable receive
  DATA_DDR = 0;                                 // input
  DATA = 1;                                     // pullup on
  while( DATA_PIN == 0 );                       // wait until pin high
...

Du setzt hier den Data Pin auf Eingang, legst einen Pull Up auf High und 
wartest bis er auf 0 gezogen wird.

Die Frage ist nun, wie wird er jetzt auf 0 gezogen?

Ich brauche ja nicht auf Eingang schalten und warten, da ich diesen PIN 
ja sowieso nur als Ausgang verwende, aber ein einfaches umschreiben auf:
void tx_data( uint8_t addr, uint8_t data )
{ 
  PCMSK = 0;
  DATA_DDR =1;
  DATA = 1;
...
funktioniert ja nicht.

Kannst du mir eventuell erklären wieso es auf 0 gezogen werden soll, 
bzw. wie ich es in meinem Fall umschreiben kann, dass es auch 
funktioniert wenn ich einen Optokoppler am Ausgang gegen Masse habe?

Ich sitze wirklich nun schon seit ca. 12 Uhr da und versuche es. Es tut 
mir Leid, dass ich nicht der Profi Programmierer bin, und ein wenig 
Hilfe brauche, ich hoffe du kannst es verstehen, und siehst auch, dass 
ich mich wirklich bemühe es selbst zu schaffen.

Großen Dank Peter!

Lg
Manuel

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn der ATtiny13 von sich aus sendet, ist er natürlich der Master und 
der andere der Slave, er muß ständig empfangsbereit sein.
Du kannst den Sendeausgang dann ständig eingeschaltet lassen.
Ein Timeout muß dann länger sein, als der Master zwischen dem Senden 
maximal Pause macht.

Wenn Du Modifikationen vornimmst, ist es ratsam, mit einem Oszi das 
Signal anzusehen.


Peter

Autor: Manuel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter Dannegger schrieb:
> Wenn der ATtiny13 von sich aus sendet, ist er natürlich der Master und
> der andere der Slave, er muß ständig empfangsbereit sein.
> Du kannst den Sendeausgang dann ständig eingeschaltet lassen.
> Ein Timeout muß dann länger sein, als der Master zwischen dem Senden
> maximal Pause macht.
>
> Wenn Du Modifikationen vornimmst, ist es ratsam, mit einem Oszi das
> Signal anzusehen.
>
>
> Peter

Hallo!

Ja das ist klar, ich habe das Programm geschrieben, da mir lediglich der 
Sendevorgang Sorge bereitet! Momentan sende ich nur mit dem Attiny13 und 
schaue mir den Ausgang am Oszilloskop an.

Wenn ich auf das warten bis der Pin "0" wird verzichte, dann 
funktioniert es nur jedes zweite mal.

Also 1. Sekunde richtig, 2. Sekunde falsch.

Falsch äußert sich dahingehend, dass das Synchronisationsbit nicht 
gesendet wird, und auch das letzte Bit nicht gesendet wird.

Beim dritten mal passt es wieder, beim 4. nicht,...

Ich kann es mir nicht so recht erklären, wieso es jedes zweite Mal 
funktioniert, da hier ja nirgends etwas umgeschalten wird, nach jedem 
mal senden, zumindest sehe ich das so.

So leid es mir tut, dich nochmals Fragen zu müssen, ob du eventuell 
einen Tipp hast, wieso selbiges Phänomen auftritt.

Danke
Lg
Manuel

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ein Sync-Bit ist per meiner Definition >=4*T, nach oben hin gibt es 
keine Grenze.
Also wenn eine Sekunde lang nichts gesendet wird, ist das ein astreines 
Sync.

Ein zusätzliches Sync schadet aber nicht, für die Anzahl gibt es auch 
keine obere Grenze.


Peter

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

Bewertung
0 lesenswert
nicht lesenswert
Folgende Änderung:
void tx_data( uint8_t addr, uint8_t data )
{
  PCMSK = 0;            // disable receive
  DATA_DDR = 1;                                 // input
  DATA = 1;                                     // pullup on
  //while( DATA_PIN == 0 );                       // wait until pin high

  OCR0B = TCNT0 + (uint16_t)(BIT_TIME * 4 + 0.5);      // sync: 4T
  TCCR0A = 1<<COM0B0;                           // toggle on compare
  //DATA_DDR = 1;                                 // tx output on
  TIFR0 = 1<<OCF0B;                             // clear earlier interrupts
  DATA_INT = 1;                                 // enable tx interrupt
  volatil(tx_idx) = 0;                          // point to first bit
  volatil(tx_buff[0]) = addr;
  volatil(tx_buff[1]) = data;
  while( DATA_INT );                            // until tx done
}

führt zum "Erfolg" im Anhang.

Ausgesendet soll zweimal eine "1" werden.

Beim 1. Bild passt alles einwandfrei
beim 2. Bild fehlt Synchronisationsbit und letztes Bit.

Lg
Manuel

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

Bewertung
0 lesenswert
nicht lesenswert
Hallo Peter!

ICh sollte mich schämen, hab ich doch glatt etwas vergessen zu ändern:
ISR( TIM0_COMPB_vect, ISR_NOBLOCK )           // Transmit/Sync interrupt
{
  uint8_t *dp;          // locals for faster access

  if( DATA_DDR )
  {
    if( tx_idx < DATA_SIZE * 8 )
  {
      OCR0B += (uint16_t)(BIT_TIME + 0.5);      // 0-bit: 1T
      dp = &tx_buff[tx_idx++ / 8];              // get byte address
      if( *dp & 0x80 )                          // msb first
        OCR0B += (uint16_t)(BIT_TIME + 0.5);    // 1-bit: 2T
      *dp <<= 1;                                // shift bits
      return;
    }
    OCR0B += (uint16_t)(BIT_TIME * 4 + 0.5);    // Sync:  4T
    TCCR0A = 1<<COM0B1 | 1<<COM0B0;             // set on compare
    if( DATA_PIN == 1 )
      return;
  }
Das:
TCCR0A = 1<<COM0B1 | 1<<COM0B0;             // set on compare
war zuvor:
TCCR0A = 1<<COM0A1 | 1<<COM0A0;             // set on compare

Dummer dummer Fehler :( Tut mir leid.

hab jetzt ein Oszi Bild in den Anhang gestellt.

Das passt nun so richtig, wie du den 124Bus Designed hast richtig?

Lg
Manuel

Autor: H.Joachim Seifert (crazyhorse)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hat schon mal einer einen slave auf dem Tiny25 gebastelt?

Autor: H.Joachim Seifert (crazyhorse)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mit Timer0 (OC0A, PB0 und PCINT0) klappt es wunderbar.
Nur mit dem Timer1 bekomme ich es nicht hin.
Platinen schon fertig, der Bus müsste auf PB4/OC1B/PCINT4.
Nach wie vor läuft der Timer1 in der Simualtion AVR-Studio 4.19 nicht 
:-(

Naja, werde jetzt erstmal die Platinen umverdrahten, 2 Tage mit dem Mist 
zugebracht...

Autor: H.Joachim Seifert (crazyhorse)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also mit dem Mist meine ich den Timer1 vom Tiny25, nicht die Software 
von PeDa, nicht dass hier Missverständnisse aufkommen....
Klappt wunderbar, und so kompakt hätte ich es selbst sicher nicht 
hinbekommen.

Eine Anmerkung trotzdem:

TIMSK = 1<<OCIE1A;                            // sync interrupt
o.ä.
kann natürlich leicht zur Falle werden.
Löscht andere Timer Int-Freigaben und man sieht schlecht, dass es auch 
darauf ankommt, dass OCIE1B gelöscht wird. Besser wäre:

 TIMSK = (TIMSK | 1<<OCIE1A) & ~ (1<<OCIE1B);    //OCIE1A on, OCIE1B off

löscht sichtbar OCIE1B und lässt die andern Bits in Ruhe.

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.