Bascom BASCOM ; Erste Schritte zum Ausprobieren

Du kannst sämtliche Unterprogramme / Sprungmarken etc. frei benennen.
Wichtig ist nur dass der Name überall identisch ist, also wenn du beispielsweise per On Oc2 Isr_oc2 festlegst dass beim Oc2 Interrupt (dieser Name ist festgelegt!) zur Sprungmarke "Isr_oc2" gesprungen wird, muss diese auch existieren. Sie könnte aber genau so gut auch Karl oder Gustav heißen, solange du dich an die Regeln hältst (keine Leerzeichen, Umlaute sind ungünstig, etc.). Das Selbe für Goto/Gosub MeinUnterprogramm und MeinUnterprogramm:
Ach ja, und einmalig müssen sie natürlich sein, also 2 Label mit dem selben Namen würde nicht nur keinen Sinn ergeben, sondern auch nicht funktionieren.

Und ja, der Anfang passt schon mal, aber nun fehlt dir die Tick_1s, die für eine Uhr ein elementarer Bestandteil ist ;).
Aber 1000ms (=1s) ist ja rein zufällig ein vielfaches von 200ms.
Genau wie 200ms ein vielfaches von 8ms ist. (Isr_oc2 ist quasi gleichzusetzen mit Tick_8ms)
Fällt dir was auf?

Das Grundprinzip hast du schon direkt vor der Nase, du musst es nur doppeln. Dann haste Tick_200ms und Tick_1s von nur einem Timer.
 
Zuletzt bearbeitet:
Ich kann jetzt alsoZeile 5

CodeBox BascomAVR
' Konfiguration Timer 2 (CTC, 8MHz/256/249 = 8ms)
   Config Timer2 = Ctc , Prescale = 256 , Clear_timer = 1
   Ocr2 = 249                           ' Setze Maximalwert für Timer 2 (CTC)
   On Oc2 Isr_oc2                       ' Setze ISR für Timer 2 Overflow Compare
   On Oc2 Isr_heini
   Enable Oc2                           ' Aktiviere Timer 2 Overflow Compare In
   Config Watchdog = 2048
   Start Watchdog
   Enable Interrupts
nehmen. Das Enable Oc2 reicht einmal. Und dann die Unterroutine Isr_heini:
Ist das richtig?
Bis jetzt ca. zwei Stunden, geht die Uhr 1 Sekunde nach.
 
Kannst du so machen, ja. Aber jetzt weist du On Oc2 2x zu, nur das Letzte ist gültig.
Also nur 1x On [Interrupt] ... und 1x Enable [Interrupt].
[Interrupt] ist ein Platzhalter, hier für OC2, aber ADC, OC0, OC1, ... wären weitere Möglichkeiten. Sind aber je Chip unterschiedlich, je nachdem was zur Verfügung steht.

Zu den Namen. Das war jetzt nur ein Beispiel, sinnvoll ist das so natürlich nicht. Bei Namen wie Isr_Oc2 oder OnOc2 weiß jeder sofort was gemeint ist.
Genau wie Tick_1s, da weiß jeder sofort, ok, wird jede Sekunde ausgeführt.
VB.Net und C# erstellen die EventHandler auch nach einem gewissen Schema, z.B.: Sub Button1_Click(...)
Buchstäblich: Wo (Button1) ist Was (Click) passiert.

Wenn sich an der IDE von Bascom sich nicht gegenüber meiner Zeit gewaltig was verbessert hat verhält sich Bascom zu VB.Net so wie Bayrisch zu Hochdeutsch. Da macht es auch Sinn, wie zu Uralt Zeiten in VB6 und davor Variablennamen zu Präfixen, damit man sieht was da drin überhaupt gespeichert werden kann / soll. Beispielsweise:
bCounter As Byte
iResult As Integer
sHeader As String...
In moderneren Basic Versionen bekommt man nicht nur beim Tippen schon den Datentyp angezeigt, ein fälschliches Umwandeln (z.B. ein String in ein Byte kopieren) wird gleich abgemahnt, weil in 99% der Fälle ist es ungewollt und schlägt in der Ausführung fehl.

