Forum: Mikrocontroller und Digitale Elektronik Interrupt "ON rxd" in Bascom


von Axel K. (axel)


Lesenswert?

Hallo!

Ich habe folgendes Problem.

Ich sende eine Zahl (4 stellig) als string mit vorangestellten "g" 
(falls weniger als 4 stellen wird mit Nullen voran aufgefüllt) an einem 
anderen mc (Beides Atmega8) Der 2.MC nimmt dann das was er empfängt und 
hängt das einer vorhandenen String Variable an.
In der Hauptschleife wird dann gewartet bis die Anzahl der Zeichen im 
"empfangen String" auf über 10 angewachsen ist. Dann sucht er mit der 
instr- Funktion nach "g" und weiß, aha ab hier muss ich 4 stellen 
abschneiden und hab dann meine Zahl.

Das Problem ist, das er durch das ganze abfragen und hantieren mit 
Stringvariablen sehr viel ressourcen braucht, was dazu führt, dass er 
nach unbestimmter Zeitdauer sich aufhängt)

Habt ihr eine Idee, wie ich das Verfahren optimieren könnte?

Wenn ich zb ein 4 stellige zahl sende, wird dann beim empfänger IC nur 
einmal der Interrupt ausgelöst, oder etwa pro empfangendes Byte?  Dann 
könnte ich nähmlich gleich in der onrxd interrupt schleife die zahl in 
einer variablen abspeichen ohne in der hauptschleife ständig zu pollen.

viele Grüße
Axel

von Gast (Gast)


Lesenswert?

Wenn du sicherstellen kannst, dass z.B. ein CR nicht in deinem zu 
übertragenden String vorkommt, würde ich so ein Zeichen als Abschluss 
des Telegramms schicken, noch hinter einer Checksum, wenn du so etwas 
brauchst.
Wenn du dann noch einen Hardware UART benutzt, kannst du in Bascom den 
Bytematch Interrupt verwenden.
Du brauchst dann gar nicht zu pollen sondern liest die Zeichen alle 
zusammen aus dem Buffer ein. Das behindert den Rest deines Programms 
fast gar nicht.

Gruß

Rolf

von D. S. (jasmin)


Lesenswert?

sorry, aber das hört sich doch recht suboptimal / konzeptlos an.

das läßt sich alles sauber und ohne jegliche ressourcenprobleme über 
interrupts lösen.

in der bascom hilfe stehen schon komplette lösungen drin.
sehr elegant auch das, sollte sofort so funktionieren :


'0011.BAS: Optimierter String-Empfang
$Regfile = "2313def.dat"
$Crystal = 3686400
$Baud    = 9600

Dim s As String*4 At &H60
Dim b(5) As Byte At &H60 Overlay
Dim n As Byte

On URXC OnRxD
Enable URXC
Enable Interrupts

Main:
  If n > 4 Then
    Print s
    n = 0
  End If
Goto Main

OnRxD:
  Incr n
  b(n) = UDR
Return

von Axel K. (axel)


Lesenswert?

Hallo!

Dietmar, ich verwende ja bereits einen Interrupt dafür. Aber beide 
Beiträge waren dennch hilfreich -  wenn ich abfrage IF n größer 4, kann 
ich ja nicht ausschließen, das irgendwas falsch übertragen wurde etc. 
Also muss ich schon noch son Abschlusszeichen nehmen. Ich probiere das 
mal mit dem Bytematch, den kannte  ich noch garnicht)) Dann spare ich 
mir ständig das mit der Stringlänge.

Kann man einfach Bytematch und dann den "buchstaben" (Abschluss vom 
telegramm) oder muss der Buchstabe als Asci stehen?

Danke Danke!

von Gast (Gast)


Lesenswert?

Schau dir mal die Hilfe zu "Config Serialin" an.
Unter Bytematch steht, dass dort der ASCII Wert angegeben werden muss, 
der den Interrupt auslöst.

Gruß

Rolf

von D. S. (jasmin)


Lesenswert?

@ axel,


du kannst doch in der isr einfach abfragen ob das endezeichen angekommen 
ist, oder dein startzeichen, oder in kombination.
Wenn du auch noch überprüfen willst ob auch alles richtig übertragen 
wurde dann musst du eh noch mit crs 's arbeiten, was aber auch nicht 100 
% ig sicher ist und auch codeanpassungen auf der senderseite 
durchführen, falls das überhaupt möglich ist..

Bleib bei dem aufbau wie in meinem beispiel, damit hst du alles unter 
kontrolle und nutzt die controllermöglichkeiten und ressourcen optimal 
aus !

von Axel K. (axel)


Lesenswert?

Dietmar S. wrote:
> sorry, aber das hört sich doch recht suboptimal / konzeptlos an.
>
> das läßt sich alles sauber und ohne jegliche ressourcenprobleme über
> interrupts lösen.
>
> in der bascom hilfe stehen schon komplette lösungen drin.
> sehr elegant auch das, sollte sofort so funktionieren :
>
>
> '0011.BAS: Optimierter String-Empfang
> $Regfile = "2313def.dat"
> $Crystal = 3686400
> $Baud    = 9600
>
> Dim s As String*4 At &H60
> Dim b(5) As Byte At &H60 Overlay
> Dim n As Byte
>
> On URXC OnRxD
> Enable URXC
> Enable Interrupts
>
> Main:
>   If n > 4 Then
>     Print s
>     n = 0
>   End If
> Goto Main
>
> OnRxD:
>   Incr n
>   b(n) = UDR
> Return


