Bascom Serielle Eindraht Kommunikation

Poeler

Neues Mitglied
17. Sep. 2011
9
0
0
Sprachen
Hallo zussammen erstmal,

ich bin neu in diesem Forum habe ich mal eine Verständnisfrage zum UART des Attiny 2313 unter Bascom.

Ich arbeite gerade an einem PowerLine Projekt. Die Knoten kommunizieren über das 220V Hausnetz.
Daher habe ich bezüglich der Kommunikation ein paar Probleme bzw. Fragen, die bei Verwendung von
getrennten RxD und TxD Leitungen nicht auftreten. Ich hoffe, Ihr könnt mir ein paar Tipps geben.

Zum Projekt:

Jeder Knoten verfügt über einen ATTINY 2313 und einen TDA5051A. Programmiersprache ist wie gesagt Bascom.
Die Kommunikation erfolgt bidirektional über die Phase des Hausnetzes. Der Master eröffnet die Kommunikation,
die Knoten senden nur eine Quittung. Dadurch ist sichergestellt, das immer nur ein Knoten sendet. Ich habe
mich entschlossen, für die Kommunikation das SNAP Protokoll zu benutzen: http://www.hth.com/snap/
Im Gegensatz zu den dortigen Beispielen möchte ich den Datenempfang per Interrupt abwickeln.

Jetzt die eigentlichen Fragen:

Soweit ich das Datasheet verstehe, wird bei jedem empfangenen Zeichen ein URXC Interrupt ausgelöst,
der dann durch Auslesen des Zeichens zurückgesetzt wird. Da ein gesendetes Zeichen wegen der gemeinsamen
RX / TX Leitung gleichzeitig auch empfangen wird, ist meine Idee, den URXC Interrupt beim Sendebeginn auszuschalten und nach dem Senden des letzten Zeichens wieder zu aktivieren. Ist das soweit grundsätzlich OK oder gibt es da einen besseren Weg?

Dann habe ich festgestellt, das der Interrupt auch dann am Sender anliegt, wenn während des Sendens der INT abgeschaltet und erst nachher wieder aktiviert wurde (Nach dem "Enable Uxrc"). Muss ich also den gesamten Buffer,
der ja während des Sendens gefüllt wurde, auslesen um den INT zu löschen?

Ich habe ebenfalls festgestellt, das der Interrupt nicht durch Auslesen eines (des letzten) Zeichens zurückgesetzt wird, sondern mehrere Zeichen ausgelesen werden müssen. Ich sehe das so, das im Puffer noch Zeichen stecken,
und der INT erst zurückgeset wird, wenn alle Zeichen ausgelesen wurden. Also müsste ich so viele Zeichen auslesen,
bis der INT zurückgesetzt wurde (zusätzliches Zeichen durch Störungen empfangen) oder habe ich da was anderes übersehen?

Ich hoffe auf ein paar Tipps, wie ich diese Problem lösen kann.

Mit freundlichen Grüßen

Poeler
 
Hallo Poeler,
herzlich willkommen in diesem freundlichen Forum.

Soweit ich das Datasheet verstehe, wird bei jedem empfangenen Zeichen ein URXC Interrupt ausgelöst, der dann durch Auslesen des Zeichens zurückgesetzt wird.
Muss nicht so sein, kannst du aber so konfigurieren. Mache ich beim UART auch am liebsten mit Interrupt.
Da ein gesendetes Zeichen wegen der gemeinsamen RX / TX Leitung gleichzeitig auch empfangen wird, ist meine Idee, den URXC Interrupt beim Sendebeginn auszuschalten und nach dem Senden des letzten Zeichens wieder zu aktivieren. Ist das soweit grundsätzlich OK oder gibt es da einen besseren Weg?