Sollte man sich gleich angewöhnen, weil irgendwann kommst du an den Punkt, du willst ne Kleinigkeit ändern, aber wegen konfuser Namensgebung und das non+ultra: fehlender Dokumentation / Kommentare musst du dich erst wieder stundenlang hineinversetzen und brauchst zig Testläufe bis es denn geht.

Falls es dich interessiert, so sieht Quelltext bei mir aus.
Sagen wird es dir kaum was (ist ja auch VB.Net, nicht Bascom), aber du siehst wie viel Arbeit in vernünftiger Dokumentation liegt. Aber glaube mir, die ist jede Minute wert.
 
Jetzt verstehe ich Garnichts mehr. Der Code macht mit und ohne auskomentieren das gleiche. Auch habe ich die Taster an B0 und B1 gehabt, auch das gleiche.
Taster an C0 oder auch an B0 reagiert, aber nur wenn er eine Sekunde oder dauerhaft gedrückt wird. Taster an C0 oder auch B0 macht nichts.
Im übrigen ging die Uhr heut morgen noch auf die Sekunde genau.

CodeBox BascomAVR
$regfile = "m8def.dat"                  'Controllerdefinitionsdatei einbinden
$crystal = 8000000                      'Systemtakt angeben (Baudrate)
$hwstack = 40                           'Stacks
$swstack = 16
$framesize = 32
Dim Count As Byte
Dim Sekunde As Word
Dim Minute As Word
Dim Stunde As Word
Dim Irq As Byte
Dim S1 As String * 2
Dim S2 As String * 2
Dim S3 As String * 2
Config Pinc.0 = Input
Portc.0 = 1
Config Pinc.1 = Input
Portc.1 = 1
Taster0 Alias Pinc.0
Taster1 Alias Pinc.1
'----------------------------------------------------------------------------
Sekunde = 00
Minute = 45
Stunde = 05
'----------------------------------------------------------------------------
Init:
   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
   Initlcd
   Cls
   Cursor Off
' Konfiguration Timer 2 (CTC, 8MHz/256/249 = 8ms)
   Config Timer2 = Ctc , Prescale = 256 , Clear_timer = 1
   Ocr2 = 249                           ' Setze Maximalwert für Timer 2 (CTC)
   On Oc2 Isr_oc2                       ' Setze ISR für Timer 2 Overflow Compare
   'On Adc Isr_key
   Enable Oc2                           ' Aktiviere Timer 2 Overflow Compare In
   'Enable Adc
   Config Watchdog = 2048
   Start Watchdog
   Enable Interrupts
'----------------------------------------------------------------------------
Main:
'----------------------------------------------------------------------------
   Home
   S1 = Str(stunde)
   S1 = Format(s1 , "00")
'----------------------------------------------------------------------------
   S2 = Str(minute)
   S2 = Format(s2 , "00")
'----------------------------------------------------------------------------
   S3 = Str(sekunde)
   S3 = Format(s3 , "00")
'----------------------------------------------------------------------------
   If Irq.0 = 1 Then
      Locate 2 , 13
      Lcd S3
      Locate 2 , 11
      Lcd ":"
      Locate 2 , 8
      Lcd S2
      Locate 2 , 6
      Lcd ":"
      Locate 2 , 3
      Lcd S1
      Locate 1 , 1
      Lcd " Std. Min. Sek."
      Waitms 50
      Irq.0 = 0
   End If
   Config Powermode = Idle
   Reset Watchdog
   Goto Main
   End
'----------------------------------------------------------------------------
Isr_oc2:
   Incr Count
   If Count = 125 Then
      Count = 0
      Gosub Tick_1s
   End If