So ich habe jetzt ewig hin und her probiert.

Wenn ich s und b() so deklariere, dann bekomme ich eine Fehlermeldung - 
hab ich nicht mehr genau im kopf, aber irgendwas mit besetzt. Woran 
könnte das liegen? Aber mit dem Overlay, das sieht in der Tat ziemlich 
ressourcensparend aus. Das ist ja ziemlich raffiniert mit dem byte ins 
Stringformat  - sonst kannte ich das nur mit dem befehl chr().

Das Ding ist, ich gebe die werte mit dem IC per Multiplexing auf 7 
segment anzeigen aus - und wenn der Codeteil zu lang wird, dann leuchten 
sekundlich mal segmente, die garnicht leuchten sollen. Müsste ich nicht 
zwingend die 2 ms waitms einlegen nach jedem bitmuster, hätte ich das 
problem vielleicht garnicht((    Es lief ja schon, nur ich musste eine 
einzige If-Anweisung in der Hauptschleife hinzufügen und das war schon 
zuviel des guten..

von Axel K. (axel)


Lesenswert?

ah ok  mit dem overlay das klappt jetzt   ich meld mich mal übermorgen 
wie es aussieht

gruss axel

von Gast (Gast)


Lesenswert?

Hallo Axel,
Overlays sind eine gute Art, die aufwändigen String Operationen zu 
vermeiden. Aber nicht so:
Dim s As String*4 At &H60
Dim b(5) As Byte At &H60 Overlay

Du hast ein Problem schon gesehen: Bascom geht die Dim Befehle der Reihe 
nach durch und setzt die Variablen beginnend am Anfang in den Speicher. 
Wo das ist, hängt von dem µC Typ ab. beim 2313 ist es tatsächlich die 
Adresse Hex60. Bei anderen Controllern ist der Start woanders. Daher 
nimmt man nie feste Werte.
Es geht auch so:

Dim s As String*4
Dim b(5) As Byte At s Overlay

und schon hast du keine Probleme mehr mit der Reihenfolge der Variablen 
im Speicher. Und du kannst dein Programm jederzeit für andere Hardware 
ohne Fehler compilieren lassen.

Wenn du Dietmars Anweisung folgst, wird der Interrupt bei jedem 
eintreffenden Zeichen auf RxD ausgelöst und du musst jedesmal 
überprüfen, ob schon alle Zeichen eingetroffen sind. Nimmst du 
Bytematch, wird nur ein Interrupt ausgelöst und du weißt, dass sie alle 
da sein müssen.
Aber mach es so, wie du es willst.

Gruß

Rolf

von Axel Krüger (Gast)


Lesenswert?

Guten Abend)

Ich habe schon Überlegungen zu dem Bytematch-Befehl angestellt und etwas 
herumprobiert.

Wie können die Daten bei dem Gebrauch der bytematch Funktion am 
effektivsten aus dem Puffer geholt und gespeichert werden? Kann man eine 
Variable auch in diesem Fall via overlay zb auf die Specherstellen des 
UART Puffers legen? Aber selbst dann entfällt zwar das Polling, aber ich 
müsste den string ja trotzdem mit instr() durchsuchen um die position zu 
erfahren um dann mit dem mid() Befehl die 3 Zeichen davor einzeln 
herauszutrennen. Man könnte vielleicht auch alles aus dem empfangspuffer 
löschen und beim Bytematch dann einfach die ersten 3 Zeichen 
entsprechend abspeichern.

Theoretisch , wozu es jedoch überaus sperrliche Informationen gibt, gibt 
es ja eben diesen Ringpuffer beim Uart und auch dafür schon festgelegte 
Variablen. _wpointer  soll angeblich die Zahl enthalten, an welcher 
Stelle die letzte Ziffer gespeichert wurde. Dabei zeigt er aber einen 
syntax Fehler an...die Auskunft in der Hilfe bzw. sogar über google ist 
sehr dürftig.

Dann müsste es doch gehen, wenn man bei Bytematch des Abschlusszeichens 
einfach in der Interrupt Routine die letzten 3 Speicherzellen davor 
ausliest und sofort in die dafür vorgesehenen variblen speichert, wobei 
das ja dem ähnlich wäre mit dem empfangspuffer löschen und beim 
Bytematch die ersten 3 Zeichen abspeichern.

gruss Axel

von Axel K. (axel)


Lesenswert?

so wie es aussieht funzt die variante - zumindesten kann ich das 
anzeigeflackern noch nicht feststellen

Der ankommende string sieht so aus: "018g"
Das array k steht für die einzelnen Ziffern der segmentanzeige.



Config Serialin = Buffered , Size = 20 , Bytematch = 103
Dim X4 As String * 20 At _rs232inbuf0 Overlay
Dim K(3) As String * 1

Serial0charmatch:

K(1) = Mid(x4 , 1 , 1)
K(2) = Mid(x4 , 2 , 1)
K(3) = Mid(x4 , 3 , 1)
Clear Serialin

Return


Danke für die Unterstützung!!

gruß Axel

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.