Auslesen von "Compiler Directives" im BASCOM Programm

Markus

BASCOM-Experte
11. Jan. 2008
1.190
6
38
Lonsee
Sprachen
Hallo Ihr Lieben,

für mein Endlos-Projekt "Wetterstation" (leider zu wenig Zeit um mal konzentriert an dem Thema zu arbeiten) ensteht gerade ein Rahmenprogramm mit grundlegenden Funktionen, welches in allen Sensoren, die über RS485-Systembus miteinander kommunizieren sollen, als Framework verwendet werden soll.

Da sich die Programmgrößen der einzelnen Slaves sehr unterscheiden werden, möchte ich wahlweise den ATmega8 oder ATmega168 oder ATmega328 einsetzen. Wahlweise auch mit 14,7456 oder 18,432 MHz für ATmega158 und ATmega328.
Wie üblich steck der Teufel im Detail, bzgl. der Timer und manchen Register, wo bei Benutzung unterschiedliche Programmierung notwendig ist.

Nun meine spannende Frage :)

Es gibt compiler directives wie z.B. "$crystal" oder "$regfile" oder "$hwstack" oder "$swstack" .....

Gibt es eine Möglichkeit oder habt Ihr eine Idee, wie man später diese Compiler-Schalter abfragen kann? Hinterlässt der Compiler im Sourcecode Spuren die ausgelesen werden können?

Wenn es nämlich darum geht, einen Timer Reoad zu machen dann ist das Clock abhängig und es wäre doch sehr schön, wenn man das generisch programmieren könnte

#if $crystal = 14Mhz tues dies $elseif $crystal=18MHz tue das $endif....

Gleiches mit $baud und $regfile etc.
Ich meine, das muss ja dynamisch garnicht funktionieren, denn die Werte stehen zur Compile-Zeit schon fest und es könnte ja fix compiliert werden.

Um es vorweg zu nehmen .... ich experimentiere und suche hier schon eine Weile und habe bisher nichts gefunden. Aber vielleicht habt ihr noch eine Idee.
Bisher habe ich das als Umweg mit Const = blablabla und #if realisiert. Das funktioniert recht gut, nur aber nicht beim $regfile .....

Grüße,
Markus
 
Hallo Markus,
für $crystal und den Controller Type schau dir mal die Konstanten _XTAL und _CHIP an.
Die findest du im "Show Results" Fenster (oder mit CTRL-W).
Dort findest du auch die berechneten Startadressen der Stacks.
Baudrate musst du glaube ich aus dem Register holen, weil das ja zur Laufzeit geändert werden kann.
 
  • Like
Reaktionen: Markus
Hallo siggi777,

ja genau, so was habe ich gesucht :) Muss es gleich mal ausprobieren, ob ich auf die Variable an den Stellen Zugriff habe, wo ich es brauche und ob sich meine Idee damit realisieren lässt. Das wäre ja super.
Um ehrlich zu sein, ärgere ich mich jetzt ein wenig über mich selbst, denn auf die Idee, den Report mal durchzuflöhen, hätte ich selbst auch kommen müssen.....

Meine Ergebnisse werde ich Euch mitteilen.

Grüßle,
Ma
 
Haha, das ging schneller als ich dachte *freu*



CodeBox BascomAVR
' Cpu_type:  ATmega8      _chip:  17
'            ATmega168            34
'            ATmega328            60

' Cpu_clock: 14Mhz       _xtal: 14745600
'            18MHz              18432000


und dann im Code



CodeBox BascomAVR
' Konfiguration eines Timers für 1 Sekunden Timer-Tick (Scheduler und Alive)
#if _xtal = 14745600
    Config Timer1 = Timer , Prescale = Timer_prescaler      ' Timer 1 verwenden
    Timer1 = Timer_compare
#elseif _xtal = 18432000
    Config Timer1 = Timer , Prescale = Timer_18mhz_prescaler       ' Timer 1 verwenden
    Timer1 = Timer_18mhz_compare
#endif

....

#if _chip = 17                                          ' ATmega8
        Print #2 , Slave_code_string ; "CPU ist ATmega8"
#elseif _chip = 34                                      ' ATmega168
        Print #2 , Slave_code_string ; "CPU ist ATmega168"
#elseif _chip = 60                                      ' ATmega328
        Print #2 , Slave_code_string ; "CPU ist ATmega328"
#endif

....

#if _xtal = 14745600
    Timer1 = Timer_compare