Return
'----------------------------------------------------------------------------
'(
Isr_key:
Incr Count
If Count = 25 Then
Count = 0
      'Gosub Tick_200ms
End If
Return
')
'----------------------------------------------------------------------------
Tick_1s:
   Incr Sekunde
   If Sekunde = 60 Then
      Sekunde = 0
      Incr Minute
   End If
   If Minute = 60 Then
      Minute = 0
      Incr Stunde
   End If
   If Stunde = 24 Then
      Stunde = 0
   End If
   If Taster0 = 0 Then
      Incr Minute
   End If
   Irq.0 = 1
Return
'----------------------------------------------------------------------------
Tick_200ms:
   If Taster0 = 0 Then
      Incr Minute
   End If
'--------------Uhr einstellen Stunde ----------------------------------------
'(
   If Taster1 = 0 Then
      Incr Stunde
   End If
Return
')
 
Vorsicht, Blockweises Auskommentieren gibt es in Basic eigentlich nicht. Bascom hat das zwar eingeführt, aber ich habe da schon viel drüber gehört dass es Probleme gibt.

Also. Isr_Oc2 ist der Timer, der generiert 8ms Impulse (bzw wird alle 8ms ausgeführt)
Darin hast du einen Software Counter (die Variable Count). Wenn dieser Counter "überläuft" (Vergleich mit 125) wird er wieder genullt und startet:
Tick_1s. Hier sind Sekundenimpulse. Weil 8ms*125=1000ms
Wir brauchen ja aber auch 200ms.

Isr_Key hatten wir ja schon gesagt, brauchen wir nicht. Ist auskommentiert. Ok. Trotzdem wird dein Tick_200ms ja nirgendwo aufgerufen. Wie soll es dann auch funktionieren?

Es gibt nur eine logische Möglichkeit Tick_200ms aufzurufen. So wie Tick_1s auch, nämlich durch den Timer.
Hier gibt es nun 2 Varianten. Beide erfordern statt wie bisher 1 Soft Counter noch einen weiteren.

Möglichkeit 1:
Du erhöhst beide Softcounter in der Timer Isr. Dann 2 Abfragen. Counter1 zählt bis 25 und ruft dann Tick_200ms auf, Counter2 zählt bis 125 und ruft Tick_1s auf.
Im Endeffekt nur ein mal Copy Paste, Wert ändern und eine zusätzliche Variable.
Vorteil: Beide Zeiten müssen nicht zwangsweise ein Vielfaches des Anderen sein, du könntest feiner einstellen falls benötigt.
Nachteil: Bei sehr langen Laufzeiten brauchst du auch größere Variablen (Integer, Long/Word). Hier reicht aber so oder so ein Byte aus.

Möglichkeit 2:
Du lässt die Isr so wie sie ist, änderst sie aber auf 200ms um, startest dementsprechend Tick_200ms.
Innerhalb Tick_200ms hast du den 2. SoftCounter. Dieser hat den "Überlauf von 5" (200*5=1000) und startet Tick_1s.
Vorteil: Für lange Zeiten wird weniger Speicherplatz benötigt.
Nachteil: Da es kaskadiert ist müssen die generierten Zeiten immer ein vielfaches sein.

Hier ist es egal, du hast bei keiner Methode Vor- noch Nachteile.
Als Zähler kommst du so oder so mit einem Byte aus (=keine Änderung) und 200 ist ein vielfaches von 1000. Passt also beides.
 
