Bascom BASCOM ; Erste Schritte zum Ausprobieren



CodeBox BascomAVR
Else
         Countdown = 10 * 60

Fehler
value doesn't fit into Byte (Wert passt nicht in Byte)
 
Das ist die Visual Basic und C# Schreibweise. Ich bin aus Bascom ja schon länger raus, daher weiß ich nicht in wie weit die sich angepasst haben.
Also ein Byte ist ja klar. 8 Bit. Mögliche Werte 0..255.
Etwas größer wäre ein Int16. Das wären 16 Bit, also 2 Bytes. Mögliche Werte -32768 .. +32767.
Ein UInt16 ist fast das gleiche, belegt auch 16 Bit, aber kann keine negativen Zahlen beinhalten. Mögliche Werte: 0..65535.
Das U besagt es ist Unsigned, also ohne Vorzeichen. Int besagt dass es eine Ganzzahl ist. 16 die Bitbreite. Das selbe mit 32 und 64, dementsprechend ist der Bereich auch größer.

Eben ergoogelt, in Bascom wird ein UInt16 immer noch Word genannt.
Siehe hier: https://halvar.at/elektronik/kleiner_bascom_avr_kurs/variablen/

Betrifft dich also nicht direkt, aber es ist Hintergrundwissen was nie verkehrt ist.
 
Kenne diese Seite auch andere von halvar.at, da ich immer wieder nachschlagen muss. Steht aber nicht das jetzt drin, wie ich auf 16 Bit mutiplizieren muss.
Habe jetzt einfach einen Test gemacht und funktioniert mit kleinen Zahlen (wegen der Wartezeit nur kleine Zahlen).

CodeBox BascomAVR
Else
         Countdown = Zeichen * 10
 
Das sollte Bascom egal sein, nur das Ergebnis muss in die (Ziel)Variable passen.
Mit *10 kommst du immerhin auf maximal 2550 Sekunden = 44,3 Minuten.
Mit *60 (Angabe in Minuten) auf max. 15300 Sekunden = 255 Minuten = 4,25 Stunden.
Mit *120 wären es dann 8,5 Stunden, würde passen. Für die Funktion gut, blöd hingegen zum testen ;)
 
Ich habe jetzt mal *60 geschrieben und ASCII 0x3C, was 60 bedeuten soll. dann schau ich mal nach ca 55 Minuten nach.
Das hat alles funktioniert. Ich könnte demzufolge einen Countdown von max. mit *240 wären es dann 17 Stunden aktivieren. Das mit dem multiplizieren hat mich durcheinander gebracht. Wusste nicht, dass man das Zeichen, welches eine Variable ist, einfach *2 nehmen kann.

