BASCOM Library mit ISR und Variablen

laplace

Mitglied
26. Nov. 2008
111
0
16
Kronach / Oberfranken
Sprachen
  1. BascomAVR
  2. Assembler
  3. Pascal
Eine BASCOM AVR-Library mit interner Variablenverwaltung und Interrupt Service Routine​

Ausgehend von der Fragestellung, wie man einen mit Carriage Return (CR = #13) und Linefeed (LF = #10) abgeschlossenen String in BASCOM über die COM Schnittstelle einlesen kann, möchte ich mal eine Lösung vorschlagen. In reinem Basic ist die Ausfilterung der Zeichen CR und LF zwar möglich, ist aber ein ganz schönes Gefummel.

Ich selbst löse Stringoperationen gern in Assembler, gerade auf dem Gebiet dieser Schnittstelle. Das steht folgende Philosophie dahinter:
Wenn ein (kleiner) Mikrocontroller mit einem PC kommuniziert, handelt es sich meist um Anweisungen vom PC an den Mikrocontroller, dass dieser etwas tun (messen)- und das Ergebnis dann zurückschicken soll. Die Aufgabe ist daher recht überschaubar wobei Steueranweisungen und Ergebnis in der Regel sehr kurze „Zeichenketten“ sind. Zur Übermittlung der Daten stehen prinzipiell 2 Wege zur Verfügung:

1. Als Binärdaten
2. Als ASCII-String terminiert mit einem Terminator (z.B. CR oder CRLF)

Die erste Methode erscheint schneller hat aber 2 gewaltige Nachteile: zum einen müssen Anweisung und Antwort immer eine bestimmte, festgelegte Länge haben (ich kann ja die Länge nicht erkennen), zum anderen kann ich die Binärdaten weder unmittelbar darstellen, noch lesen noch direkt in einer Datei speichern.
Die zweite Methode zeigt diese Nachteile nicht, im Gegenteil: die Daten können nicht nur unterschiedlich lang sein sondern wenn ich sie mit CR (oder besser gleich mit CRLF) terminiere, könnte ich sie direkt in eine Datei wegschreiben. Der Geschwindigkeitsnachteil durch die Formatierung und die höhere Anzahl an zu übertragenden Zeichen ist für mich von untergeordneter Bedeutung.

Zur Kommunikation mit dem Mikrocontroller brauche ich also 2 Routinen auf Mikrocontrollerseite:

• Eine Routine, die im Hintergrund (Interrupt) einen Kommandostring einliest, mir anzeigt wenn das Ende (CR) erreicht ist und ein eventuell vorhandenes LF herausfiltert. Bequem wäre es noch, wenn sich die Routine – sobald sie erkennt, dass ein Kommando anliegt – ohne „Hang-up“ selber blockiert, bis das Kommando an „höhere Stelle“ weitergeleitet wurde.
• Eine zweite Routine, die einen String an den PC schickt und ihn automatisch mit CRLF terminiert.

Im Prinzip geht beides auch in BASIC. Die erste Routine ist wie schon gesagt recht „unwuchtig“ zu realisieren, die zweite Aufgabe, das Senden des Strings, geht aber recht angenehm von Basic aus mittels des Befehls „Print“. Ich hab‘ trotzdem eine eigene Routine implementiert. Na ja, ich hab‘ mir gedacht „wenn schon, denn schon“ und so entsteht ein „abgeschlossenes System“. Die Routine(n), die ich gleich vorstellen möchte, sind sehr schlank (das Demoprogramm hat so 384 Byte) und arbeiten ebenfalls mit Basic.
Wie schon in der Überschrift angedeutet, habe ich diese Problemstellung durch Erstellen einer BASCOM-Library gelöst. Das Besondere an dieser Library ist, dass sie neben der Einbindung der Interrupt Service Routine für den USART-Empfang auch eine Verwaltung/Einbindung von BASCOM Variablen in die Library selbst hat. Beide Features habe ich bisher im Netz nicht gefunden; ich habe deshalb die wesentlichen Dateien in einer ZIP-Datei zusammen gepackt, dass man die einzelnen Schritte bzw. die Vorgehensweise, wie so etwas implementiert wird, auch nachvollziehen kann

In der ZIP-Datei sind folgende Dateien enthalten:

• _firstlib.lib : BASCOM Library (Quelldatei)
• _firstlib.lbx : Vorcompilierte Library Datei
• libtest.bas : Demo-/Testprogramm für die Library
• libtest.hex : HEX-Datei des Testprogramms
• libtest.asm : Re-/Disassemblat der HEX-Datei (mittels ReAVR erstellt). Ein Ein Re- oder Disassembler wie z.B. ReAVR erzeugt aus einem HEX-File wieder ein (lesbares) ASM-File. Wer ernsthaft überlegt, in die Assemblerprogrammierung einzusteigen, sollte sich diese Freeware zulegen und sich solche „Rück-Übersetzungen“ einmal anschauen. Solche Beispiele sind extrem lehrreich. Den Re-Assembler gibt’s wie gesagt als Freeware im Netz: http://avr.jassenbaum.de/ja-tools/reavr.html
• libtest_hex_Resassemblat.pdf : zum Teil kommentietes Reassemblat

Diese Dateien _firstlib.lib und _firstlib.lbx müssen in den Bascom-Library Ordner kopiert werden. Bei mir ist das: „C:\Users\ws\Programme\BASCOM-AVR\LIB“. Die letztere *.lbx-Datei kann auch in der BASCOM IDE mit dem LIB-Manager (zu finden unter „Werkzeuge“) aus der _firstlib.lib erstellt werden.

Als Hilfe bei der Erstellung der Library hatte ich im wesentlichen folgende Hilfsmittel:

• Das Kapitel „Mixing ASM and BASIC“ in der BASCOM-Hilfe
• Die Datei „mylib.lib“ (aus dem Library-Ordner) sowie andere Libraries im Ordner
• Ein recht guter Artikel zu dem Thema von den „Kollegen“ vom Roboternetz http://www.rn-wissen.de/index.php/Bascom_Libraries
• ... und viel Probieren

Die wahrscheinlich interessanteste Datei ist sicher die Library selbst (_firstlib.lib). Die Erstellung war mit Sicherheit auch ein Hauptteil der Arbeit. Ich möchte daher auch noch ein paar Kommentare dazu abgeben, vielleicht sind die hilfreich für eigene Projekte. Einige Kommentare habe ich auch in die Library selbst geschrieben.

• Die Library wird wohl von einer BASCOM-Utility übersetzt, die näher an Assembler ist als an BASCOM-Basic. So dürfen Konstanten nicht mit „Const“ sondern müssen mit „.equ“ definiert werden, genauso wie bei der symbolischen Registerdefinition die Assembler-Deklaration „.def“ anstelle der BASCOM „Alias“-Deklaration benutzt werden muss. Auch sind Kommentare nicht überall möglich und an manchen Stellen können Kommentare auch mit dem in Assembler üblichen Semikolon eingeleitet werden. Dieser Kommentarwirrwar hat mich doch schon einiges an Zeit gekostet.
• Zu Beginn, als meine Quell-Datei noch jede Menge Fehler enthielt, habe ich sie mit dem Lib-Manager precompiliert (die *.lbx Datei erstellt). Da kamen die groben Fehler mit einer (wenig informativen) Fehlermeldung auch zum Vorschein – allerdings konnte ich den Lib-Manager danach nur noch mit dem Windows Task-Manager schließen (= rauswerfen). Ansonsten gab’s keine Nebeneffekte. Also, beim Probieren lohnt es sich, den Task-Manager permanent offen zu halten. Nicht nur aufgrund diesen „bockigen Verhaltens“ glaube ich, dass das Erstellen von Libraries nicht unbedingt als Standard innerhalb BASCOM vorgesehen ist, sondern doch wohl eher zur Implementierung von speziellen, wohl eher kostenpflichtigen Erweiterungen. Da ist m.E. auch nichts gegen zu sagen. Hauptsache, die Möglichkeit der Erweiterung besteht.
• Wenn man *.lib und *.lbx Dateien vergleicht, kann man ein paar wichtige Prinzipien herausfinden. Ein Teil steht in der oben genannten Literaturstelle im Roboternetz. Im Prinzip kann man sagen, dass alles precompiliert (= im Voraus übersetzt) werden kann, dass keine Referenzen auf Konstanten oder Variablen enthält. Was vorcompiliert wird - z.B. push, pop, reine Registeroperationen ... - wird in ein OBJ-Statement (z.B. „.OBJ 93CF“) übersetzt, das dann offensichtlich den fertigen Maschinencode in ASCII-Form enthält.
• Für Statements, die Referenzen enthalten, muss am Beginn der Zeile ein „*“-Zeichen angegeben werden. Dadurch wird die Precompilierung verhindert und das Statement erst bei der Compilierung des kompletten Programms übersetzt, wenn diese Referenzen aufgelöst werden können. Da bei heutigen, schnellen PC’s kaum ein Geschwindigkeitsunterschied zu merken sein sollte, würde ich im Zweifelsfall lieber einmal einen „*“ mehr setzen als einen zu wenig. Dieser „Geschwindigkeitsnachteil“ würde allerdings so und so nur zum Tragen kommen, falls man die „*.lbx“ Datei anstelle der „*.lib“ Datei! Mit einem „einfachen *“ können so aber nur einfache Assemblerbefehle vor der „Precompilierung geschützt“ werden – also zum Beispiel das Laden einer Variablen (LDS register,{Varname}). Damit komme ich zum wichtigsten bzw. schwierigsten Punkt, dem Einbinden von Variablen.
• Die Routine einer Library wird ja erst in den Programmcode eingebunden, wenn die Routine tatsächlich gebraucht wird - und eingebunden wird der Code in den Flash-Speicher (ROM). In Assembler kann man zwar an beliebiger Stelle Variablen (RAM) einbinden, allerdings muss man dazu 4 Pseudobefehle einbinden, nämlich
• A.) .DSEG (Datensegment einschalten)
B.) Varname: (Label=Name der Variablen definieren)
C.) .BYTE 2 (Platz für 2 Byte reservieren)
D.) .CSEG (auf Codesegment zurückschalten)
Solch eine komplexe Einbindung war in BASCOM wohl nicht vorgesehen, nicht auf Assembler oder ähnlicher Ebene. Allerdings bin ich davon ausgegangen, dass so etwas wie das Einbinden von Variablen in eine Library möglich sein musste. Und es geht tatsächlich, durch das Voranstellen einer „*BASIC:“ Instruktion an den Anfang einer Zeile (siehe die Library). Hierdurch können offensichtlich (zumindest in rudimentärer Form) Basic- Operationen beim Einbinden einer Library in den Programmcode durchgeführt werden, z.B. die Deklaration von Variablen mittels „DIM“. Hier gibt’s ein paar „ungewohnte“ Einschränkungen. So können keine Arrays direkt indiziert- (wohl aber deklariert) werden oder Kommentare können in diesen Zeilen ebenfalls nicht angegeben werden.
• Die so definierten Variablen werden korrekt eingebunden -(bis auf ein 1-Byte Loch beim Übergang der normalen Variablen im BASCOM-Basic Teil der Variablen zu den Variablen im Library-Teil. Bei der Ausgabe der Variablen im Ergebnisreport tauchen die so definierten Variablen ebenfalls nicht auf. Dass die jedoch korrekt eingebunden und adressiert werden, kann man dem Reassemblat entnehmen.

Wie die Library eingebunden wird bzw. wie die neuen Funktionen aufgerufen werden, geht aus dem BASCOM-Beispielprogramm hervor.
Ich hoffe, der Eine oder andere kann etwas mit diesem post was anfangen. Würde mich freuen.

LG
Werner
 

Anhänge

  • BASCOM_Library.zip
    79,2 KB · Aufrufe: 114
Hi Werner,

sehr schön ... ;) da muß ich mich auch mal mit beschäftigen um BASCOM bei
ein paar Sachen etwas auf die Sprünge zu helfen :D