Dann habe ich festgestellt, das der Interrupt auch dann am Sender anliegt, wenn während des Sendens der INT abgeschaltet und erst nachher wieder aktiviert wurde (Nach dem "Enable Uxrc"). Muss ich also den gesamten Buffer,
der ja während des Sendens gefüllt wurde, auslesen um den INT zu löschen?
Wenn du den Interrupt disablest bedeutet das nur, das nach dem Empfang eines Zeichens nicht sofort in die ISR gesprungen wird. Wenn du dann enablest, kommt die ISR.
Alternativ kannst du auch den ganzen Empfang abschalten. Dazu setzt du im Register UCSRB das Bit RXEN auf 0. Schau es dir mal im Datenblatt auf Seite 135 an.

Gruß

Sebastian
 
Hi Poeler,

wie Sebastian schon sagte, reicht es nicht aus das Interrupt auszuschalten, Du musst den Empfänger ausschalten. Wenn Du mit dem Senden dann fertig bist, schaltest Du den Empfänger und ISR wieder ein.

Bedenke: Wenn die MCU im Interrupt ist, kann sie nichts anderes machen. Deswegen ist es immer sehr gut die Interruptroutinen so kurz und so schnell wie möglich zu gestalten, damit die MCU dann schnell wieder rauskann. Die Attiny sind ja eh nicht so die Rechenmonster.

Grüssle
Heinrich
 
Hallo Sebastian und Heinrich,

war offensichtlich eine gute Idee hier zu fragen. Euer Ansatz ist genau das, was ich gesucht habe.
Die ISR ist so kurz wie möglich gehalten. Es werden eigentlich nur die empfangenen Zeichen in ein Array gepackt.
Die Auswertung kommt dann später. Der kleine ATTINY hat eigentlich auch nicht viel zu tun. Er soll ja nur eine recht simple Aktion auführen.
Im Moment befasse ich mich mit einigen Testprogrammen um mal auszuloten, ob man im Hausnetz eine einigermaßen zuverlässige Übertragung hin bekommt. Es gibt da ja auch einige gescheiterte Projekte.

Besten Dank erstmal, ich melde mich bestimmt wieder.

Gruß

Poeler
 
Guten Abend zusammen,

gerade habe ich den obigen Vorschlag mal probiert:

Code:
Senden:
Reset Led2                                                  'Sendequittung
Ucsrb = Ucsrb And &B11101111                                'Beim Senden RxD disablen
For I = 1 To 26                                             '26 Bytes aus EPROM holen und senden
   Readeeprom J , I
   Print Chr(j)
Next I
Waitms 10
Ucsrb = Ucsrb Or &B00010000
Return

Allerdings scheint Bascom das Register UCSRB (Data Sheet Seite 131) nicht zu kennen. Im Simulator gibt es das Register nicht, im Programmcode wird es nicht farblich anders dargestellt. Das Register UCSRC gibt es.
Muss man UCSRCB anders behandeln z.B. weil Bit 1 nur RO ist? Wie manipuliere ich dann ein einzelnes Bit des Registers?

Danke für einen Tipp.

Gruß

Poeler
 
Du hast oben geschrieben, dass du einen Attiny2313 hast. Dann musst du im regfile das angeben:
$regfile = "attiny2313.dat"

Wahrscheinlich hast du
$regfile = "2313def.dat"
was aber ein anderer Typ ist.

Gruß

Sebastian
 
Hallo Sebastian,

also es ist definitiv ein ATtiny 2313. Steht drauf, die Rechnung sagt das gleiche und die Chiperkennung auch.
Meine Definition sieht so aus:
Code:
$regfile = "ATtiny2313.dat"
' Define serial communication parameters
$baud = 1200
$crystal = 9830400
Trotz mehrerer Versuche ändert sich daran nichts. Das Register lässt sich weder mit
Set Ucsrb , Rxen = 0 noch mit
Ucsrb = Ucsrb And &B11101111
beeinflussen. Im Simulator taucht das Register wie gesagt nicht auf.
Ich habe allerdings noch Bascom 1.11.8.3 im Einsatz. Die Version hat ich bisher noch nicht enttäuscht.
Kann es eventuell daran liegen? Oder vielleicht die attiny2313.dat Konfig?
Oder besser, kann ich das Register bzw. das Bit auch anders beeinflussen?

Danke und Gruß

Poeler
 