CodeBox BascomAVR
$regfile = "m8def.dat"                  'Controllerdefinitionsdatei einbinden
$crystal = 8000000                      'Systemtakt angeben (Baudrate)
$hwstack = 40                           'Stacks
$swstack = 16
$framesize = 32
$baud = 19200                           'Baudrate UART
Dim Zeichen As Byte                     'UART-Empfang
Dim Z As Byte
Dim Fla As Byte
Dim Pause As Byte
Dim Pausex2 As Byte
Dim Tov1cnt As Byte
Dim Countdown As Word
Rot Alias Portd.7                       'Namen für LED-Beine
Gruen Alias Portc.3
Config Rot = Output                     'Ausgänge
Config Gruen = Output
Rot = 1                                 'LEDs erstmal an
Gruen = 1
'Phasenkorrekter 8-Bit-PWM, PWM-Frequenz=245Hz
Config Timer1 = Pwm , Prescale = 64 , Compare A Pwm = Clear Down , Compare B Pwm = Clear Down
Pwm1b = 100
'ADC aktivieren (single conversion, Prescaler Auto, AVcc (INTERN!!!)
Config Adc = Single , Prescaler = Auto , Reference = Avcc
Do                                      'Hauptschleife Begin
    'erstes Teilprogramm - UART Empfang und auswerten
   If Ischarwaiting() = 1 Then          'Wenn Zeichen Empfangen
      Zeichen = Inkey()                 'dann Zeichen aus Puffer lesen
      If Zeichen = "1" Then             'Wenn Zeichen = "1"
         Rot = 1                        '...
         Print "Led An"
      Elseif Zeichen = "0" Then         'Wenn Zeichen = "0"
         Rot = 0                        '...
         Print "Led Aus"
      Elseif Zeichen = "t" Then         'Wenn Zeichen = "t"
         Toggle Rot                     '...
         Print "Toggle Led"
      Elseif Zeichen = "?" Then         'Wenn Zeichen = "?"
         If Rot = 0 Then                'Dann wenn Led aus ist...
            Print "Led ist aus"
         Elseif Rot = 1 Then            'sonst wenn Led an ist...
            Print "Led ist an"
         End If
      Elseif Zeichen = 0 Then           'bei 0x00 PWM deaktivieren
         Config Timer1 = Pwm , Prescale = 64 , Compare A Pwm = Disconnect , Compare B Pwm = Disconnect
      Elseif Zeichen = 255 Then         'bei 0xFF PWM aktivieren
         Config Timer1 = Pwm , Prescale = 64 , Compare A Pwm = Clear Down , Compare B Pwm = Clear Down
      Else
         Countdown = Zeichen * 60
         Config Timer1 = Pwm , Prescale = 64 , Compare A Pwm = Clear Down , Compare B Pwm = Clear Down
      End If
   End If
   'zweites Teilprogramm - LED durch timer blinken lassen
   If Tifr.tov1 = 1 Then                'wenn Timer übergelaufen ist
      Set Tifr.tov1                     'Überlaufflag zurücksetzen
      Incr Tov1cnt                      'überlaufzähler inkrementieren
      If Pause = Tov1cnt Then           'entspricht dem 2ten "waitms pause"
         Fla = Rnd(200)
         Fla = Fla + 55
         Pwm1a = Fla
      End If
      If Pausex2 = Tov1cnt Then         'entspricht dem ersten "waitms pause"
         Pwm1b = 255 - Fla
         Pause = Rnd(10)
         Pause = Pause * 6
         Pausex2 = Pause
         Shift Pausex2 , Left           'pausex2=pause*2
         Tov1cnt = 0
      End If
      Incr Z
      If Z = 245 Then                   'Überläufe zählen (245)
         Z = 0                          'Zähler zurücksetzen
         Toggle Gruen                   'LED toggeln
         If Countdown = 0 Then
            Config Timer1 = Pwm , Prescale = 64 , Compare A Pwm = Disconnect , Compare B Pwm = Disconnect
         Else
            Decr Countdown
         End If
      End If
   End If
Loop
Wie geht es nun weiter?
Die Steuerung geht immer noch über UART. Das andere wäre noch, dass dieser Code auch auf nem Tiny13 funktionieren würde #290. Wäre mir angenehmer.
 
Zuletzt bearbeitet:
Das mit den Sekunden war schon absichtlich so gewählt, um damit rumexperimentieren zu können, ohne Stundenlang warten zu müssen.
Wenn Du den Countdown so gestartet hast, kannst Du trotzdem zwischendurch mi den UART-Kommandos 0x00 und 0xFF an und ausschalten - nach den vorgegebenen Sekunden schaltet der Countdown zuverlässig ab.
Der Vorgabewert entsprach der Leuchtdauer in Sekunden - wie man das auf Leuchtdauer in Minuten oder gar Stunden umwandeln könnte, habt ihr ja schon geklärt.