sehr schöner Beitrag ...

Gruß
Dino
 
Hallo Werner,

Deine Bibliothek gefällt mir auch sehr gut. Ich möchte sie in meinem nächsten Projekt mal einsetzen und mir genauer anschauen.

Ich finde es sehr schön wenn sich jemand die Mühe macht, seine Ideen und Wünsche in eine Library packt und diese anderen zur Verfügung stellt. Damit können wir weitere Unzulänglichkeiten der Hochsprache ausmerzen.

Danke und Grüße,
Markus
 
Hallo Werner,

gut dass du dich mit dem Thema beschäftigt hast, das hilft mir bestimmt weiter. Ich möchte demnächst einige C-Routinen in Assembler umschreiben und dies dann in eine Bascom-Lib integrieren. Ich hatte damit zwar schon einmal angefangen, aber es gab noch einige Fehlermeldungen von Bascom mit denen ich nichts anfangen konnte :rolleyes: Ich nehme mal dann deine Lösung als Vorlage und schaue wie du die Parameter übergibst und mit Variablen innerhalb der Lib umgehst.

Noch einen schönen Abend,
Dirk
 
Lizenz

Eine BASCOM AVR-Library mit interner Variablenverwaltung und Interrupt Service Routine​

...

Wie die Library eingebunden wird bzw. wie die neuen Funktionen aufgerufen werden, geht aus dem BASCOM-Beispielprogramm hervor.
Ich hoffe, der Eine oder andere kann etwas mit diesem post was anfangen. Würde mich freuen.