Du solltest auf eine aktuelle Version (2.0.7.2) updaten.
Gibt es einen Grund, dass dies nicht geht?
In der Zwischenzeit sind jede Menge Features dazugekommen. Kollegen, die dir helfen wollen, werden immer wieder über diesen Umstand stolpern.

Grüße

Sebastian
 
Hallo Sebastian,

jetzt ist klar, das es eine gute Idee war, hier zu fragen. Du hattest Recht mit der Version.
Nach dem Update kann ich das Register beschreiben und das Unterdrücken des Interrupts klappt auch.
Allerdings muss ich ein paar ms Verzögerung einbauen, sonst wird er doch noch ausgelöst. Habe ich noch nicht ganz verstanden.

Senden:
Reset Led2 'Sendequittung
Ucsrb = Ucsrb And &B11101111 'Beim Senden RxD disablen
For I = 1 To 26 '26 Bytes aus EPROM holen und senden
Readeeprom J , I
Print Chr(j)
Next I
Waitms 50
Ucsrb = Ucsrb Or &B00010000
Set Led2
Return

Wo ist denn der "Code" Tag hin?
So komme ich erstmal weiter und kann in den nächsten Tagen mal die Qualität der Kommunikation über das Stromnetz testen.

Danke und Gruß

Poeler
 
Allerdings muss ich ein paar ms Verzögerung einbauen, sonst wird er doch noch ausgelöst. Habe ich noch nicht ganz verstanden.

Hallo Poeler,
es kann sein, dass dies durch dein
Print CHR(J)
kommt. Bascom schickt nach dem Zeichen noch ein CR und ein LF, wenn du das nicht explizit unterbunden hast.
Schreib hinter den Print Befehl mal versuchsweise ein ;
Das verhindert die beiden Zeichen. Nimm dann mal die Verzögerung raus und schaue, was passiert.

Grüße

Sebastian
 
Hallo Sebastian,

das ";" ändert nichts. Ich brauche immer noch mindestens 20ms.
Sicher bin ich mir zwar nicht, aber für mich sieht es so aus, als ob das letzte Byte wegen der geringen Baudrate noch nicht komplett gesendet ist, wenn ich den Interrupt wieder aktiviere. So richtig störend ist das zwar nicht, wäre aber doch gut zu wissen, was da genau passiert. Ich nehme mir nochmal das Datasheet vor und mache ein paar Versuche.
Danke erstmal, ich melde mich spätestens, wenn ich Ergebnisse bezüglich der Übertragungsqualität über das Lichtnetz habe. Ist sicherlich für den einen oder anderen interessant.

Gruß

Horst

P.S. Der Code Tag ist auch wieder aufgetaucht. War letztens doch schon etwas spät.
 
Guten Abend zusammen,

in den letzten Tagen habe ich trotz knapper Zeit mal ein wenig rumprobiert.
Erstmal habe ich per MAX232 eine Möglichkeit geschaffen, die gesendeten und empfangenen Daten im Terminal auszugeben. Das Debugging mittels LED ist doch etwas kontraproduktiv.
Jetzt ist auch klar zu erkennen, dass das ";" ein CR / LF hinter jedem Byte unterdrückt.
Dann habe ich festgestellt, das das UCSRB Register nicht direkt manipulierbar ist, also erst lesen, dann manipuliern und wieder zurückschreiben. Das Senden mit ein / ausschalten des RXD Interrupts klappt jetzt zuverlässig.

Allerdings habe ich noch immer Probleme, die empfangenen Bytes in ein Array zu schreiben. Die Quittung, die vom Empfänger zurück an den Sender geschickt wird, enthält nur 24 Nullen. Gelegentlich verschluckt sich der Empfänger auch und sendet wesentlich mehr Zeichen zurück. Ich finde einfach den Fehler nicht. Ich hänge die relevanten Programmteile mal an:
Code:
---------Hauptprogramm---------------
If Modus = 1 Then
    Reset Led1                                              'Automatik Sendemodus
   If Hundertstel >= 250 Then                               '250*20 ms= 5 Sekundentakt
      Hundertstel = 0
      Waitforanswer = 1                                     'Merker zum Verhindern einer endlos loop
      Gosub Eepromread                                      '24 Bytes aus EEPEOM lesen
      Set Led1                                              'Sendequittung
      Gosub Senden                                          'Unterprogramm Senden
      Reset Led1
   End If
