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


von Peter D. (peda)


Angehängte Dateien:

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

von sum (Gast)


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

von chris (Gast)


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

von Knut B. (Firma: TravelRec.) (travelrec) Benutzerseite


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 ;-)

von Peter D. (peda)


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

von chris (Gast)


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?

von Blackbird (Gast)


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

von Manuel (Gast)


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

von Peter D. (peda)


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

von Manuel (Gast)


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

von Manuel (Gast)


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

von Peter D. (peda)


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

von Manuel (Gast)


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

von Manuel (Gast)


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

von Manuel (Gast)


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

von Peter D. (peda)


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

von Manuel (Gast)


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

von Peter D. (peda)


Lesenswert?

Manuel schrieb:
> Woran kann das liegen

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


Peter

von Manuel (Gast)


Angehängte Dateien:

Lesenswert?

Hallo!

Tut mir Leid.

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

Lg
Manuel

von Peter D. (peda)


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

von Peter D. (peda)


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?
1
    TCCR0A = 1<<COM0B1;// | 1<<COM0B0;             // set on compare
2
///////////////////////////////////////////////////////////////////////////////////////////
3
  if( DATA_PIN == 1 )
4
      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

von Manuel (Gast)


Lesenswert?

Hallo!

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

Ja die hohe Datenrate brauche ich.

auch wenn ich
1
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

von Peter D. (peda)


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

von Peter D. (peda)


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

von Manuel (Gast)


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

von Manuel (Gast)


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

von Peter D. (peda)


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.

von Manuel (Gast)


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:
1
ISR( TIMER0_COMPB_vect )                // sync received
2
{ if( rx_idx == DATA_SIZE * 8)          // receive successful
3
  {  PCMSK1 = 0;      // disable further receive
4
  }
5
  rx_idx = 255;                         // detect sync transition
6
  if( rx_timeout ){            // timeout answer from slave
7
    rx_timeout--;
8
    TCNT0 = 0;
9
  }
10
}

Testcode:
1
ISR( TIMER0_COMPB_vect )                               
2
{ if( rx_idx == DATA_SIZE * 8 || rx_idx == DATA_SIZE * 8 - 1) 
3
  {  PCMSK1 = 0;                      
4
  }
5
  rx_idx = 255;                       
6
  if( rx_timeout ){            
7
    rx_timeout--;
8
    TCNT0 = 0;
9
  }
10
}

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
1
ISR( PCINT1_vect )
 Aufruf und
1
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
1
ISR_NOBLOCK
 bei der
1
ISR ( PCINT1_vect )
 Routine zu keinem Fehler kommt:
Nachdem der Compiler ja als bald als möglich den Interrupt mit
1
sei()
 wieder frei gibt, hat der
1
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

von Peter D. (peda)


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

von Manuel (Gast)