#elseif _xtal = 18432000
    Timer1 = Timer_18mhz_compare
#endif


Ich glaube so lässt sich das machen und damit kann ich leben. Dann habe ich nämlich nur an einer Stelle im Programmkopf, je nach Konfiguration, das richtige $regfile und $crystal zu setzen und den Rest kann ich im Code generisch implementieren.

Danke siggi777 !!

Bin ja mal gespannt, ob die Werte für den _chip bei einem BASCOM Update gleich bleiben oder sich ändern..... Aber das werden wir sehen.

Sehr schön :) .... Ist doch ganz einfach ..... (wenn man weiß wie es geht und wo man schauen muss)
 
Hi Markus, in den Reports hatte ich auch schon mal rumgewühlt, zB auch wegen den default-I²C-Beinen (da werden entsprechende Hintergrund-Compiler-Variablen angelegt, wenn ein I2cinit im Code steht (die Routine kann man sogar mit einer komplett leeren überschreiben (eigene Lib)) - aber das nur am Rande...

Zum Timer hatte ich hier mal mit dem optionalen "configuration"-flag experimentiert.

Zu Deinem Lösungsansatz: Ich(!) würde trotzdem über Konstanten (also Compilervariablen) gehen, also Reload bzw Comparewerte aus den entsprechenden Zeiten und dem xtal-Wert berechnen lassen.
(bei den teilweise stark unterschiedlichen Prescalern unterschiedlicher Timer (in teilweise exotischen Controllern) vielleicht nicht unbedingt sinnig (da scheint auch Bascom selbst manchmal Probleme zu haben), aber bei Reload/Compares..., und da dann natürlich _xtal und co nutzen)

Zur Baudrate: bei Verwendung von Print, Input usw initialisiert Bascom selbst den HW-UART (wenn man das nicht umconfiguriert).
Dabei wird der default-Wert verwendet, der unter Menü->Optionen->Compiler->Kommunikation->Baudrate angegeben ist. (Menü->Optionen->Kommunikation->Baudrate hingegen betrifft die des Bascom-Terminalemulators).
Der default-Wert kann durch die Verwendung der $baud-Direktive übersteuert werden (für mich gehört das immer in den Sourcecode, nicht in die defaults).
Zur Änderung der Baudrate zur Laufzeit wird der Befehl "Baud" verwendet.

Tricky wird das ganze natürlich, wenn zur Laufzeit Taktfrequenz und/oder -quelle umgeschaltet werden...
 
Hallo LotadaC,

danke für Deine Erklärung.

Ich(!) würde trotzdem über Konstanten (also Compilervariablen) gehen
Das habe ich versucht. Hatte auch soweit funktioniert, nur nicht bei $regfile. Ein #if Konstrukt mit Konstante Const CPU_type = "ATmega8" oder Const CPU_type = 1 hat bei $regfile einfach nicht funktioniert. In der Zwischenzeit weiß ich auch warum :)
Hier gibt es in den Options unter Environment>IDE einen Schalter "Use new method" und der betrifft genau "support $regfile settings nested in #if #endif" .... da muss man erst mal drauf kommen.

Das hatte ich dann auch schon alles am Laufen. Aber mir hat es nicht gefallen und so habe ich nach einer Lösung gesucht, die ich in direktem Zusammenhang von $regfile und $crystal implementieren kann. Und genau diese Lösung habe ich nun mittels _xtal und _chip gefunden.

Baudraten und IDE Einstellungen
Die Reload und Comparewerte stammen bei mir aus einer Berechnung, welche ich auf Papier mache und dann mit Konstanten (Const), meist in einem Header-File als Include-Datei definiere. Da ich es hier mit 3 Pin-Kompatiblen ATmega-Varianten zu tun habe, habe ich mir die Arbeit einer dynamischen Implementierung der Timer-Konfiguration in Anlehnung an den Clock erspart. Kann man sicher machen und die Werkzeuge dazu haben wir.

Prinzipiell ist es so, dass ich IMMER ALLES im Source Code konfiguriere und setzte. Das macht das Programm verständlicher und es ist für jedermann lesbar, ohne wissen zu müssen, was in der IDE eingestellt ist. Ich persönlich betrachte den redundanten Weg IDE und Überschreiben im Programm als böse Falle und führt zur Schlamperei.... Daher ignoriere einen Großteil der IDE Einstellungen und konfiguriere alles mit compiler directives und configs im Code.


Die Lösung mit _xtal und _chip finde ich super und so werde ich das jetzt auch weiter verfolgen und meine generische Implementierung für die 7 Slaves fortsetzen. Damit kann ich dann nämlich nicht nur Quarz und Chip einfach austauschen und umschalten, sondern ich kann auch sehr Chip spezifische Dinge entsprechend programmieren.
Ein Beispiel sei hier erwähnt: Es geht um den externen Interrupt INT0. Er ist bei allen 3 von mir verwendeten ATmegas am gleich Port-Pin angeschlossen. Beim ATmega8 heißt das für den INT0 relevante interrupt flag register GIFR ( general interrupt flag register) und beim ATmega168 und ATmega328 EIFR(external interrupt flag register). Solche Feinheiten kann ich jetzt schön generisch mit einem Source-Code implementieren. Ja, zugegeben, das wäre mit Const's auch gegangen.

Grüßle und gute Nacht,
Markus
 
da muss man erst mal drauf kommen.
Ok, genau davon geht man bei bedingter Kompilierung ja auch eigentlich aus...

Die Reload und Comparewerte stammen bei mir aus einer Berechnung, welche ich auf Papier mache und dann mit Konstanten (Const), meist in einem Header-File als Include-Datei definiere.
Wenn die mal geändert werden können sollen, laß ich das gern durch den Compiler berechnen. Statt also den Comparewert für meinetwegen eine ms (oder die Frequenz) als Konstante zu hinterlegen, hinterlege ich die 1(ms) als Konstante, und über die Formel die Konstante für den Compare bei der Zuweisung.
Ebenso bei der Baudrate (gibts ja bei Assembler in der Form nicht nativ).
Prinzipiell ist es so, dass ich IMMER ALLES im Source Code konfiguriere und setzte. Das macht das Programm verständlicher und es ist für jedermann lesbar, ohne wissen zu müssen, was in der IDE eingestellt ist. Ich persönlich betrachte den redundanten Weg IDE und Überschreiben im Programm als böse Falle und führt zur Schlamperei.... Daher ignoriere einen Großteil der IDE Einstellungen und konfiguriere alles mit compiler directives und configs im Code.
:good2:
Die Lösung mit _xtal und _chip finde ich super
zu beidem hab ich unter ASM keine Lösung parat - den effektiven Takt leg ich oft anfangs als Konstante fest, um dann Timings usw draus abzuleiten, bei den Variabilitäten der Chips führt eine Fallunterscheidung dann aber zu weit - zumindest bei den unterschiedlichen Core-Versions der Tinies ist da am Ende kein System mehr zu erkennen. Wenn man für ein bestimmtes (Teil-)Programm nur ein paar bestimmte Controller verwenden will geht das noch, aber universell... nee
Ein Beispiel sei hier erwähnt: Es geht um den externen Interrupt INT0. Er ist bei allen 3 von mir verwendeten ATmegas am gleich Port-Pin angeschlossen.
Wenn ich das richtig in Erinnerung habe (@dino03 mag mich korrigieren), war der Ur-Vater dieser Controller der AT90(L)S2333/4433. Beim Mega8 kamen dann unter anderem ein paar alternative Funktionen hinzu (Reset als I/O fusebar, XTALs ebenso), ein dritter Timer usw.
ATmega48/88/168/328 sind meiner Meinung nach auch alle derselbe Chip mit variabler Speicherbestückung (die auf den Mega8 zurückgehen), deutliche Neuerungen gab es beim 328er bei der PB-Revision (also ATmega328PB, unter anderem 'n vierten Timer (nebst entsprechenden Waveform outputs), je einen zusätzlichen USART, TWI, SPI sowie den PTC (ATXmega sowie X-1-Core-Tinies).
Unterstützt Bascom inzwischen den PTC?

Natürlich wurden bei den großen Änderungen diverse Register und -Bits neu gemischt.
Da sich die Programmgrößen der einzelnen Slaves sehr unterscheiden werden, möchte ich wahlweise den ATmega8 oder ATmega168 oder ATmega328 einsetzen.
Für Slaves (Sensoren/Aktoren ohne "Intelligenz") setze ich gern Tinies ein - die hebn nicht soo viele Krabbelbeine...

P.S.:
???
Quelle?
 
da muss man erst mal drauf kommen.
Meine Aussage bezog sich nicht auf die bedingte Compilierung. Die ist mir seit Jahrzehnten bekannt und ist bei C und C++ üblich. Meine Aussage bezog sich viel mehr auf den Schalter "Use new method" .... ist ja vom namen her total selbsterklärend, dass hier genau die von mir gesuchte Funktion gesucht ist :)

zu beidem hab ich unter ASM keine Lösung parat
ASM ... was ist das. :) Das ist das ganze Zeugs mit der nicht verständlichen Mnemonic und den Zahlenkolonnen, von denen die ganzen heutigen Arduino Newbee's mit ihren SW-Baukästen überhaupt keine Ahnung mehr haben.
Als ich vor über 35 Jahren in die Informatik und Computertechnik eingestiegen bin, habe ich noch ASM von Hand beschrieben, die Mnemonic von Hand in Zahlen übersetzt und meinen ersten Z80 über Schalter und Taster programmiert..... Mit uns wird das Wissen über die Geheimnisse von Assembler und das Verständnis, wie eine ALU funktioniert aussterben.....
Anmerkung: Das ist garnicht so weit hergeholt. Ich hatte die letzten Tage eine Konversation mit einem Arduino-Jünger .... war sehr interessant ....