Else
 Set Led1
End If

If K >= 5 Then                                              'LED für INT zurücksetzen
 Set Led3
 K = 0
End If

If Modus = 0 Then                                           'Antwort senden, nur wenn Empfänger (Modus=0)
   If Temp2 >= 24 Then                                      '24 Byte empfangen
      Temp2 = 0                                             'Zähler zurücksetzen
      Wait 2                                                'Nach 2 Sekunden Quittung senden
      Swap B(6) , B(8)                                      'Swap SAB1 <-> DAB1 and SAB2 <-> DAB2 address bytes
      Swap B(5) , B(7)                                      'Sender / Empfängeradresse vertauschen
      Gosub Senden                                          'Quittung senden
   End If
End If
----------Unterprogramme--------------
Onrxd:                                                      'INT wenn Byte empfangen
K = 0
Reset Led3                                                  'Empfangsquittung
Temp1 = Udr                                                 'Byte auslesen
Incr Temp2                                                  'Zähler hochzählen
If Ucsra.rxc = 1 Then
    B(temp2) = Temp1                                        'Nächstes Byte Ins Array
End If
Onrxdret:
Return                                                      'All 26 bytes of protocol in B(i) array

Timer_irq:                                                  '10ms
   Hundertstel = Hundertstel + 1
   J = J + 1                                                'Zähler für Sende LED
   K = K + 1                                                'Zähler für Empfangs LED
   Timer0 = Reload
Return

Eepromread:
For L = 1 To 24                                             '24 Bytes aus EPROM holen und senden (ohne CRC)
   Readeeprom B(l) , L
Next L
Return

Senden:
Reset Led2                                                  'Sendequittung
Temp1 = Ucsrb
Temp1 = Temp1 And &B11101111                                'Beim Senden RxD disablen
Ucsrb = Temp1                                               'Register erlaubt keine Rechenoperationen !!!!
For L = 1 To 24                                             '26 Bytes senden incl. CRC
   Print B(l);
Next L
Waitms 50
Temp1 = Temp1 Or &B00010000
Ucsrb = Temp1
Set Led2
Return

Modus 0 = Empfänger bzw. Modus 1 = Sender wird per Taster gesetzt. Außerdem kann per Taster auch einmalig manuell gesendet werden. Diese Routinen habe ich nicht mit reinkopiert. Es gibt aber keine Überschneidung von Variablen.

Und noch etwas: Die 50 ms beim Senden muss ich einbauen, andernfalls zeigt die INT LED an, das der Onrxd Interrupt noch kommt. Woran kann denn das liegen? CR und LF sind ja jetzt per ";" abgeschaltet.

Ich würde mich über ein paar Tipps freuen.

Schönen Abend noch,

Gruß

Poeler
 
Hallo,

Dann habe ich festgestellt, das das UCSRB Register nicht direkt manipulierbar ist, also erst lesen, dann manipuliern und wieder zurückschreiben. Das Senden mit ein / ausschalten des RXD Interrupts klappt jetzt zuverlässig.
Code:
Temp1 = Ucsrb
Temp1 = Temp1 And &B11101111                                'Beim Senden RxD disablen
Ucsrb = Temp1                                               'Register erlaubt keine Rechenoperationen !!!!
...
Temp1 = Temp1 Or &B00010000
Ucsrb = Temp1
das bezweifle ich jetzt mal. Beim Tiny2313 ist das UCSRB im IO-Bereich und sollte darum auch direkt auf Bitebene manipulierbar sein. Man sollte also genau so wie deine LEDs das RxD-Bit im Register an und ausschalten können. Probier es mal aus.

Die Register PINA, PORTA, DDRA, PIND, PORTD, DDRD, ... liegen ja auch im IO-Bereich und lassen sich auf Bitebene manipulieren.