LG
Werner

Hallo Werner
Sehr interessante Erweiterung. Ich würde gern auf meiner Website einen Link platzieren. Unter welcher Lizenz steht die Bibliothek zur Verfügung?
Viele Grüsse
Claus

www.ckuehnel.ch
 
Guten Abend,

vielen Dank für die positiven Kommentare zu meinem letzten Beitrag - hab' mich darüber gefreut ;) .

@Claus,
an die Frage "Lizenz" oder Ähnlichem hatte ich gar nicht gedacht. Das Tool hier zu veröffentlichen hatte ich als eventuelle Hilfestellung für andere Forumsuser gedacht - hab' selber schon von derartigen Beiträgen profitiert. Also gegen ein Verlinken hätte ich absolut nichts einzuwenden.
Falls es nötig ist, kann ich eine "Allgemeine Öffentliche GNU-Lizenz" in die Software einfügen, so wie es < hier > am Ende des Textes beschrieben ist.


Da ich keine praktischen Erfahrungen auf diesem "Lizenz-" Gebiet habe, fände ich Kommentare, Meinungen bzw. Korreturen zu diesem Themengebiet recht nützlich.


Schönen Abend noch
Werner
 
Guten morgen,

Ich möchte 2 Bemerkungen korrigieren, die ich im Eingangspost gemacht habe:
  1. Die Variablen der Library können doch angezeigt werden. Dazu muss ein Schalter in der BASCOM-IDE eingeschaltet werden. Der Schalter steht unter: Optionen > Compiler > Ausgang (Output) > Show internal variables
  2. Wenn man den Schalter setzt, kann man auch sehen, dass das "1-Byte-Loch" im RAM-Bereich gar kein "Loch" ist sondern von einer internen Variable belegt ist.