Ok, was war das eigentliche Ziel?
Die LEDs sollten nach Tastendruck 8h leuchten - und dann ausgehen...
Wie ein Tastendruck durch Polling abzufragen ist, ist klar.
Wie das Flackern zu starten, und das Flackern selbst zu realisieren ist (ohne die anderen "Threads" zu blockieren) auch.
Wie ein Countdown (jetzt eben mit irgendeinem fixen Vorgabewert sodaß 8h erreicht werden) auch.
Wie das Flackern dann abgeschaltet werden kann auch.
Eigentlich solltest Du das Problem jetzt also selbst angehen können...

Hab grad nicht viel Zeit - Danke Thomas...
 
Hatte ich schon mal gesagt:
Nur zu Interrupts:

Im Moment nutzt du Polling. Du hast eine Anwendungsschleife die konstant durchläuft. Darin sind Teilprogramme die nur dann ausgeführt werden wenn eine Bedienung erfüllt ist (IsCharWaiting, Tifr.tov1 = 1, ...). Wenn nichts davon erfüllt ist startet die Schleife von vorne und fragt wieder den Zustand ab (=Polling, also abfragen / ziehen des Zustandes). Sorgt aber auch für 100% CPU Last und somit hohen Stromverbrauch*.

Bei Interrupts ist es fast das Selbe, nur dass du nicht abfragst sondern Routinen hast die automatisch aufgerufen werden, von der Hardware. Deine Hauptschleife, da gibt es 2 Möglichkeiten.
Möglichkeit 1:
Du behandelst alles in der Interrupt Routine selbst, also alles was dann ausgeführt werden soll.
Das hat aber Nachteile sollte hier viel (zeitintensiver) Code laufen, wie z.B. Schreiben auf ein LCD. Es kann nur ein Interrupt gleichzeitig arbeiten (nicht ganz richtig, reicht aber erst mal). Beispiel, dein ADC hat einen neuen Wert fertig, Interrupt läuft, schreibt auf ein LCD. Aber währenddessen treten 20 Timer Events auf. Blöd, weil die verpasst du währenddessen.
Möglichkeit 2:
Du setzt in der Interrupt Routine nur ein Flag, welches in der Hauptschleife abgefragt wird. Dort, also losgelöst vom Interrupt, wird dann der Code ausgeführt. So würde der ADC Code in der Hauptroutine (unterbrechbar) ausgeführt werden und den Timer nicht beeinflussen.

Wie auch immer, wenn man mit Interrupts arbeitet nutzt man auch den Sleep Befehl. Damit wird die CPU schlafen gelegt wenn die Hauptschleife fertig ist. Geweckt wird er wieder durch Interrupts. Es wird also nach Sleep weiter gearbeitet.

Allerdings bleibt der Code selbst größtenteils gleich, er ist nur anders angeordnet.

*hoher Stromverbrauch ist bei AVR's natürlich relativ zu sehen, aber bei batteriegetriebenen Anwendungen ist das durchaus relevant.
 
Irgendwo hatten wir es schon mal dass du einen Taster abgefragt hast.
Da hattest du glaube ich eine LED getoggelt.
Wenn man das Alte jetzt nimmt und statt wie früher die LED zu toggeln einfach den Countdown auf Wert X zu setzen (X ist die Zahl die du für 8 Stunden brauchst) und PWM aktivierst, kannst du deine Kerze anzünden ohne PC.

Ich würde aber vielleicht erst mal den Code etwas strukturieren.
Es entwickelt sich so langsam ein Rattenschwanz, den man in ein paar Monaten nicht mehr versteht ;)

Speicher dir dein Programm erst mal ab, nicht dass es nachher vermurkst ist.

Du kannst mit Labeln (=Sprungmarken) und Befehlen wie Goto, Gosub und Return deinen Code strukturieren.
Goto springt zu einer Sprungmarke, Gosub macht quasi das selbe, allerdings kann mit Return wieder zurück gesprungen werden zu dem Punkt nach dem Gosub Befehl. Ändert an deinem Code nahezu nichts, aber so kannst du die Teilbereiche besser voneinander trennen.

Beispiel:


CodeBox BascomAVR
' Die Controller Initialisierung