So wie du es machst geht es auch. Aber über Bit-Set/Bit-Clear Befehle sollte es einfacher und Resourcenschonender gehen.

Gruß
Dino
 
Hallo Dino,

gerade habe ich es nochmal probiert. Du hast recht.
Operationen wie Ucsrb = Ucsrb Or &B00010000 funktionieren.
Vielleicht bin ich wegen des 50ms Problems in der gleichen Subroutine darüber gestolpert.
Hast Du vielleicht einen Ansatz, woran das liegen kann? 25ms Verzögerung reichen übrigens auch.
Wenn ich die Verzögerung aber ganz weg lasse, signalisiert mir LED3 einen Interrupt.

Gruß

Poeler
 
Hallo Poeler,
wenn ich einzelne Bits der Register setzen möchte, dann mache ich das normalerweise so:
UCSRB.RXEN = 1
Die Bit-Nummern sind von Bascom alle als Konstanten angelegt, genau so, wie von Atmel vorgegeben.
Das liest sich viel einfacher und man muss nicht erst überlegen und nachschlagen, was wohl dies bedeuten soll:
Ucsrb = Ucsrb Or &B00010000.

Dein Echo des gesendeten Bytes kommt vom TDA. Der empfängt das Signal natürlich sofort wieder und gibt es an den Controller weiter. Da er nur 600 oder 1200 Baud macht, dauert das seine Zeit.
Ich sehe im Datenblatt auch keine Möglichkeit, den Empfang zu unterdrücken. Es steht dort, dass die Verstärkung auf -6db zurückgenommen wird, aber das scheint noch immer zu reichen, um das Signal wieder zu empfangen.
Welche Schaltung aus dem Datenblatt hast du eigentlich realisiert?

Gruß

Sebastian
 
Hi,

wenn ich einzelne Bits der Register setzen möchte, dann mache ich das normalerweise so:
UCSRB.RXEN = 1
Die Bit-Nummern sind von Bascom alle als Konstanten angelegt, genau so, wie von Atmel vorgegeben.
Das liest sich viel einfacher und man muss nicht erst überlegen und nachschlagen, was wohl dies bedeuten soll:
Ucsrb = Ucsrb Or &B00010000.
so kann man es auch machen. Ich hab es eher so gedacht:
SET UCSRB.RXEN
RESET UCSRB.RXEN

Das ist aber ein wenig Geschmackssache. Im Assemblercode läuft das aber dann auf ein kleines popeliges ...
sbi UCSRB,RXEN
cbi UCSRB,RXEN

... raus. Das ist wesentlich kürzer als wenn man erst das IO-Register in eine Variable laden muß, dann die Variable mit einem Wert logisch verknüpfen und danach wieder zurückspeichern. Das wäre dann mindestens die 3fache Länge. Eher mehr weil die Variablen bei Bascom glaube ich über Indexregister im Speicher angesprochen werden. Also würde ich bei Bascom mit dem ganzen Overhead von der etwa 10-15fachen Länge ausgehen.

Was über komplizierte Programmierung ...
Negative Zahlen mal umständlich
... viel Spaß beim lesen ;)

Gruß
Dino
 
Hallo Dino und Sebastian,

erstmal, die Schaltung entspricht der Fig. 19 des Datenblatts.
Eure Anregung zum setzen / resetten der Bits habe ich übernommen.
Bisher habe ich einzelne Bits eigentlich nur an den I/O Ports manipuliert.
Wie oben gesagt, hat das Doppelproblem mit der Verzögerung den Blick wohl getrübt.
Ich lag mit dem Verdacht für den Grund der Verzögerung offensichtlich so halbrichtig, konnte es aber nicht erklären.
Danke für die Bestätigung.
Wenn es so weiter geht, kann ich am nächsten Wochenende mal ans Hausnetz gehen und die Übertragungsqualität testen.
Langsam bekomme ich Respekt vor der seriellen Übertragung.
Danke bis dahin.

Gruß

Horst
 

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)