Ich finde dass - egal womit man sich beschäftigt - man lernt immer etwas dazu.

Schönen Tag noch
Werner :victory:
 
Hallo Werner,

ich nutze für mein Projekt einen mega2560 und wollte Deine lib. dafür nutzen bzw. testen, ob genau dies macht was ich für meine serielle Kommunikation benötige.
Leider wirft mir der Compiler bei dem verwendeten mega folgende Fehlermeldungen aus:

Error : 222 Line : 117 Illegal character [expected (, got '' [UDRIE]] , in File : C:\ELEKTRONIK\BASCOM-AVR 2.0.7.9\LIB\_FIRSTLIB.LIB
Error : 1 Line : 117 Unknown statement [.EQU not found for:UCSRA] , in File : C:\ELEKTRONIK\BASCOM-AVR 2.0.7.9\LIB\_FIRSTLIB.LIB
Error : 387 Line : 117 IO address must be in range [0-31] [UCSRA] , in File : C:\ELEKTRONIK\BASCOM-AVR 2.0.7.9\LIB\_FIRSTLIB.LIB

leider kenne ich mich mit Assembler nicht aus und weiß daher nicht, warum er dort:


CodeBox Assembler
[_RS232StringPresent]
; Declare   Sub _RS232StringPresent(byref x as Byte)
_RS232StringPresent:
   clr   mReg                   ' Default = 0 => kein kompletter string
*  lds   fReg,{_FlagReg}        ' dazu FlagReg auf Bit 7 prüfen
   SBRC  fReg,_RS232DataBranch  ' Sprung, falls Bit 7 gelöscht ist
   LDI   mReg,1                 ' sonst : kompletter String vorhanden
   LDD   XL,Y                   ' Zeiger auf Variable "x"
   LDD   XH,Y+1                 ' nach (X)                                                  <= Fehlermeldung
   st    X,mReg
   RET
[END]


mich anmeckert. Hat sicherlich mit der Schnittstelle zu tuen.

Könntest Du mir dabei mal helfen?
Danke und Grüße
MAT-SCHE
 
Hi,

die Bibliothek scheint ursprünglich auf ATmega8-kompatible Controller ausgelegt worden zu sein. Damalige Controller besaßen üblicherweise nur einen Hardware-USART. Folglich gab es nur ein "USART Control und Statusregister A" (UCSRA). Inzwischen haben viele Controller mehrere "Instanzen" diverser Hardware-Module, folglich dann auch mehrere Register-Instanzen. (beim 2560 sind es vier USARTs und folglich gibt es UCSRnA mit n=0..3).
Dasselbe gilt dann auch für das UDRIE-Bit (genau genommen sollte es eigentlich das UDRE-Bit sein - die haben nur denselben Wert... jedenfalls gibt's da auch mehrere "Instanzen" von (vier, klar).)

Diese beiden Punkte könnte man in der Bibliothek recht einfach ersetzen (möglicherweise sogar mit Parameter für "n").

Aber:
UCSRA hat beim Mega8 I/O-Adresse 0x0B, die vier UCSRnA beim Mega2560 liegen nicht mal im konventionellen I/O-Space, sondern im extendet I/O auf 0xC0, 0xC8, 0xD0 und 0x130.
Konventionelle I/Os bis 0x1F sind direct Bit accessible, und genau solch eine Instruction hatte @laplace damals verwendet (um UDRE (!!) zu prüfen bzw auf UDRE zu warten).
Da müßte man jetzt indirekt prüfen, also UCSRnA aus dem SRAM laden (LDS), und dann entweder genau so auf das Bit (im Rechenregister) skippen, oder die anderen Weg-Maskieren und dann bedingt springen.

Ich hab wohl demnächst keine Zeit, um mir das mal genauer anzusehen - Laplace war immerhin dieses Jahr noch im Forum unterwegs, sogar erst im Oktober...
 
Hallo LotadaC,
danke für Deine Antwort!
Nach dem ich mich schon intensiver mit den Registern der einzelnen UARTs vom ATmega beschäftigt hatte, beantwortete ich mr auch so die Fragen. Leider kann ich kein Assembler um dafür eine Lösung zu finden........
Danke nochmals
 
Ich habe mich mit Werners Bibliothek nicht weiter auseinandergesetzt, allerdings lassen bereits die ersten Zeilen darauf schließen, daß bereits in der Empfangs-ISR (also während des byteweisen Empfangens) auf den/ie Terminator/en geprüft werden soll. Zumindest würde ich das so angehen.
In reinem Basic ist die Ausfilterung der Zeichen CR und LF zwar möglich, ist aber ein ganz schönes Gefummel.
Meinem Verständnis nach meint er damit irgendwelche fertigen High-Level-Routinen, Input oder sowas ähnliches eben.
Auf die nötigen Register hast Du auch unter Bascom selbst Zugriff.
Das Problem für Dich ist, daß modernere (größere) Controller eben andere Register- und Bitnamen dafür nutzen, und im Falle von UDRE ggf nicht mehr den direkten Zugriff mit SBI/CBI/SBIC/SBIS erlauben.

Der eigentliche Wert dieses Themas ist allerdings nicht der Zugriff auf die Schnittstelle selbst, sondern die Bereitstellung der entsprechenden externen Funktionen und Subroutinen in einer Bibliothek. Also auch, wie man so eine Bibliothek selbst entwickeln kann.

Wie kann ich in der externen LIB auf, vorher im aufrufenden Code definierte Variablen zugreifen? Wie kann ich in der externen Bibliothek Konstanten/Variablen definieren? Wie kann ich statt des üblichen ASM-Codes doch Bascom-Code in die externe Lib einflechten... usw.

Ich ergänze mal zwei Punkte, die nichts mit dem USART zu tun haben, aber mit dem Bibliothekenbau:
  • Interrupts sollten sich natürlich auch in der Bibliothek scharfschalten lassen, klar. Das Eintragen ISR-Sprunges in die Interruptvektortabelle (IVT) erledigt man in Bascom ja mit

    CodeBox BascomAVR
    On Interruptquelle ISR-Name
    (so auch hier in der "libtest.bas" für den URXC geschehen, mit einer in der Lib implementierten Routine als Sprungziel. Aber selbst dieser IVT-Eintrag kann in einer Lib erfolgen:
    durch das Voranstellen einer „*BASIC:“ Instruktion an den Anfang einer Zeile […] können offensichtlich (zumindest in rudimentärer Form) Basic- Operationen beim Einbinden einer Library in den Programmcode durchgeführt werden
    . Zumindest läßt sich ein in der LIB enthaltenes

    CodeBox BascomAVR
    *BASIC: On Interruptquelle ISR-Name
    fehlerfrei compilieren und simulieren - in Hardware hab ichs noch nicht getestet. Das Ziel kann dabei sowohl in der Lib sein, als auch im aufrufenden Code (wegen der Precompile-Unterdrückung)
  • bedingte Compilierung ist auch in der Bibliothek möglich, mit den dafür bei Bascom zu verwendenden … äh … Tags(?), auch hier lassen sich Konstanten(!!) aus dem aufrufenden Code verwenden. Als Beispiel mal die Verwendung der, im Regfile hinterlegten CHIP-ID (leider nicht der Name oder sowas):

    CodeBox BascomAVR
    #if _CHIP=31
       'Codeblock für den ATtiny2313A
    #elseif _CHIP=49
       'Codeblock für den ATtiny4313
    #endif
    
 
Zuletzt bearbeitet:

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