Für Slaves (Sensoren/Aktoren ohne "Intelligenz") setze ich gern Tinies ein - die hebn nicht soo viele Krabbelbeine...
Du glaubst gar nicht, wie viele Krabbelbeine ich für meine Slaves brauche. Da sind die 28 Beinchen des ATmega8 schon fast zu wenig. Die Anzahl der Beinchen ist linear zu den Ideen, was der Slave so alles können soll.
Beispiel: I2C Interface + RS485 Interface (UART) + Tracing Interface (SW UART) + LED's + GPIO Pin's für diverse Steueraufgaben ... da kommt was zusammen

Gut aufgepasst :) War ein Test .... soll natürlich ATmega168 heißen

Ich wünsche Euch allen ein schönes regnerisches Wochenende. Raus kann man nicht und darf man nicht ...... Da kann gebastelt werden, bis der Lötkolben explodiert :dance3:
 
Meine Aussage bezog sich nicht auf die bedingte Compilierung. Die ist mir seit Jahrzehnten bekannt
Genau so meinte ich das auch, wenn ich auf die CPU bedingt compilieren kann erwarte ich auch daß das geht, und nicht, daß ich nach 'nem Schalter in der IDE suchen muß, der das erst freischaltet...
ls ich vor über 35 Jahren in die Informatik und Computertechnik eingestiegen bin, habe ich noch ASM von Hand beschrieben, die Mnemonic von Hand in Zahlen übersetzt und meinen ersten Z80 über Schalter und Taster programmiert

