Was an sich meine erste Vermutung dann bestätigen würde...
nämlich das die abarbeitung zu schnell abläuft und das nächste zeichen noch garnicht im Buff vorliegt.
Wenn das dann so stimmt weiss ich ja, wo ich ansetzen muss...
Eine Wartezeit wie ein Waitus 2000 sollte nicht im Interrupts sein. Auch die Ausgabe auf das LCD ist ggf. ein Problem, auch wenn das wohl eher eine HIlfe zur Fehlersuche ist. So wie es jetzt gemacht ist, wird die Wartezeit gebraucht damit in der Zeit die zur Verarbeitung von 1 byte schon das Nächste byte ankommt. Entsprechend sollte die Wartezeit zusammen mit der Laufzeit auf die Bautrate abgestimmt sein. Dabei kann der recht langsame LCD Befehl ggf. die extra Wartezeit auch ganz ersetzen, was vor allem Zeigt das man LCD(...) in der ISR vermeiden sollte.
Die Interrupt Routine sollte so schnell sein, das immer nur 1 Byte verarbeitet wird - die while Schleife ist also eigentlich überflüssig. Damit muss natürlich dann auch die Abfrage auf das vorzeitige Ende eines Datenblocks anders gelöst werden, z.B. in die IF Abfrage mit ASC(endzeichen).
Was an sich meine erste Vermutung dann bestätigen würde...
nämlich das die abarbeitung zu schnell abläuft und das nächste zeichen noch garnicht im Buff vorliegt.
Wenn das dann so stimmt weiss ich ja, wo ich ansetzen muss...
JAAAA... Microchips kann man essen... aber der Geschmack ist furchtbar.
Da ist auch ein Wait 1 in der isr...
So würde ich es wohl probieren: (ungetestet, da nur Laptop hier und keine Hardware)
Code:'------------------------------------------------------------------------------- '------------------------------------------------------------------------------- '------------------------------------------------------------------------------- 'Programmname: UART-Schnittstelle.bas 'Letzte Änderung: 03.03.2013 'Funktion: Empfang von gesamt 18Byte, ' ausgabe als echo über seriell und lcd zur kontrolle 'Mikrocontroller: Mega8 ' 'Input: 'Output: '------------------------------------------------------------------------------- '------------------------------------------------------------------------------- '------------------------------------------------------------------------------- 'Den Atmega mit den passenden Daten füttern. '------------------------------------------------------------------------------- $regfile = "m8def.dat" 'eingesetzter Mikrocontroller $crystal = 8000000 'eingestellte Taktfrequenz (8MHz) $hwstack = 40 'Standardwert $swstack = 40 'Standardwert $framesize = 20 'Standardwert $baud = 9600 '------------------------------------------------------------------------------- 'Ports/Pins/Configs '------------------------------------------------------------------------------- '------------------------------------------------------------------------------- 'Timer/OCR/PWM/ISR usw. setzen '------------------------------------------------------------------------------- Config Lcdpin = Pin , Db4 = Portd.4 , Db5 = Portd.5 , Db6 = Portd.6 , Db7 = Portd.7 , E = Portd.3 , Rs = Portd.2 Config Lcd = 16 * 2 Config Serialin = Buffered , Size = 18 Enable Interrupts '------------------------------------------------------------------------------- 'Variablen '------------------------------------------------------------------------------- Dim Temp_byte As Byte Dim Datenblock(16) As Byte Dim Indexposition As Byte Const Startzeichen = 123 Const Endzeichen = 125 Const Datenblock_laenge = 16 Dim Datenblock_komplett As Bit Dim Lcd_position As Byte Dim Datenblock_string As String * 16 Dim Datenblock_byte(16) As Byte At Datenblock_string Overlay '------------------------------------------------------------------------------- 'Hauptprogramm '------------------------------------------------------------------------------- Cls Waitms 100 Do If Ischarwaiting() = 1 Then Gosub Empfangen End If If Datenblock_komplett = 1 Then Reset Datenblock_komplett Gosub Anzeige End If Loop End Anzeige: Cls Waitms 100 For Indexposition = 1 To 3 Step 1 Lcd_position = Indexposition Locate 1 , Lcd_position Lcd Chr(datenblock(indexposition)) Next For Indexposition = 3 To Datenblock_laenge Step 1 Lcd_position = Indexposition - 8 Locate 2 , Lcd_position Lcd Chr(datenblock(indexposition)) Next 'Echo zurücksenden zur Kontrolle Print Datenblock_string Return Empfangen: Temp_byte = Inkey() If Temp_byte > 12 Then 'unter 13 sind nur Sonderzeichen If Temp_byte = Startzeichen Then Indexposition = 0 Elseif Temp_byte = Endzeichen Then Gosub Auswerten Else Incr Indexposition Datenblock(indexposition) = Temp_byte End If If Indexposition = Datenblock_laenge Then Gosub Auswerten End If End If Return Auswerten: Dim Dummy As Byte Datenblock_string = String(datenblock_laenge , 0) Dummy = Memcopy(datenblock(1) , Datenblock_byte(1) , Indexposition) Datenblock(1) = String(datenblock_laenge , 22) 'Wozu? Indexposition = 0 Set Datenblock_komplett Return
Wenn das Herz involviert ist, steht die Logik außen vor! \/
Als erstes danke ich euch mal für eure Mühe...
und natürlich auch für den vorgelegten Code.
das...
War dazu gedacht, das ich auch kurze Messages senden kann und der rest mit "lückenfüller" neutralisiert wird.Datenblock(1) = String(datenblock_laenge , 22) 'Wozu?
Hab den Code von dir versucht... bis auf die Ausgabe auf lcd ist das anscheinend funktionierend.
Wobei das LCD eh nur für Testzwecke dranhängt bis die Komunikation fehlerlos steht.
Das LCD ist aber schnell angepasst.
Was mir gedanken macht daran... sollte aus irgendeinem Grund 2 oder mehr Datenblöcke kurz nacheinander gesendet werden
und das hauptprogramm hatte noch keine zeit den Buffer auszulesen...
Wird dann alles, was zuviel gesendet wird einfach verworfen ?
Dann sollte ich mir sozusagen ein "manuelles handshake" einbauen... das die pc-software weiss,
wann der client wieder empfangsbereit ist.
Das war der ursprüngliche grund, weshalb ich den Buffer "so schnell wie möglich" auslesen wollte mit der ISR.
JAAAA... Microchips kann man essen... aber der Geschmack ist furchtbar.
Wie schon gesagt, das ganze Konzept ist kompletter Käse, Du hast das Prinzip Interrupt-gesteuerter Verarbeitung überhaupt nicht verstanden.
Der BYTEMATCH ist normalerweise dafür vorgesehen, das Ende einer Übertragung zu erkennen. Es ist nicht dafür gedacht den Anfang zu erkennen und dann solange in der ISR rumzurödeln und alles andere zu blockieren, bis man die Zeichenkette empfangen hat. Wofür soll dann der gepufferte Empfang überhaupt noch gut sein?
Das hier ist jetzt in ein paar Minuten entstanden und sollte eigentlich funktionieren. "Eigentlich", weil nicht auf Hardware getestet, aber vielleicht siehst Du die Idee.
Code:$regfile = "m8def.dat" $crystal = 8000000 $hwstack = 100 $swstack = 100 $framesize = 100 $baud = 9600 Const block_wait = 0 Const block_receive = 1 Const block_length = 16 Const False = 0 Const True = 1 Dim rx_state As Byte Dim buff(block_length) As Byte Dim data_block(block_length) As Byte Dim db_index As Byte Dim rcvd_char As Byte Dim rcv_complete As Bit Dim tmp As Byte rx_state = block_wait db_index = 0 rcv_complete = False On URXC UART_Get_Char Enable URXC Enable Interrupts Do If rcv_complete = True Then Printbin data_block(1) rcv_complete = False End If Loop UART_Get_Char: rcvd_char = UDR Select Case rx_state Case block_wait: If rcvd_char = "{" Then rx_state = block_receive Case block_receive: If rcvd_char <> "}" Then If db_index < block_length Then Incr db_index buff(db_index) = rcvd_char Else db_index = 0 rx_state = block_wait End If Else If db_index > 0 Then tmp = memcopy(buff(1) , data_block(1) , db_index) rcv_complete = True End If db_index = 0 rx_state = block_wait End If End Select Return
Bei 9600 Baud und 8 MHz langweilt der sich zwischendurch. Da geht normal nichts verloren. Wenn du aus der Hauptschleife Subs aufrufst, welche lange Pausen beinhalten, oder die Pausen gar in die Hauptschleife legst, dann besteht die Gefahr, dass der Buffer überläuft. Ich teste die Geschwindigleit meiner Programme gern mit einem blinkenden Herz auf dem LCD. Alle 1000 Durchläufe wird das Herz dargestellt oder ausgeblendet. Selbst meine umfangreichen Projekte kommen da gefühlt auf 1000 Durchläufe die Sekunde. Handshaking nutze ich selbstgemacht. Wenn der Raspberry was zum AVR schickt, dann wird eine Antwort passend zum gesendeten erwartet. Kommt diese, aus welchen Gründen auch immer, nicht, dann wird das zuletzt gesendete wiederholt. Da beißt sich auch nichts. Mein Protokoll berücksichtigt auch bereits gestartete Übertragungen, z.B. wenn die Fernbedienung oder eine Taste am Gerät "was zu melden hat".
Ich sende dafür nicht aus jeder Sub direkt per print, sondern schreibe die Daten in einen Sendepuffer. Jeder Durchgang der Hauptschleife ruft eine Sub auf, welche prüft, ob es was zu senden gibt und sendet dann chronologisch nach FIFO art. Der Raspberry macht es ähnlich. Da nutze ich zum Senden ein eigenes C-Programm, welches prüft, ob es evtl. schon in einer anderen Instanz läuft und falls ja, wird eine Pause eingelegt. Meine Tests mit 100 "gleichzeitigen" Aufrufen liefen fehlerfrei. Soviel kommen in der Realität aber gar nicht vor.
Wenn das Herz involviert ist, steht die Logik außen vor! \/
... und genau das hatte ich anfangs komplett falsch eingeschätzt.Bei 9600 Baud und 8 MHz langweilt der sich zwischendurch
ich war erst der meinung, "die paar" Zeichen liegen schon im Buff, bis die erste schleife der isr durch ist. *blöderweise
Ist aber ne bekannte schwäche bei mir. *lach
Wenn man dann das Geschwindigkeitsproblem betrachtet ist auch ganz klar das Bytematch
(wie MagicWSmoke sagte) genau in eine andere Richtung "korrekt" verwendet werden muss.
Der Ansatz, es über Bytematch zu lösen ist an sich nicht schlecht... aber ich muss erst den Buffer füllen lassen...
und danach erst das Auslesen beginnen.
Ich finds aber immerwieder schön was zu lernen. Am besten passiert das natürlich aus eigenen Fehlern
Wo ich gerade bei Bytematch bin...
Was ist der Sinn dahinter, das man Register per Pushall behandeln muss bei Verwendung von Bytematch ?
Ich konnte das aus der Bascom-hilfe nicht wirklich erkennen.
Auch konnte ich nicht finden, welche register denn wirklich dafür verwendet werden.
Wäre schön, wenn da jemand knappe Infos oder nen Link hätte damit ich das nachlesen kann.
JAAAA... Microchips kann man essen... aber der Geschmack ist furchtbar.
Die Serialcharmatch ist nichts anderes als die Verlängerung des URXC-Interrupts. Zuerst schreibt Bascom das angekommene Byte in den Puffer, danach wird Serialcharmatch ausgeführt. Bascom sichert für den URXC seine im Interrupt verwendeten Register, aber nicht solche aus Usercode. Wird ASM benutzt, dann ist's sehr einfach, die Register sind dann bekannt, bei Basic-Code eher weniger, dann müsste man alle verwendeten Register in Erfahrung bringen und diese sichern, das Erkennen ist eher schwierig. Deshalb der Rat zu Pushall/Popall.
OK. das ist also...
Empfang (urxc) -> Buffer -> auf Byte/Char-match kontrollieren durch den MC (interne ISR) -> erst bei Treffer in die "User"-ISR springen
... aber ist mir noch nicht ganz verständlich aus welchem Grund die Register dazu gesichert werden müssen.
Würde es sonst zu Überschneidungen kommen beim Empfangsbuffer während intern die routine abläuft ?
JAAAA... Microchips kann man essen... aber der Geschmack ist furchtbar.
Weil jeder Interrupt, auch der URXC, mitten im normalen Code unterbrechen kann, müssen alle von einer Interruptroutine veränderten Register gesichert werden, sonst gibt's Verhau.
Der Code für den gepufferten Empfang macht das für die von ihm veränderten Register. Sobald aber User-Code in diese URXC mit "eingehängt" wird, können weitere Register verändert werden.
Lesezeichen