Main: ' Die Haupt Anwendungsschleife
   If Bedienung1 = 1 Then Gosub Bedienung1Erfuellt
   If Bedienung2 = 1 Then Gosub Bedienung2Erfuellt
   'Sleep ' Controller in Sleep Mode versetzen -- machen wir später
   'Reset Watchdog ' Watchdog zurücksetzen -- machen wir später
Goto Main

Bedienung1Erfuellt:
   ' Tu was
Return

Bedienung2Erfuellt:
   ' Tu was
Return


Deine äußere Do-Loop wurde durch Sprungmarke und Goto ersetzt, bewirkt aber exakt das Gleiche. Der Name Main ist absichtlich so gewählt. Kann man natürlich nennen wie man will, aber das hat sich so eingebürgert.
In der Hauptschleife fragst du nur noch die Bedienungen ab und startest dann die jeweiligen Unterprogramme.
Hier sollte man die Namen natürlich möglichst sinnvoll wählen. Beispielsweise OnTimer1Overflow oder OnAdcComplete...

Unterroutinen können auch weitere Unterroutinen aufrufen.
Du fragst ja ab ob der Timer abgelaufen ist. -> OnTimer1Overflow.
Darin fragst du ab ob der Timer x mal übergelaufen ist um an deine 1 Sekunde Intervalle zu kommen -> Tick1Sec
Dann haben wir noch die serielle Schnittstelle. -> OnUartRx

Soweit klar?
 
Speicher dir dein Programm erst mal ab, nicht dass es nachher vermurkst ist.
Das mache ich immer, nach einem Erfolgreichen Teilabschluß, von NoEcho bis Poti und letztes Countdown.
Jetzt kommt Goto, Gosub, Watchdog und OnTimer1Overflow. Alles Dinge, von denen ich schon gelesen aber nichts richtig verstanden habe.
Also nehme ich eine neue Datei und kopiere aus #347 Zeilen 1-21 und aus #352 Zeilen 3-16 hinein. Aber da wird erst einmal nicht passieren, vermute ich.
 
Watchdog ist eher ein kleines Sidequest ;)
Aber ist sehr schnell erklärt.
Es handelt sich hierbei um eine Art Wachhund (daher der Name). Dieser läuft quasi als 2. System nebenher. Hast du den ein mal scharf gestellt (über Start Watchdog) oder auch über die Fuses des Controllers, dann bist du, bzw. dein Programm dazu verpflichtet ihn fortlaufend zu resetten. Sonst wird davon ausgegangen dass sich dein Programm "aufgehängt" oder "festgefahren" hat und es wird ein Reset durchgeführt. Sehr sinnvoll das Ganze. Selbst meinen Server hat es letztens mal erwischt, da hat der Hund zugebissen.
8067

Aber außer Start und Reset ist da nicht großartig was zu beachten.
Wobei @LotadaC jetzt wieder einwerfen wird dass man ihn auch als zusätzlichen Timer gebrauchen kann. Ja, kann man, ist zwar nicht so ganz im Sinne des Erfinders, aber "who cares?" :)
Das wäre für hier aber zu viel.

Technisch gesehen ist es einfach nur ein Timer mit eigener Clock. Läuft der über -> Reset des Controllers. Und jedes WDR / Reset Watchdog setzt den Zähler wieder auf 0 zurück.
 
Ein Wächter, konnte ich mir schon denken. Aber wie wird das dann geschrieben? Wann wird er eingesetzt?
Aber was und wie könnte ich in #352 mal einsetzten, um die Funktionsweise von Goto, Gosub zu testen bzw. über das Steckbrett die Led's zu signalisieren und zu beobachten, was passiert. Ich bin jetzt Neugierig.
 