Diesbezüglich hab irgendwo mal 'n Tutorial gesehen, wo jemand genau das mit'nem AVR gemacht hat, also Mnemonics in Opcodes übersetzt, die Bytes fürs SPI-Programming ergänzt, und dann alles mittels zweier Taster in den Controller ge... äh ... morst (?)
(waren zugegebenermaßen keine Code-Monster ;) )
wie viele Krabbelbeine ich für meine Slaves brauche. Da sind die 28 Beinchen des ATmega8 schon fast zu wenig
Der Mega8 hat 23 I/Os (wenn man auf Reset und XTALs verzichtet), SMDs bieten zwei zusätzliche ADC-Eingänge).
Der Mega328PB hat 27 I/Os (ein Stromversorgungspaar weniger und die beiden ADC-Eingänge sind jetzt I/Os, der Rest ist pinkompatibel)

Die "krabbeligsten" (konventionellen) Tinies sind ATtiny48/88 und ATtiny828 mit bis zu 28 I/Os.

Bei den X-1-Core-Tinies wäre bei 24 Beinen Schluß (die "7" am Ende), davor 'ne "1" für X-1, davor die Speichervariante (Flashgröße - 4, 8, 16 oder 32 kB).
ATtiny417/817/1617/3217
Zwei Beine Stromversorgung, die restlichen 22 sind als I/O verwendbar (unter Verzicht auf Reset, und fürs Programming muß der UPDI 12V-tolerant verwendet werden)

Raus kann man nicht und darf man nich
Mußte noch den Weg in den Garten für'n Baum-Sachverständigen schaffen - der will da mit 2x8m (und 2,3t) durch den Stellplatz und über den Rasen um sich den Baum anzusehen und abzusichern...
 

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