Danke! Es ist doch im Prinzip ganz einfach, wenn man auf den richtigen Weg gebracht wird. Versanden habe ich auch alles, nur mit dem Format (welches ich mir #12 geklaut habe) bin ich mir noch nicht sicher. Aber ich habe ja noch das Datum offen.

CodeBox BascomAVR
$regfile = "m8def.dat"
$crystal = 8000000
$hwstack = 40
$swstack = 16
$framesize = 32
'----------------------------------------------------------------------------
Dim Count1 As Byte
Dim Count2 As Byte
Dim Sekunde As Word
Dim Minute As Word
Dim Stunde As Word
Dim Irq As Byte
Dim S1 As String * 2
Dim S2 As String * 2
Dim S3 As String * 2
Config Pinb.0 = Input
Portb.0 = 1
Config Pinb.1 = Input
Portb.1 = 1
Taster0 Alias Pinb.0
Taster1 Alias Pinb.1
'Startoption-----------------------------------------------------------------
Sekunde = 00
Minute = 29
Stunde = 12
'Initialisiere LCD-----------------------------------------------------------
Init:
   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
   Initlcd
   Cls
   Cursor Off
'Konfiguration Timer 2 (CTC, 8MHz/256/249 = 8ms)-----------------------------
   Config Timer2 = Ctc , Prescale = 256 , Clear_timer = 1
   Ocr2 = 249                           ' Setze Maximalwert für Timer 2 (CTC)
   On Oc2 Isr_oc2                       ' Setze ISR für Timer 2 Overflow Compare
   Enable Oc2                           ' Aktiviere Timer 2 Overflow Compare In
   Config Watchdog = 2048
   Start Watchdog
   Enable Interrupts
'----------------------------------------------------------------------------
Main:
'----------------------------------------------------------------------------
   Home
   S1 = Str(stunde)
   S1 = Format(s1 , "00")
'----------------------------------------------------------------------------
   S2 = Str(minute)
   S2 = Format(s2 , "00")
'----------------------------------------------------------------------------
   S3 = Str(sekunde)
   S3 = Format(s3 , "00")
'----------------------------------------------------------------------------
   If Irq.0 = 1 Then
      Locate 2 , 13
      Lcd S3
      Locate 2 , 11
      Lcd ":"
      Locate 2 , 8
      Lcd S2
      Locate 2 , 6
      Lcd ":"
      Locate 2 , 3
      Lcd S1
      Locate 1 , 1
      Lcd " Std. Min. Sek."
      Waitms 50
      Irq.0 = 0
   End If
   Config Powermode = Idle
   Reset Watchdog
   Goto Main
   End
'Interrupts------------------------------------------------------------------
Isr_oc2:
   Incr Count1
   If Count1 = 25 Then
      Count1 = 0
      Gosub Tick_200ms
   End If
   Incr Count2
   If Count2 = 125 Then
      Count2 = 0
      Gosub Tick_1s
   End If
Return
'----------------------------------------------------------------------------
Tick_1s:
   Incr Sekunde
   If Sekunde = 60 Then
      Sekunde = 0
      Incr Minute
   End If
   If Minute = 60 Then
      Minute = 0
      Incr Stunde
   End If
   If Stunde = 24 Then
      Stunde = 0
   End If
Return
'--------------Uhr einstellen Stunde oder resetten---------------------------
Tick_200ms:
   If Taster0 = 0 Then
      Incr Minute
      If Minute = 60 Then
         Minute = 0
      End If
   End If
   If Taster1 = 0 Then
      Incr Stunde
      If Stunde = 24 Then
         Stunde = 0
      End If
   End If
   If Taster0 = 0 And Taster1 = 0 Then
      Sekunde = 0
      Minute = 0
      Stunde = 0
   End If
   Irq.0 = 1
Return
 
Na siehste, geht doch :)

Datum, da wird es schon komplexer, dank unserem tollen Kalendersystem.
Prinzipiell ist es nichts anders wie mit der Uhrzeit. Hier bräuchten wir noch nicht mal einen SoftCounter, da wir den indirekt schon haben, nämlich durch die Variable Stunden. Läuft die über und wird genullt muss halt das Datum erhöht werden. Fehlt nur ein Gosub.