Eingesetzt wird er... Ok, das ist jetzt Geschmackssache. Ich sage: immer. Die Industrie schreibt sowas sogar strikt vor. Als Hobbybastler für eine LED Steuerung... Naja, wenn sie es mal nicht mehr tut, Stecker raus und wieder rein, irgendwann fällt es ja auf. Das Problem ist das "irgendwann". Stell dir vor dein Programm hängt sich auf und da hängen große Aktoren (wie Motoren, Pneumatik oder Hydraulik) dran. Kann böse teuer werden. Da ist so ein Wachhund der im Fehlerfall zubeißt und das System in einen sicheren Zustand versetzt Gold wert.

Mach es dir nicht ganz so kompliziert. Fang mal ein neues Programm an.
Den Initialisierungs Teil kannst du ja kopieren. Ist ja die selbe Hardware.

Setz das so um wie in meinem letzten Beispiel.
Als Abfrage machen wir erst mal die Abfrage ob der Taster gedrückt ist. Wenn ja springe in Routine 1, wenn nicht in Routine 2.
Routine 1 schaltet die LED an, Routine 2 schaltet sie wieder aus.
Ich weiß, es ist dämlich, weil man es direkt zuweisen könnte, aber hier geht es ja um das Verstehen.
 
Ich musste erst einmal wiede alles ins Gedächtnis zurück holen. Aber ich denke mal, das ist es, was erfüllt werden sollte.
Bei nicht gedrückte Taster ist Rot=aus, Blau=an und bei gedrücktem Taster Rot=an, Blau=aus.

CodeBox BascomAVR
$regfile = "m8def.dat"                  'Controllerdefinitionsdatei einbinden
$crystal = 8000000                      'Systemtakt angeben (Baudrate)
$hwstack = 40                           'Stacks
$swstack = 16
$framesize = 32
$baud = 19200                           'Baudrate UART
Dim Zeichen As Byte                     'UART-Empfang
Dim Z As Byte
Dim Fla As Byte
Dim Pause As Byte
Dim Pausex2 As Byte
Dim Tov1cnt As Byte
Dim Countdown As Word
Ddrc = &B_00_0000
Portc = &B11_1111
Ddrd = &B_1111_1111
Portd = &B0000_0000
Rot Alias Portd.7
Blau Alias Portd.6
Taster Alias Pinc.3
Rot = 0
Blau = 0
Main:                                   ' Die Haupt Anwendungsschleife
   If Taster = 0 Then Gosub Bedienung1erfuellt
   If Taster = 1 Then Gosub Bedienung2erfuellt
   'Sleep ' Controller in Sleep Mode versetzen -- machen wir später
   'Reset Watchdog ' Watchdog zurücksetzen -- machen wir später
   Goto Main
Bedienung1erfuellt:
   Rot = 1
   Blau = 0
Return
Bedienung2erfuellt:
   Rot = 0
   Blau = 1
Return
 
Perfekt :)
Richtig auf den ersten Versuch. :top:

Das war jetzt ja nur ein kleines Beispiel zum Verständnis. Wenn alles klar ist können wir uns jetzt um das Hauptprogramm kümmern und das dort ähnlich machen.

Du hast es ja schon richtig kommentiert, erstes Teilprogramm, zweites Teilprogramm...
Dein erstes kümmert sich ja um den Uart, das Zweite um den Timer Überlauf.
Vom Prinzip musst du jetzt nur das umsetzen was du jetzt gelernt hast (der Taster kommt später, erst mal nur aufräumen)
 
Ich verstehe nicht ganz, wie Du das meinst. Die #347 mit Gosub umschreiben. Also zB. Zeile 49 Ne Quatsch. Ich weiß momentan nicht wie ich anfangen soll.
 
Zuletzt bearbeitet:
Aus #347.
Da hast du ja Zeile 27ff und 54ff deine 2 Teilprogramme.
Die If hast du da schon. Jetzt nur den Inhalt auslagern, wie in dem Taster Programm.
If IsCharWaiting Then Gosub...
Und so weiter.
Die eigentliche Aktion, also was jetzt in der If ist, in eine Routine packen, wie im Lerncode wo du die LEDs gesetzt hast.
 

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