Angehängte Dateien:

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:
1
void tx_data( uint8_t addr, uint8_t data )
2
{
3
  PCMSK = 0;            // disable receive
4
  DATA_DDR = 0;                                 // input
5
  DATA = 1;                                     // pullup on
6
  while( DATA_PIN == 0 );                       // wait until pin high
7
...

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:
1
void tx_data( uint8_t addr, uint8_t data )
2
{ 
3
  PCMSK = 0;
4
  DATA_DDR =1;
5
  DATA = 1;
6
...
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

von Peter D. (peda)


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

von Manuel (Gast)


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

von Peter D. (peda)


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

von Manuel (Gast)


Angehängte Dateien:

Lesenswert?

Folgende Änderung:
1
void tx_data( uint8_t addr, uint8_t data )
2
{
3
  PCMSK = 0;            // disable receive
4
  DATA_DDR = 1;                                 // input
5
  DATA = 1;                                     // pullup on
6
  //while( DATA_PIN == 0 );                       // wait until pin high
7
8
  OCR0B = TCNT0 + (uint16_t)(BIT_TIME * 4 + 0.5);      // sync: 4T
9
  TCCR0A = 1<<COM0B0;                           // toggle on compare
10
  //DATA_DDR = 1;                                 // tx output on
11
  TIFR0 = 1<<OCF0B;                             // clear earlier interrupts
12
  DATA_INT = 1;                                 // enable tx interrupt
13
  volatil(tx_idx) = 0;                          // point to first bit
14
  volatil(tx_buff[0]) = addr;
15
  volatil(tx_buff[1]) = data;
16
  while( DATA_INT );                            // until tx done
17
}

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

von Manuel (Gast)


Angehängte Dateien:

Lesenswert?

Hallo Peter!

ICh sollte mich schämen, hab ich doch glatt etwas vergessen zu ändern:
1
ISR( TIM0_COMPB_vect, ISR_NOBLOCK )           // Transmit/Sync interrupt
2
{
3
  uint8_t *dp;          // locals for faster access
4
5
  if( DATA_DDR )
6
  {
7
    if( tx_idx < DATA_SIZE * 8 )
8
  {
9
      OCR0B += (uint16_t)(BIT_TIME + 0.5);      // 0-bit: 1T
10
      dp = &tx_buff[tx_idx++ / 8];              // get byte address
11
      if( *dp & 0x80 )                          // msb first
12
        OCR0B += (uint16_t)(BIT_TIME + 0.5);    // 1-bit: 2T
13
      *dp <<= 1;                                // shift bits
14
      return;
15
    }
16
    OCR0B += (uint16_t)(BIT_TIME * 4 + 0.5);    // Sync:  4T
17
    TCCR0A = 1<<COM0B1 | 1<<COM0B0;             // set on compare
18
    if( DATA_PIN == 1 )
19
      return;
20
  }
Das:
1
TCCR0A = 1<<COM0B1 | 1<<COM0B0;             // set on compare
war zuvor:
1
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

von H.Joachim S. (crazyhorse)


Lesenswert?

Hat schon mal einer einen slave auf dem Tiny25 gebastelt?

von H.Joachim S. (crazyhorse)


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...

von H.Joachim S. (crazyhorse)


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.

von Johannes (Gast)


Lesenswert?

Hallo, hat jemand den Bus schonmal auf einem ATtiny10 zum laufen 
gebracht?

Ich bin recht frisch im Microcontroller programmieren und würde gerne 
von einem Raspberry Pi aus mehrere ATtiny10 ansteuern die dann je einen 
Servo steuern.
Könnte mir jemand sagen ob ich mit dem 124Bus auf dem richtigen Weg bin?

Ich habe versucht den Slave2 für den ATtiny10 zu kompilieren, dies 
schlägt aber mit einigen Errors fehl:
1
Severity  Code  Description  Project  File  Line
2
Error    recipe for target 'main.o' failed  NextSerialTest  C:\Users\Abc\Documents\Atmel Studio\7.0\NextSerialTest\NextSerialTest\Debug\Makefile  79
3
Error    'CS12' undeclared (first use in this function)  NextSerialTest  C:\Users\Abc\Documents\Atmel Studio\7.0\NextSerialTest\NextSerialTest\main.c  46
4
Error    'CS12' undeclared (first use in this function)  NextSerialTest  C:\Users\Abc\Documents\Atmel Studio\7.0\NextSerialTest\NextSerialTest\main.c  46
5
Error    'CS11' undeclared (first use in this function)  NextSerialTest  C:\Users\Abc\Documents\Atmel Studio\7.0\NextSerialTest\NextSerialTest\main.c  46
6
Error    'CS11' undeclared (first use in this function)  NextSerialTest  C:\Users\Abc\Documents\Atmel Studio\7.0\NextSerialTest\NextSerialTest\main.c  46
7
Error    'CS10' undeclared (first use in this function)  NextSerialTest  C:\Users\Abc\Documents\Atmel Studio\7.0\NextSerialTest\NextSerialTest\main.c  46
8
Error    'CS10' undeclared (first use in this function)  NextSerialTest  C:\Users\Abc\Documents\Atmel Studio\7.0\NextSerialTest\NextSerialTest\main.c  46
9
Error    'DDRA' undeclared (first use in this function)  NextSerialTest  C:\Users\Abc\Documents\Atmel Studio\7.0\NextSerialTest\NextSerialTest\main.c  52
10
Error    'OCR1C' undeclared (first use in this function)  NextSerialTest  C:\Users\Abc\Documents\Atmel Studio\7.0\NextSerialTest\NextSerialTest\main.c  71
11
Error    'TCCR1B' undeclared (first use in this function)  NextSerialTest  C:\Users\Abc\Documents\Atmel Studio\7.0\NextSerialTest\NextSerialTest\main.c  79
12
Error    'PCMSK1' undeclared (first use in this function)  NextSerialTest  C:\Users\Abc\Documents\Atmel Studio\7.0\NextSerialTest\NextSerialTest\main.c  86
13
Error    'TCCR1B' undeclared (first use in this function)  NextSerialTest  C:\Users\Abc\Documents\Atmel Studio\7.0\NextSerialTest\NextSerialTest\main.c  87
14
Error    'TIFR' undeclared (first use in this function)  NextSerialTest  C:\Users\Abc\Documents\Atmel Studio\7.0\NextSerialTest\NextSerialTest\main.c  94
15
Severity  Code  Description  Project  File  Line
16
Error    'OCF1B' undeclared (first use in this function)  NextSerialTest  C:\Users\Abc\Documents\Atmel Studio\7.0\NextSerialTest\NextSerialTest\main.c  94
17
Error    'TCNT1' undeclared (first use in this function)  NextSerialTest  C:\Users\Abc\Documents\Atmel Studio\7.0\NextSerialTest\NextSerialTest\main.c  95
18
Error    'OCR1B' undeclared (first use in this function)  NextSerialTest  C:\Users\Abc\Documents\Atmel Studio\7.0\NextSerialTest\NextSerialTest\main.c  96
19
Error    'OCR1C' undeclared (first use in this function)  NextSerialTest  C:\Users\Abc\Documents\Atmel Studio\7.0\NextSerialTest\NextSerialTest\main.c  97
20
Error    'TCCR1A' undeclared (first use in this function)  NextSerialTest  C:\Users\Abc\Documents\Atmel Studio\7.0\NextSerialTest\NextSerialTest\main.c  98
21
Error    'COM1B1' undeclared (first use in this function)  NextSerialTest  C:\Users\Abc\Documents\Atmel Studio\7.0\NextSerialTest\NextSerialTest\main.c  98
22
Error    'COM1B0' undeclared (first use in this function)  NextSerialTest  C:\Users\Abc\Documents\Atmel Studio\7.0\NextSerialTest\NextSerialTest\main.c  98
23
Error    'FOC1B' undeclared (first use in this function)  NextSerialTest  C:\Users\Abc\Documents\Atmel Studio\7.0\NextSerialTest\NextSerialTest\main.c  99
24
Error    'TIMSK' undeclared (first use in this function)  NextSerialTest  C:\Users\Abc\Documents\Atmel Studio\7.0\NextSerialTest\NextSerialTest\main.c  103
25
Error    'OCIE1B' undeclared (first use in this function)  NextSerialTest  C:\Users\Abc\Documents\Atmel Studio\7.0\NextSerialTest\NextSerialTest\main.c  103
26
Error    'TCNT1' undeclared (first use in this function)  NextSerialTest  C:\Users\Abc\Documents\Atmel Studio\7.0\NextSerialTest\NextSerialTest\main.c  120
27
Error    'TIFR' undeclared (first use in this function)  NextSerialTest  C:\Users\Abc\Documents\Atmel Studio\7.0\NextSerialTest\NextSerialTest\main.c  126
28
Error    'OCF1B' undeclared (first use in this function)  NextSerialTest  C:\Users\Abc\Documents\Atmel Studio\7.0\NextSerialTest\NextSerialTest\main.c  126
29
Error    'PCMSK1' undeclared (first use in this function)  NextSerialTest  C:\Users\Abc\Documents\Atmel Studio\7.0\NextSerialTest\NextSerialTest\main.c  138
30
Error    'PCMSK1' undeclared (first use in this function)  NextSerialTest  C:\Users\Abc\Documents\Atmel Studio\7.0\NextSerialTest\NextSerialTest\main.c  143
31
Error    'TCCR1B' undeclared (first use in this function)  NextSerialTest  C:\Users\Abc\Documents\Atmel Studio\7.0\NextSerialTest\NextSerialTest\main.c  148
32
Error    'TCCR1A' undeclared (first use in this function)  NextSerialTest  C:\Users\Abc\Documents\Atmel Studio\7.0\NextSerialTest\NextSerialTest\main.c  152
33
Error    'TIFR' undeclared (first use in this function)  NextSerialTest  C:\Users\Abc\Documents\Atmel Studio\7.0\NextSerialTest\NextSerialTest\main.c  153
34
Error    'OCF1A' undeclared (first use in this function)  NextSerialTest  C:\Users\Abc\Documents\Atmel Studio\7.0\NextSerialTest\NextSerialTest\main.c  153
35
Error    'OCF1B' undeclared (first use in this function)  NextSerialTest  C:\Users\Abc\Documents\Atmel Studio\7.0\NextSerialTest\NextSerialTest\main.c  153
36
Error    'TCNT1' undeclared (first use in this function)  NextSerialTest  C:\Users\Abc\Documents\Atmel Studio\7.0\NextSerialTest\NextSerialTest\main.c  154
37
Error    'OCR1B' undeclared (first use in this function)  NextSerialTest  C:\Users\Abc\Documents\Atmel Studio\7.0\NextSerialTest\NextSerialTest\main.c  155
38
Error    'OCR1A' undeclared (first use in this function)  NextSerialTest  C:\Users\Abc\Documents\Atmel Studio\7.0\NextSerialTest\NextSerialTest\main.c  156
39
Error    'TIMSK' undeclared (first use in this function)  NextSerialTest  C:\Users\Abc\Documents\Atmel Studio\7.0\NextSerialTest\NextSerialTest\main.c  158
40
Error    'OCIE1A' undeclared (first use in this function)  NextSerialTest  C:\Users\Abc\Documents\Atmel Studio\7.0\NextSerialTest\NextSerialTest\main.c  158
41
Error    'PCMSK0' undeclared (first use in this function)  NextSerialTest  C:\Users\Abc\Documents\Atmel Studio\7.0\NextSerialTest\NextSerialTest\main.c  160
42
Error    'PCMSK1' undeclared (first use in this function)  NextSerialTest  C:\Users\Abc\Documents\Atmel Studio\7.0\NextSerialTest\NextSerialTest\main.c  161
43
Error    'PCINT11' undeclared (first use in this function)  NextSerialTest  C:\Users\Abc\Documents\Atmel Studio\7.0\NextSerialTest\NextSerialTest\main.c  161
44
Error    'GIFR' undeclared (first use in this function)  NextSerialTest  C:\Users\Abc\Documents\Atmel Studio\7.0\NextSerialTest\NextSerialTest\main.c  162
45
Error    'PCIF' undeclared (first use in this function)  NextSerialTest  C:\Users\Abc\Documents\Atmel Studio\7.0\NextSerialTest\NextSerialTest\main.c  162
46
Error    'GIMSK' undeclared (first use in this function)  NextSerialTest  C:\Users\Abc\Documents\Atmel Studio\7.0\NextSerialTest\NextSerialTest\main.c  163
47
Error    'PORTA' undeclared (first use in this function)  NextSerialTest  C:\Users\Abc\Documents\Atmel Studio\7.0\NextSerialTest\NextSerialTest\main.c  170

Ich vermute das hier die Bezeichnung für die Pins des Tiny10 anders 
sind.

Zusammengefasst noch mal meine Frage: Lohnt sich der Weg über den 124Bus 
für einen ATtiny10, gibt es ggf. einfachere Ansätze oder kennt jemand 
eine Lösung für die Raspberry Pi -> ATtiny10 Kommunikation die ich mir 
anschauen könnte.

Vielen Dank im Vorraus,
Johannes

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.