Aber hier geht es los, weil mal haben wir 30 Tage, mal 31, mal 28 und herrjemine, 29 kommt auch mal vor. Also quasi einen variablen Überlauf.
Monat und Jahr hingegen ist ja nur simples hoch zählen, wie bei der Uhrzeit.
Ich warne vor, mit IFs wird brutal, nimm hier auf jeden Fall Select Case für.
Kannst dir ja mal Gedanken machen wie das Erhöhen des Tages auszusehen hat ;)

EDIT:
Vielleicht etwas übersichtlicher wegen dem IRQ.0
Du kannst dem ja auch ein Alias verpassen, beispielsweise LcdIsDirty oder RedrawLcd
Ist aber Geschmackssache.
 
Mit IRQ hatte ich ja vor kurzem erklärt, siehe #830. Hier wird es als Flag benutzt (also 1 Bit, Gesetzt oder nicht). Ist es gesetzt muss die Main das LCD neu zeichnen, sonst nicht. Willst du was auf dem Display ändern lassen musst es auf 1 setzen. In der Main wird das LCD dann aktualisiert, und da es jetzt nicht mehr "dreckig" ist, wieder genullt, also zurück gesetzt.

Man könnte es z.B. auch auf splitten. IRQ.0: Zeile 1 neu zeichnen (Datum), IRQ.1: Zeile 2 neu zeichnen (Uhrzeit).
So kann man auf einfachsten Wege gewaltig an Resourcen einsparen - und somit auch Strom. LCDs sind lahm und "verbrennen" viel durch Wartezyklen.
Du definierst somit halt was die Main Loop zu tun hat. Idealerweise nichts, also nur Kund treten und wieder einschlafen (bis zum nächsten Interrupt).
 
Also kommt das nur in die Main rein und hat nichts in den Unterprogrammen zu suchen. Zeile 122 also weg.
Datums-Format hab ich schon mal geschrieben. Gibt es nicht viel zu verstehen. Wie gesagt, nur das Format und Startoption.
 
Nein.

Sagen wir IRQ.0 ist immer 0, dann würde das Display niemals aktualisiert. Außer du machst es im Interrupt selbst, was so ungefähr das schlimmste ist was du machen könntest. Aber im Interrupt änderst du die Zustände von Variablen (Stunde, Minute, Sekunde, ggf. weitere) die ein Neu"zeichnen" des Displays erfordern. Sonst würde die Änderung ja nie angezeigt. Daher setzt du da IRQ.0 auf 1, was besagt dass das Display neu gezeichnet werden muss.
Wenn der Controller irgendwann wieder Zeit hat, also sich normal in der Main Loop befindet, stellt er fest dass IRQ.0 = 1 ist, also das Display neu gezeichnet werden muss. Also: Neu zeichnen und IRQ.0 auf 0 zurück setzen, weil Job done.

Nix anderes als die Tankanzeige im Auto. Du hältst doch auch nicht an jeder Tanke an, die du auf dem Weg irgendwie erreichen könntest, nur um einen vollen Tank zu haben. Du fährst den Tank, sagen wir, bis zu ~15% leer bevor du wieder voll tankst.
Vorher, ohne IRQ.0, hast du deine Main Loop dazu gezwungen ständig, so oft wie technisch möglich, das Display mit Daten zu befeuern, also spätestens alle 8ms ein Mal. Hier beißt sich die Ratte aber selber in den Schwanz, weil das Neuschreiben des Displays länger als 8ms dauert, der Controller kam also nie in den Sleep Mode. Und dass es trotzdem noch präzise lief hast du nur den Interrupts zu verdanken, da die in der Priorität höher liegen.
 
Sagen wir IRQ.0 ist immer 0,
Ok, das ist klar. Also kommt es nirgendwo rein, hab ich auch nicht. In Zeile 55 steht If Irq.0 = 1 Then und dann muss ich vor dem Return in Zeile 102 noch mal Irq.0 = 1 reinsetzen, da sonst gar nichts erscheint. Aber das Irq.0 = 0 brauche ich nicht, das löscht ja alles wieder.
 
