www.mikrocontroller.net

Forum: Codesammlung mehrere MC seriell über Datenbus verbinden (1Draht)


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

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:

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:

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:

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:

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:

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:

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:

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:

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:

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:

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:

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:

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:

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:

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:

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:

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:

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:

Hallo!

Tut mir Leid.

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

Lg
Manuel
Autor: Peter Dannegger (peda)
Datum:

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:

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:

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:

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:

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:

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:

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:

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:

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:

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:

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:

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:

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:

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:

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:

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:

Hat schon mal einer einen slave auf dem Tiny25 gebastelt?
Autor: H.joachim Seifert (crazyhorse)
Datum:

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:

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




Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder GIF-Format hochladen.
Siehe Bildformate

Mit dem Abschicken erkennst du die Nutzungsbedingungen an.

webmaster@mikrocontroller.netImpressumNutzungsbedingungenWerbung auf Mikrocontroller.net