Das IRQ.0 = 0 brauchst du, aber nur in der Main Loop, bzw. genauer gesagt nachdem du das Display neu gezeichnet hast. Dann ist es ja nicht mehr "dreckig". Zumindest so lange bis irgendeine ISR wieder anzuzeigende Werte verändert, das Display also neu gezeichnet werden muss, und somit wieder IRQ.0 auf 1 setzt.
Und ja, stimmt, in Tick_1s vorm Return fehlt das IRQ.0=1 noch, war mir gar nicht aufgefallen.

Und IRQ.0 = 0 löscht nichts (zumindest klang das missverständlich). Das Display wird dann einfach nicht aktualisiert, das was drauf steht bleibt stehen.
Daher sagte ich das mit der LED am LCD E Pin. So siehst du den Unterschied. Du könntest auch eine andere LED nehmen die an irgendeinem Pin hängt. Nehmen wir mal in Gedanken eine rote. Vor Idle machst du sie aus, danach an. Je heller sie leuchtet desto mehr ist die CPU ausgelastet. Ist zwar eine Milchmädchenrechnung, weil die ISR nicht mit rein fällt (obwohl gearbeitet wird ist sie aus), aber zur Veranschaulichung reicht es.
 
Habe ich mit und ohne Irq.0 = 1 getestet. In beiden Varianten leuchtet sie schwächer als normal an +5V. Allerdings kann man mit Irq.0 = 1 erkennen, dass sie erst schwach und dann etwas heller, aber immer noch schwächer als bei +5V brennt. Aber wo genau kommt das Irq.0 = 0 hin.
 
Du hast auch noch ne ziemlich lange Wait nach dem Beschreiben des Displays drin, kA warum.
Eigentlich dürfte die LED nur im Sekundentakt blinken.
Wenn die Abfrage If Irq.0 = 1 weg fällt müsste sie immer leuchten (nahezu).

Aber wo genau kommt das Irq.0 = 0 hin.
Hab ich doch grade eben gesagt.....
... bzw. genauer gesagt nachdem du das Display neu gezeichnet hast.
Ich helf dir gerne, wirklich. Aber lesen musst du schon selber
arf.gif
 
Entschuldige bitte!
Machmal hab ich totales Blackout und kann das gelesene nicht verarbeiten.
Habe schon verstanden, dass es in die Main Loop rein kommt, genauer gesagt in Zeile 55. Das ist es ja auch drin gewesen #846. Ich hatte es aus irgend welchen Gründen oder Unklarheiten raus genommen. Jetzt passt alles wieder.
Die Led leuchte zwar dauerhaft, aber im Sekundentakt bekommt sie wohl kleine Stromstöße.
 
Kann gut sein dass der Bus nicht 100% sauber ist, also wirklich auf 0 oder 5V zieht.
Beispielsweise I2C arbeitet mit "unsauberen" VCC, also entweder 5V durch PullUps oder auf 0V gezogen. Eine LED daran kann schon für Probleme sorgen, weil sie zu viel Strom zieht. Im Zweifelsfall mal anders herum polen. Also statt
Pin ---|>|---[Rv]--- GND
mal
Pin ---|<|---[Rv]--- 5V
bzw. anders herum. Das Leuchten ist dann natürlich inventiert.
 
Hmm, merkwürdig. Ich kann es leider nicht selber testen, mangels Mega8 und *funktionierendem* Bascom.
Die Uralt Version die mal lief hab ich wohl nicht mehr.
Aber vielleicht mag das ja mal wer anders nachstecken.

Wobei anders herum Dauerleuchten klingt gut, die Aus Impulse müssten auch sehr kurz sein. Kannst ja die LED im Programm auch inventieren, vielleicht ist es so leichter zu sehen.
Aber grob gesagt ist es eigentlich egal, es müsste so gehen.

Also weiter zum Datum.
 

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