Archiv verlassen und diese Seite im Standarddesign anzeigen : [ERLEDIGT] TIME funktioniert nicht beim ATtiny44, wie kann ich das Problem lösen?
Naubaddi
13.02.2025, 13:38
Hi,
habe mit einem 4 Zeilen Display und einem ATtiny44 einen einfachen Lichtschranken Rundenzähler für Schlitzrennbahnen gebastelt, hat alles gut funktioniert bis ich einen Zeitzähler brauchte der die Durchfahrt eines Slotcar korrekt erkennt und nur eine Runde zählt. Na ja, es funktioniert ( do : waitms 50 : until Spur_1 = 0 ) mit dem Nachteil das während den 50 ms die Spur 2 nicht erfasst wird wenn die Slotcars gleichzeitig durch die Lichtschranke fahren. Am PC war das kein Problem da bei Gambas man einfach mit ( Signal = Time : If Signal + 100 < time then : durchfahrt = 1 : endif ), und so etwas schaffe ich nicht mit Bascom.
Das ganze Programm:
' Compiler: Bascom-Demo 2.0.7.5
' Dateiname: Formel X.avr
' Funktion: ein Rundenzähler für Schlitzautos mit einem ATtiny44 auf einem 20x4 Display
' Datum: Start 01.02.2025, Stand 12.02.2025
' Von: Naubaddi foto-schubser@arcor.de
'
' ATtiny44 (B.3 RESET)
'
' +----v----+
' VCC | 1 14| GND
' PCINT8/XTAL1 B.0 | 2 13| A.0 ADC0/AREF/PCINT0
' PCINT9/XTAL2 B.1 | 3 12| A.1 ADC1/AIN0/PCINT1
' PCINT11/RESET/dW B.3 | 4 11| A.2 ADC2/AIN1/PCINT2
' PCINT10/INT0/OC0A/CKOUT B.2 | 5 10| A.3 ADC3/T0/PCINT3
' PCINT7/ICP/OC0B/ADC7 A.7 | 6 9| A.4 ADC4/USCK/SCL/T1/PCINT4
' PCINT6/OC1A/SDA/MOSI/ADC6 A.6 | 7 8| A.5 ADC5/DO/MISO/OC1B/PCINT5
' +---------+
'
' --- Mikrocontroler Daten... ----------------------------------------------------------------------------------
$regfile = "attiny44.dat"
$crystal = 8000000
$hwstack = 40
$swstack = 40
$framesize = 40
' --- Deklarationen... -----------------------------------------------------------------------------------------
enable interrupts
config timer0 = timer , prescale = 256
on timer0 Timer_0
disable timer0
config porta = output
config portb = input
config lcdpin = pin , Db4 = porta.2 , Db5 = porta.3 , Db6 = porta.4 , Db7 = porta.5 , E = porta.0 , Rs = porta.1
config lcd = 20 * 4
cursor off : cls
Ampel_1 alias porta.6 : Ampel_1 = 0 ' Spannung für die Ampel Spur 1
Ampel_2 alias porta.7 : Ampel_2 = 0 ' Spannung für die Ampel Spur 2
Spur_1 alias pinb.1 ' Spur 1 und Auswahl -
Spur_2 alias pinb.2 ' Spur 2 und Auswahl +
Start_Stopp alias pinb.0 ' das Rennen starten/stoppen
' --- Variablen... ---------------------------------------------------------------------------------------------
dim Soll as byte : Soll = 122 ' 122,07 ist ca. eine Sekunde
dim Ist as byte : Ist = 1 ' Zeit-Zähler bis Ist > Soll erreicht wurde
dim blinken as byte : blinken = 0 ' blinken für die Runden, die Ampel, den Fehlstart...
dim Runden as byte : Runden = 20 ' die Anzahl der Runden für ein Rennen
dim Runde_Spur_1 as byte : Runde_Spur_1 = 0 ' die gefahrenen Runden auf Spur 1
dim Runde_Spur_2 as byte : Runde_Spur_2 = 0 ' die gefahrenen Runden auf Spur 2
dim Ampel as byte : Ampel = 0 ' die Startampel für Spur 1 und/oder Spur 2
dim Ampel_Z as byte : Ampel_Z = 0 ' ein Zähler für das Blinken der Ampel
dim Fehlstart as byte : Fehlstart = 0 ' ein Fahrer ist vor dem Startsignal losgefahren
dim rennen as byte : rennen = 0 ' läuft das Rennen? 0 = nein, 1 = ja
dim Z_formatiert as string * 2 : Z_formatiert = "" ' Zahlen rechtsbündige formatieren
' --- Programm Anfang ------------------------------------------------------------------------------------------
Z_formatiert = str(Runden)
locate 1,1 : lcd "Formel X " ; format(Z_formatiert , " ") ; " Runden"
locate 2,1 : lcd "--------------------"
locate 3,1 : lcd "Spur 1 ---- Runde 0"
locate 4,1 : lcd "Spur 2 ---- Runde 0"
do
gosub Runden_einstellen
if rennen = 1 then
Z_formatiert = str(Runden)
locate 1,12 : lcd ; format(Z_formatiert , " ") ; " Runden"
locate 2,1 : lcd "--------------------"
locate 3,1 : lcd "Spur 1 ---- Runde 0"
locate 4,1 : lcd "Spur 2 ---- Runde 0"
Runde_Spur_1 = 0 : Runde_Spur_2 = 0
Ampel = 0 : Ampel_1 = 0 : Ampel_2 = 0
gosub Ampelphase
if rennen = 1 then
do
if Spur_1 = 1 then
incr Runde_Spur_1
Z_formatiert = str(Runde_Spur_1)
locate 3,19 : lcd ; format(Z_formatiert , " ")
do : waitms 55 : loop until Spur_1 = 0
end if
if Spur_2 = 1 then
incr Runde_Spur_2
Z_formatiert = str(Runde_Spur_2)
locate 4,19 : lcd ; format(Z_formatiert , " ")
do : waitms 55 : loop until Spur_2 = 0
end if
if Runde_Spur_1 > Runden then
rennen = 0 : Ampel_1 = 1
locate 2,1 : lcd "- * ----------------"
locate 3,1 : lcd "Spur 1 hat gewonnen "
end if
if Runde_Spur_2 > Runden then
rennen = 0 : Ampel_2 = 1
locate 2,1 : lcd "---------------- * -"
locate 4,1 : lcd "Spur 2 hat gewonnen "
end if
if rennen = 0 then
do : waitms 55 : loop until Start_Stopp = 1
do : waitms 55 : loop until Start_Stopp = 0
locate 2,1 : lcd "--------------------"
else
gosub Abbruch
endif
loop until rennen = 0
end if
end if
loop
' --- Prozeduren, Funktionen... --------------------------------------------------------------------------------
Runden_einstellen:
Ampel_Z = 0 : blinken = 0
Ist = 1 : Soll = 122
enable timer0
do
if blinken = 1 then
locate 1,15 : lcd " "
else
locate 1,15 : lcd "Runden"
end if
if Spur_1 = 1 then
decr Runden
if Runden < 2 then : Runden = 99 : end if
Z_formatiert = str(Runden)
locate 1,12 : lcd ; format(Z_formatiert , " ") ; " Runden"
waitms 222
end if
if Spur_2 = 1 then
incr Runden
if Runden > 99 then : Runden = 2 : end if
Z_formatiert = str(Runden)
locate 1,12 : lcd ; format(Z_formatiert , " ") ; " Runden"
waitms 222
end if
loop until Start_Stopp = 1
rennen = 1
do : waitms 55 : loop until Start_Stopp = 0
disable timer0
return
' --------------------------------------------------------------------------------------------------------------
Ampelphase:
Ampel_Z = 0 : blinken = 0
Ist = 1 : Soll = 122 ' 122 = normal blinken, 33 = Fehlstart blinken
enable timer0
do
if Ampel_Z < 6 or Soll = 33 then
if Soll = 33 then : Ampel_Z = 0 : end if
if blinken = 1 then
Select case Ampel
case 0 : locate 2,1 : lcd "- * ------------ * -" : Ampel_1 = 1 : Ampel_2 = 1
case 1 : locate 2,1 : lcd "- * ------------ -" : Ampel_1 = 1 : Ampel_2 = 0
case 2 : locate 2,1 : lcd "- ------------ * -" : Ampel_1 = 0 : Ampel_2 = 1
end select
else
locate 2,1 : lcd "- ------------ -" : Ampel_1 = 0 : Ampel_2 = 0
end if
end if
if Soll <> 33 then
if Spur_1 = 1 then
Fehlstart = 3 : Ampel = 1
end if
if Spur_2 = 1 then
Fehlstart = 4 : Ampel = 2
end if
end if
if Fehlstart > 0 then
locate Fehlstart,8 : lcd " Fehlstart "
Fehlstart = 0
Ist = 1 : Soll = 33
end if
gosub Abbruch
loop until Ampel_Z > 9 or rennen = 0
locate 2,1 : lcd "--------------------" : Ampel_1 = 0 : Ampel_2 = 0
disable timer0
return
' --------------------------------------------------------------------------------------------------------------
Abbruch:
If Start_Stopp = 1 then
locate 2,1 : lcd "--------------------"
locate 3,8 : lcd " Abbruch "
locate 4,8 : lcd " --------- "
rennen = 0
do : waitms 55 : loop until Start_Stopp = 0
end if
return
' --------------------------------------------------------------------------------------------------------------
Timer_0:
if Ist > Soll then
Ist = 1
if blinken = 0 then
blinken = 1
else
blinken = 0
end if
incr Ampel_Z
else
incr Ist
end if
return
' --- Programm Ende --------------------------------------------------------------------------------------------
end
' --------------------------------------------------------------------------------------------------------------
und die Zeilen mit dem Problem:
if Spur_1 = 1 then
incr Runde_Spur_1
Z_formatiert = str(Runde_Spur_1)
locate 3,19 : lcd ; format(Z_formatiert , " ")
do : waitms 55 : loop until Spur_1 = 0
end if
if Spur_2 = 1 then
incr Runde_Spur_2
Z_formatiert = str(Runde_Spur_2)
locate 4,19 : lcd ; format(Z_formatiert , " ")
do : waitms 55 : loop until Spur_2 = 0
end if
Was ich brauche ist so etwas:
if Spur_1 = 1 then
if einfahrt = 0 then
einfahrt = time + 100
end if
if einfahrt < time then
incr Runde_Spur_1
Z_formatiert = str(Runde_Spur_1)
locate 3,19 : lcd ; format(Z_formatiert , " ")
einfahrt = 0
end if
end if
Hat Jemand eine Idee zu diesem Problem?
Grüßle, Naubaddi
Naubaddi
14.02.2025, 16:13
Hi,
es funktioniert, wenn auch mit sehr viel mehr Code und Variablen. Da timer0 nicht während dem Rennen benötigt wird kann er jetzt die Durchfahrt der Lichtschranke Spur 1 überwachen, für Spur 2 wurde der timer2 angelegt. Da es jetzt 2 Timer sind mussten alle benötigten Variablen verdoppelt werden, z.B. wurde aus "Ist, Soll" "Ist_1,Ist_2, Soll_1, Soll_2" usw. damit sich die 2 Timer nicht ins Gehege kommen.
' Compiler: Bascom-Demo 2.0.7.5
' Dateiname: Formel X.avr
' Funktion: ein Rundenzähler für Schlitzautos mit einem ATtiny44 auf einem 20x4 Display
' Datum: Start 01.02.2025, Stand 14.02.2025
' Von: Naubaddi foto-schubser@arcor.de
'
' ATtiny44 (B.3 RESET)
'
' +----v----+
' VCC | 1 14| GND
' PCINT8/XTAL1 B.0 | 2 13| A.0 ADC0/AREF/PCINT0
' PCINT9/XTAL2 B.1 | 3 12| A.1 ADC1/AIN0/PCINT1
' PCINT11/RESET/dW B.3 | 4 11| A.2 ADC2/AIN1/PCINT2
' PCINT10/INT0/OC0A/CKOUT B.2 | 5 10| A.3 ADC3/T0/PCINT3
' PCINT7/ICP/OC0B/ADC7 A.7 | 6 9| A.4 ADC4/USCK/SCL/T1/PCINT4
' PCINT6/OC1A/SDA/MOSI/ADC6 A.6 | 7 8| A.5 ADC5/DO/MISO/OC1B/PCINT5
' +---------+
'
' --- Mikrocontroler Daten... ----------------------------------------------------------------------------------
$regfile = "attiny44.dat"
$crystal = 8000000
$hwstack = 40
$swstack = 40
$framesize = 40
' --- Deklarationen... -----------------------------------------------------------------------------------------
enable interrupts
config timer0 = timer , prescale = 256
on timer0 Timer_0
disable timer0
config timer1 = timer , prescale = 1
on timer1 Timer_1
disable timer1
config porta = output
config portb = input
config lcdpin = pin , Db4 = porta.2 , Db5 = porta.3 , Db6 = porta.4 , Db7 = porta.5 , E = porta.0 , Rs = porta.1
config lcd = 20 * 4
cursor off : cls
Ampel_1 alias porta.6 : Ampel_1 = 0 ' Spannung für die Ampel Spur 1
Ampel_2 alias porta.7 : Ampel_2 = 0 ' Spannung für die Ampel Spur 2
Spur_1 alias pinb.1 ' Spur 1 und Auswahl -
Spur_2 alias pinb.2 ' Spur 2 und Auswahl +
Start_Stopp alias pinb.0 ' das Rennen starten/stoppen
' --- Variablen... ---------------------------------------------------------------------------------------------
dim Soll_1 as byte : Soll_1 = 122 ' 122,07 ist ca. eine Sekunde
dim Ist_1 as byte : Ist_1 = 1 ' Zeit-Zähler bis Ist > Soll erreicht wurde
dim blinken_1 as Byte : blinken_1 = 0 ' blinken für die Runden, die Ampel, den Fehlstart...
dim Ampel_Z_1 as byte : Ampel_Z_1 = 0 ' ein Zähler für das blinken der Ampel
dim Soll_2 as byte : Soll_2 = 122 ' 122,07 ist ca. eine Sekunde
dim Ist_2 as byte : Ist_2 = 1 ' Zeit-Zähler bis Ist > Soll erreicht wurde
dim blinken_2 as Byte : blinken_2 = 0 ' blinken für die Runden, die Ampel, den Fehlstart...
dim Ampel_Z_2 as byte : Ampel_Z_2 = 0 ' ein Zähler für das blinken der Ampel
dim Runden as Byte : Runden = 20 ' die Anzahl der Runden für ein Rennen
dim Runde_Spur_1 as Byte : Runde_Spur_1 = 0 ' die gefahrenen Runden auf Spur 1
dim Spur_1PZ as Byte : Spur_1PZ = 0 ' die Prellzeit für Spur 1
dim Runde_Spur_2 as Byte : Runde_Spur_2 = 0 ' die gefahrenen Runden auf Spur 2
dim Spur_2PZ as Byte : Spur_2PZ = 0 ' die Prellzeit für Spur 2
dim Ampel as Byte : Ampel = 0 ' die Startampel für Spur 1 und/oder Spur 2
dim Fehlstart as Byte : Fehlstart = 0 ' ein Fahrer ist vor dem Startsignal losgefahren
dim rennen as byte : rennen = 0 ' läuft das Rennen? 0 = nein, 1 = ja
dim Z_formatieren as string * 2 : Z_formatieren = "" ' Zahlen rechtsbündige formatieren
' --- Programm Anfang ------------------------------------------------------------------------------------------
Z_formatieren = str(Runden)
locate 1,1 : lcd "Formel X " ; format(Z_formatieren , " ") ; " Runden"
locate 2,1 : lcd "--------------------"
locate 3,1 : lcd "Spur 1 ---- Runde 0"
locate 4,1 : lcd "Spur 2 ---- Runde 0"
do
gosub Runden_einstellen
if rennen = 1 then
Z_formatieren = str(Runden)
locate 1,12 : lcd ; format(Z_formatieren , " ") ; " Runden"
locate 2,1 : lcd "--------------------"
locate 3,1 : lcd "Spur 1 ---- Runde 0"
locate 4,1 : lcd "Spur 2 ---- Runde 0"
gosub Ampelphase
if rennen = 1 then
Runde_Spur_1 = 0 : Runde_Spur_2 = 0
Spur_1PZ = 0 : Spur_2PZ = 0
do
if Spur_1 = 1 or Spur_1PZ <> 0 then
if Spur_1PZ = 0 then
incr Runde_Spur_1
Z_formatieren = str(Runde_Spur_1)
locate 3,19 : lcd ; format(Z_formatieren , " ")
Ist_1 = 0 : Soll_1 = 122 : Spur_1PZ = 1
enable timer0
else
if Spur_1PZ > 60 then
disable timer0
Spur_1PZ = 0
end if
end if
end if
if Spur_2 = 1 or Spur_2PZ <> 0 then
if Spur_2PZ = 0 then
incr Runde_Spur_2
Z_formatieren = str(Runde_Spur_2)
locate 4,19 : lcd ; format(Z_formatieren , " ")
Ist_2 = 0 : Soll_2 = 122 : Spur_2PZ = 1
enable timer1
else
if Spur_2PZ > 60 then
disable timer1
Spur_2PZ = 0
end if
end if
end if
if Runde_Spur_1 > Runden then
rennen = 0 : Ampel_1 = 1
locate 2,1 : lcd "- * ----------------"
locate 3,1 : lcd "Spur 1 hat gewonnen "
end if
if Runde_Spur_2 > Runden then
rennen = 0 : Ampel_2 = 1
locate 2,1 : lcd "---------------- * -"
locate 4,1 : lcd "Spur 2 hat gewonnen "
end if
if rennen = 0 then
do : waitms 55 : loop until Start_Stopp = 1
do : waitms 55 : loop until Start_Stopp = 0
locate 2,1 : lcd "--------------------"
else
gosub Abbruch
endif
loop until rennen = 0
end if
end if
loop
' --- Prozeduren, Funktionen... --------------------------------------------------------------------------------
Runden_einstellen:
Ist_1 = 1 : Soll_1 = 122 : blinken_1 = 0
enable timer0
do
if blinken_1 = 1 then
locate 1,15 : lcd " "
else
locate 1,15 : lcd "Runden"
end if
if Spur_1 = 1 then
decr Runden
if Runden < 2 then : Runden = 99 : end if
Z_formatieren = str(Runden)
locate 1,12 : lcd ; format(Z_formatieren , " ") ; " Runden"
waitms 222
end if
if Spur_2 = 1 then
incr Runden
if Runden > 99 then : Runden = 2 : end if
Z_formatieren = str(Runden)
locate 1,12 : lcd ; format(Z_formatieren , " ") ; " Runden"
waitms 222
end if
loop until Start_Stopp = 1
disable timer0
rennen = 1
do : waitms 55 : loop until Start_Stopp = 0
return
' --------------------------------------------------------------------------------------------------------------
Ampelphase:
Ist_1 = 1 : Soll_1 = 122 : blinken_1 = 0 ' 122 = normal blinken, 33 = Fehlstart blinken
Ampel_Z_1 = 0 : Ampel = 0
enable timer0
do
if Ampel_Z_1 < 6 or Soll_1 = 33 then
if Soll_1 = 33 then : Ampel_Z_1 = 0 : end if
if blinken_1 = 1 then
Select case Ampel
case 0 : locate 2,1 : lcd "- * ------------ * -" : Ampel_1 = 1 : Ampel_2 = 1
case 1 : locate 2,1 : lcd "- * ------------ -" : Ampel_1 = 1 : Ampel_2 = 0
case 2 : locate 2,1 : lcd "- ------------ * -" : Ampel_1 = 0 : Ampel_2 = 1
end select
else
locate 2,1 : lcd "- ------------ -" : Ampel_1 = 0 : Ampel_2 = 0
end if
end if
if Soll_1 <> 33 then
if Spur_1 = 1 then
Fehlstart = 3 : Ampel = 1
end if
if Spur_2 = 1 then
Fehlstart = 4 : Ampel = 2
end if
end if
if Fehlstart > 0 then
locate Fehlstart,8 : lcd " Fehlstart "
Fehlstart = 0
Ist_1 = 1 : Soll_1 = 33
end if
gosub Abbruch
loop until Ampel_Z_1 > 9 or rennen = 0
disable timer0
locate 2,1 : lcd "--------------------" : Ampel_1 = 0 : Ampel_2 = 0 : Ampel = 0
return
' --------------------------------------------------------------------------------------------------------------
Abbruch:
If Start_Stopp = 1 then
locate 2,1 : lcd "--------------------"
locate 3,8 : lcd " Abbruch "
locate 4,8 : lcd " --------- "
rennen = 0
do : waitms 55 : loop until Start_Stopp = 0
end if
return
' --------------------------------------------------------------------------------------------------------------
Timer_0:
if Ist_1 > Soll_1 then
Ist_1 = 1
if blinken_1 = 0 then
blinken_1 = 1
else
blinken_1 = 0
end if
incr Ampel_Z_1
else
incr Ist_1
incr Spur_1PZ
end if
return
Timer_1:
if Ist_2 > Soll_2 then
Ist_2 = 1
if blinken_2 = 0 then
blinken_2 = 1
else
blinken_2 = 0
end if
incr Ampel_Z_2
else
incr Ist_2
incr Spur_2PZ
end if
return
' --- Programm Ende --------------------------------------------------------------------------------------------
end
' --------------------------------------------------------------------------------------------------------------
Grüßl, Naubaddi
Naubaddi
15.02.2025, 13:42
Hi,
habe mal ein Foto von dem fertigen Rundenzähler gemacht, so kann man besser erkennen worum es geht.
36046
Grüßle, Naubaddi
021aet04
16.02.2025, 16:08
Hallo Naubaddi und Willkommen im Forum
Sorry für die späte Antwort. Ich würde dein Programm ein bisschen ändern.
Ich kenne mich mit Bascom nicht aus, dadurch kann ich dir keinen Code zur Verfügung stellen.
Ich kann es aber als Pseudocode schreiben, den du in Bascom ändern kannst.
Ich weiß nicht ob Bascom Interrupts unterstützt, wenn ja, dann würde ich diese verwenden.
In den Interrupt schreibst du (wenn du pro Spur einen Interrupt hast, "x" ist deine Spur):
Runden_Spur_x = Runden_Spur_x + 1
Oder wenn du einen Pin Change Interrupt hast und beide Spuren in einem Interrupt verarbeitest:
Spur_1_Flanke = Spur_1 und nicht Flankenmerker_Spur_1
Spur_2_Flanke = Spur_2 und nicht Flankenmerker_Spur_2
if Spur_1_Flanke then
Runden_Spur_1 = Runden_Spur_1 +1
endif
if Spur_2_Flanke then
Runden_Spur_2 = Runden_Spur_2 +1
endif
Flankenmerker_Spur_1 = Spur_1
Flankenmerker_Spur_2 = Spur_2
Wenn du die Eingänge per Sorftware entprellen willst, dann würde ich eine kurze Zeit wählen (z.B. 1ms) und zum Entprellen zählen. Den Hilfsmerker verknüpfst du mit dem Eingang für die Spur, mit dem du dann den Rundenzähler erhöhst. (Also z.B. Spur1 und nicht Hilfsmerker1 => Rundenzähler + 1)
Z.B. so
Hauptschleife:
...
...
...
...
...
...
if Spur_1_Flanke then
Hilfsmerker_Spur_1 = 1
Entprellung_Spur_1 = 0
endif
if Hilfsmerker_Spur_1 = 1 then
if Entprellung_Spur_1 < 50 then
Entprellung_Spur_1 = Entprellung_Spur_1 + 1
else
Hilfsmerker_Spur_1 = 0
endif
Gleicher Ablauf für Spur 2
Warte 1ms
Wenn du Interrupts verwendest, dann musst du den Code, den ich in der Hauptschleife geschrieben habe, in den Interrupt geben.
Solltest du keinen Interrupt verwenden können, dann musst du den gesamten Teil in die Hauptschleife geben.
Schöner Aufbau, sehr gut.
edit: Was mir noch aufgefallen ist, ist die Variable "Blinken..." in Timer 0. Dort schreibst du:
if blinken = 1 then
blinken = 0
else
blinken = 1
endif
einfacher wäre:
blinken = nicht blinken
MfG Hannes
Naubaddi
17.02.2025, 11:05
Hi Hannes,
Danke für die Anregungen und die Beispiele wie man es machen kann.
...Ich weiß nicht ob Bascom Interrupts unterstützt...
Ja, BASCOM hat Interrupts welche ich auch benutze: timer0 für Spur 1 und timer1 für Spur 2, es sind die 2 Prozeduren am Ende des Programms. Das Programm funktioniert mittlerweile ja auch sehr zuverlässig, ein paar Verbesserungen und gut ist.
...Was mir noch aufgefallen ist, ist die Variable "Blinken..."...
Die "if Blinken_1 = 0 then..." Schleife wurde auf Dein Anregen durch ein einfaches "toggle Blinken_1" ersetzt.
...Wenn du die Eingänge per Sorftware entprellen willst, dann würde ich eine kurze Zeit wählen (z.B. 1ms) ...
Die Prellzeit muß lang sein weil z.B. das GoKart sehr viele Lücken hat und bei der Durchfahrt ca. 8 Runden zählt :-( , da reicht 1ms nicht aus.
36048
So sieht es jetzt aus:
' Compiler: Bascom-Demo 2.0.7.5
' Dateiname: Formel X.avr
' Funktion: ein Rundenzähler für Schlitzautos mit einem ATtiny44 auf einem 20x4 Display
' Datum: Start 01.02.2025, Stand 17.02.2025
' Von: Naubaddi foto-schubser@arcor.de
'
' ATtiny44 (B.3 RESET)
'
' +----v----+
' VCC | 1 14| GND
' PCINT8/XTAL1 B.0 | 2 13| A.0 ADC0/AREF/PCINT0
' PCINT9/XTAL2 B.1 | 3 12| A.1 ADC1/AIN0/PCINT1
' PCINT11/RESET/dW B.3 | 4 11| A.2 ADC2/AIN1/PCINT2
' PCINT10/INT0/OC0A/CKOUT B.2 | 5 10| A.3 ADC3/T0/PCINT3
' PCINT7/ICP/OC0B/ADC7 A.7 | 6 9| A.4 ADC4/USCK/SCL/T1/PCINT4
' PCINT6/OC1A/SDA/MOSI/ADC6 A.6 | 7 8| A.5 ADC5/DO/MISO/OC1B/PCINT5
' +---------+
'
' --- Mikrocontroler Daten... ----------------------------------------------------------------------------------
$regfile = "attiny44.dat"
$crystal = 8000000
$hwstack = 40
$swstack = 40
$framesize = 40
' --- Deklarationen... -----------------------------------------------------------------------------------------
enable interrupts
config timer0 = timer , prescale = 256 ' bei 8 Bit 256 für ca. eine Sekunde
on timer0 Timer_0
disable timer0
config timer1 = timer , prescale = 1 ' bei 16 Bit 1 für ca. eine Sekunde
on timer1 Timer_1
disable timer1
config porta = output
config portb = input
config lcdpin = pin , Db4 = porta.2 , Db5 = porta.3 , Db6 = porta.4 , Db7 = porta.5 , E = porta.0 , Rs = porta.1
config lcd = 20 * 4
cursor off : cls
Ampel_1 alias porta.6 : Ampel_1 = 0 ' Spannung für die Ampel Spur 1
Ampel_2 alias porta.7 : Ampel_2 = 0 ' Spannung für die Ampel Spur 2
Spur_1 alias pinb.1 ' Spur 1 und Auswahl -
Spur_2 alias pinb.2 ' Spur 2 und Auswahl +
Start_Stopp alias pinb.0 ' das Rennen starten/stoppen
' --- Variablen... ---------------------------------------------------------------------------------------------
dim Soll_1 as byte : Soll_1 = 122 ' 122,07 ist ca. eine Sekunde
dim Ist_1 as byte : Ist_1 = 1 ' Zeit-Zähler bis Ist_1 > Soll_1 erreicht wurde
dim blinken_1 as bit : blinken_1 = 0 ' blinken für die Runden, die Ampel, den Fehlstart...
dim Ampel_Z_1 as byte : Ampel_Z_1 = 0 ' ein Zähler für das blinken der Ampel
dim Soll_2 as byte : Soll_2 = 122 ' 122,07 ist ca. eine Sekunde
dim Ist_2 as byte : Ist_2 = 1 ' Zeit-Zähler bis Ist_2 > Soll_2 erreicht wurde
dim blinken_2 as bit : blinken_2 = 0 ' blinken für die Runden, die Ampel, den Fehlstart...
dim Ampel_Z_2 as byte : Ampel_Z_2 = 0 ' ein Zähler für das blinken der Ampel
dim Runden as byte : Runden = 20 ' die Anzahl der Runden für ein Rennen
dim Runde_Spur_1 as byte : Runde_Spur_1 = 0 ' die gefahrenen Runden auf Spur 1
dim Spur_1PZ as byte : Spur_1PZ = 0 ' die Prellzeit für Spur 1
dim Runde_Spur_2 as byte : Runde_Spur_2 = 0 ' die gefahrenen Runden auf Spur 2
dim Spur_2PZ as byte : Spur_2PZ = 0 ' die Prellzeit für Spur 2
dim Ampel as byte : Ampel = 0 ' die Startampel für Spur 1 und/oder Spur 2
dim Fehlstart as byte : Fehlstart = 0 ' ein Fahrer ist vor dem Startsignal losgefahren
dim rennen as byte : rennen = 0 ' läuft das Rennen? 0 = nein, 1 = ja
dim Z_formatiert as string * 2 : Z_formatiert = "" ' Zahlen rechtsbündige formatieren
' --- Programm Anfang ------------------------------------------------------------------------------------------
Z_formatiert = str(Runden)
locate 1,1 : lcd "Formel X " ; format(Z_formatiert , " ") ; " Runden"
locate 2,1 : lcd "--------------------"
locate 3,1 : lcd "Spur 1 ---- Runde 0"
locate 4,1 : lcd "Spur 2 ---- Runde 0"
do
gosub Runden_einstellen
if rennen = 1 then
Z_formatiert = str(Runden)
locate 1,12 : lcd ; format(Z_formatiert , " ") ; " Runden"
locate 2,1 : lcd "--------------------"
locate 3,1 : lcd "Spur 1 ---- Runde 0"
locate 4,1 : lcd "Spur 2 ---- Runde 0"
gosub Ampelphase
if rennen = 1 then
Runde_Spur_1 = 0 : Runde_Spur_2 = 0
Spur_1PZ = 0 : Spur_2PZ = 0
do
if Spur_1 = 1 or Spur_1PZ <> 0 then
if Spur_1PZ = 0 then
Ampel_1 = 1 : locate 2,1 : lcd "- * -"
incr Runde_Spur_1 : Z_formatiert = str(Runde_Spur_1)
locate 3,19 : lcd ; format(Z_formatiert , " ")
Ist_1 = 0 : Soll_1 = 222 : Spur_1PZ = 1
enable timer0
Ampel_1 = 0 : locate 2,1 : lcd "-----"
else
if Spur_1PZ > 120 then
disable timer0
Spur_1PZ = 0
end if
end if
end if
if Spur_2 = 1 or Spur_2PZ <> 0 then
if Spur_2PZ = 0 then
Ampel_2 = 1 : locate 2,16 : lcd "- * -"
incr Runde_Spur_2 : Z_formatiert = str(Runde_Spur_2)
locate 4,19 : lcd ; format(Z_formatiert , " ")
Ist_2 = 0 : Soll_2 = 222 : Spur_2PZ = 1
enable timer1
Ampel_2 = 0 : locate 2,16 : lcd "-----"
else
if Spur_2PZ > 120 then
disable timer1
Spur_2PZ = 0
end if
end if
end if
if Runde_Spur_1 > Runden then
rennen = 0 : Ampel_1 = 1
locate 2,1 : lcd "- * -"
locate 3,1 : lcd "Spur 1 hat gewonnen "
end if
if Runde_Spur_2 > Runden then
rennen = 0 : Ampel_2 = 1
locate 2,16 : lcd "- * -"
locate 4,1 : lcd "Spur 2 hat gewonnen "
end if
if rennen = 0 then
do : waitms 55 : loop until Start_Stopp = 1
do : waitms 55 : loop until Start_Stopp = 0
locate 2,1 : lcd "--------------------"
Ampel_1 = 0 : Ampel_2 = 0
else
gosub Abbruch
endif
loop until rennen = 0
end if
end if
loop
' --- Prozeduren, Funktionen... --------------------------------------------------------------------------------
Runden_einstellen:
Ist_1 = 1 : Soll_1 = 122 : blinken_1 = 0
enable timer0
do
if blinken_1 = 1 then
locate 1,15 : lcd " "
else
locate 1,15 : lcd "Runden"
end if
if Spur_1 = 1 then
decr Runden
if Runden < 2 then : Runden = 99 : end if
Z_formatiert = str(Runden)
locate 1,12 : lcd ; format(Z_formatiert , " ") ; " Runden"
waitms 222
end if
if Spur_2 = 1 then
incr Runden
if Runden > 99 then : Runden = 2 : end if
Z_formatiert = str(Runden)
locate 1,12 : lcd ; format(Z_formatiert , " ") ; " Runden"
waitms 222
end if
loop until Start_Stopp = 1
disable timer0
rennen = 1
do : waitms 55 : loop until Start_Stopp = 0
return
' --------------------------------------------------------------------------------------------------------------
Ampelphase:
Ist_1 = 1 : Soll_1 = 122 : blinken_1 = 0 ' 122 = normal blinken, 33 = Fehlstart blinken
Ampel_Z_1 = 0 : Ampel = 0
enable timer0
do
if Ampel_Z_1 < 6 or Soll_1 = 33 then
if Soll_1 = 33 then : Ampel_Z_1 = 0 : end if
if blinken_1 = 1 then
Select case Ampel
case 0 : locate 2,1 : lcd "- * ------------ * -" : Ampel_1 = 1 : Ampel_2 = 1
case 1 : locate 2,1 : lcd "- * ------------ -" : Ampel_1 = 1 : Ampel_2 = 0
case 2 : locate 2,1 : lcd "- ------------ * -" : Ampel_1 = 0 : Ampel_2 = 1
end select
else
locate 2,1 : lcd "- ------------ -"
Ampel_1 = 0 : Ampel_2 = 0
end if
end if
if Soll_1 <> 33 then
if Spur_1 = 1 then
Fehlstart = 3 : Ampel = 1
end if
if Spur_2 = 1 then
Fehlstart = 4 : Ampel = 2
end if
end if
if Fehlstart > 0 then
locate Fehlstart,8 : lcd " Fehlstart "
Fehlstart = 0
Ist_1 = 1 : Soll_1 = 33
end if
gosub Abbruch
loop until Ampel_Z_1 > 9 or rennen = 0
disable timer0
locate 2,1 : lcd "--------------------"
Ampel_1 = 0 : Ampel_2 = 0 : Ampel = 0
return
' --------------------------------------------------------------------------------------------------------------
Abbruch:
If Start_Stopp = 1 then
locate 2,1 : lcd "--------------------"
locate 3,8 : lcd " Abbruch "
locate 4,8 : lcd " --------- "
rennen = 0
do : waitms 55 : loop until Start_Stopp = 0
end if
return
' --------------------------------------------------------------------------------------------------------------
Timer_0:
if Ist_1 > Soll_1 then
Ist_1 = 1
toggle blinken_1
incr Ampel_Z_1
else
incr Ist_1
incr Spur_1PZ
end if
return
Timer_1:
if Ist_2 > Soll_2 then
Ist_2 = 1
toggle blinken_2
incr Ampel_Z_2
else
incr Ist_2
incr Spur_2PZ
end if
return
' --- Programm Ende --------------------------------------------------------------------------------------------
end
' --------------------------------------------------------------------------------------------------------------
Grüßle, Hermann
021aet04
17.02.2025, 20:39
Ich meinte nicht das du nur 1ms misst.
In der Hauptschleife fügst du ein delay von 1ms ein (somit hast du einen Schleifendurchlauf von Programmablauf + 1ms).
Wenn die Lichtschranke ein Fahrzeug erkennt (und vorher noch keines erkannt wurde) setzt du einen Merker (=Fahrzeug erkannt).
Gleichzeitig setzt du einen Counter auf 0.
Wenn du ein Fahrzeug erkannt hast (Merker) zählst du in jedem Schleifendurchlauf den Counter hoch.
Wenn der Counter z.B. 50 erreicht hat (entspricht mindestens 50ms), dann gibst du die die Fahrzeugerkennung wieder frei (Merker "Fahrzeug erkannt" wieder auf "0" setzen).
Ich hoffe das du es jetzt besser verstanden hast was ich meine.
Edit: Den Merker benötigst du natürlich für jede Spur ein mal.
MfG Hannes
Naubaddi
18.02.2025, 08:44
Hi,
wenn ich es richtig verstanden habe sollte es so aussehen:
waitms 1
if Spur_1 = 1 then
Durchfahrt_1 = 1 : Zeit_1 = 0
end if
if Durchfahrt_1 = 1 then
incr Zeit_1
end if
if Zeit_1 = 50 then
Ampel_1 = 1 : locate 2,1 : lcd "- * -"
incr Runde_Spur_1 : Z_formatiert = str(Runde_Spur_1)
locate 3,19 : lcd ; format(Z_formatiert , " ")
Ampel_1 = 0 : locate 2,1 : lcd "-----"
end if
if Zeit_1 > 1000 then
Durchfahrt_1 = 0 : Zeit_1 = 0
end if
es funktioniert wie meine Version:
if Spur_1 = 1 or Spur_1PZ <> 0 then
if Spur_1PZ = 0 then
Ampel_1 = 1 : locate 2,1 : lcd "- * -"
incr Runde_Spur_1 : Z_formatiert = str(Runde_Spur_1)
locate 3,19 : lcd ; format(Z_formatiert , " ")
Ist_1 = 0 : Soll_1 = 222 : Spur_1PZ = 1
enable timer0
Ampel_1 = 0 : locate 2,1 : lcd "-----"
else
if Spur_1PZ > 120 then
disable timer0
Spur_1PZ = 0
end if
end if
end if
Grüßle, Hermann
Searcher
18.02.2025, 12:25
Hallo Hermann,
ich verfolge den thread auch schon einige Tage. Ich denke, eine richtige Entprellung wie für prellende Tasten ist bei Dir nicht nötig. Sobald eine Lichtschranke von einem Auto getriggert wurde, könnte schon eine Runde gezählt werden. Wegen der Lücken im Auto dann einfach die Zählung der entsprechenden Spur für eine notwendige Zeit unterbinden um die Mehrfachzählung bei einer Durchfahrt zu verhindern.
Das hast Du ja im Prinzip mit der Prellzeit etc. schon verwirklicht.
Ich schlage dazu, ich nenne es mal "Monoflop" vor:
Programm:
Der Timer 0 erzeugt alle etwa 10ms einen compare0a Interrupt
In der Interruptserviceroutine wird der Ablauf der Monoflops realisiert.
In der Hauptschleife werden die Lichtschranken abgefragt. (bei Autodurchfahrt werden sie "0")
Ist eine Lichtschranke "0" und das entsprechende Monoflop = "0" wird die Runde gezählt und die Monoflop Zeit "aufgezogen"
Der Timer0 hat nach der Ablaufzeit das Monoflop wieder scharf geschaltet. Das Auto ist durch, die Lichtschranke auf "1" und somit bereit für die nächste Durchfahrt.
$regfile = "ATtiny44.DAT"
$framesize = 24
$swstack = 20
$hwstack = 34
$crystal = 8000000
const deadtime = 100 '100 * 10ms of copmare0a interrupt
opto_1 alias pina.1 'light barrier track 1
opto_2 alias pina.2 'light barrier track 2
porta.1 = 1 'pullup opto_1
porta.2 = 1 'pullup opto_2
ocr0a = 78
config timer0 = timer , prescale = 1024 , CLEAR_TIMER = 1 'about 10 milliseconds compare0A interrupt
on compare0a isr_deadtime
enable COMPARE0A
enable interrupts
dim monoflop_1 as byte
dim monoflop_2 as byte
dim round_1 as byte 'round counter
dim round_2 as byte 'round counter
do
if opto_1 = 0 and monoflop_1 = 0 then
incr round_1
monoflop_1 = deadtime
endif
if opto_2 = 0 and monoflop_2 = 0 then
incr round_2
monoflop_2 = deadtime
endif
loop
isr_deadtime:
if monoflop_1 > 0 then decr monoflop_1
if monoflop_2 > 0 then decr monoflop_2
return
end 'end program
Gruß
Searcher
Naubaddi
18.02.2025, 17:43
Hi Searcher,
das gefällt mir, weniger Zeilen und damit auch übersichtlicher :-). Es funktioniert mit einer kleinen Änderung, da ich an den Foto-LEDs mit einem Transistor die Polung invertiere bedarf es eine 1 bei "opto_1 = 0..." oder die Transistoren wieder entfernen. Die Namen der Variablen werde ich im fertigen Programm so umbennenen das ich sie in X Jahren noch wiedererkenne ;-).
Was ich noch nicht verstehe:
* ocr0a = 78 --- Wer oder was ist das?
* compare0a --- Wer oder was ist das, warum nicht timer0?
Das kleine Testprogramm sieht dann so aus:
' --- Mikrocontroler Daten... ----------------------------------------------------------------------------------
$regfile = "attiny44.dat"
$crystal = 8000000
$hwstack = 40 ' $hwstack = 34
$swstack = 40 ' $swstack = 20
$framesize = 40 ' $framesize = 24
' --- Deklarationen... -----------------------------------------------------------------------------------------
enable interrupts
ocr0a = 78
config timer0 = timer , prescale = 1024 , CLEAR_TIMER = 1 ' about 10 milliseconds compare0A interrupt
on compare0a isr_deadtime '
enable COMPARE0A
config porta = output
config portb = input
config lcdpin = pin , Db4 = porta.2 , Db5 = porta.3 , Db6 = porta.4 , Db7 = porta.5 , E = porta.0 , Rs = porta.1
config lcd = 20 * 4
cursor off : cls
opto_1 alias pinb.1 ' light barrier track 1
opto_2 alias pinb.2 ' light barrier track 2
' --- Variablen... ---------------------------------------------------------------------------------------------
const deadtime = 100 ' 100 * 10ms of copmare0a interrupt
dim monoflop_1 as byte
dim monoflop_2 as byte
dim round_1 as byte ' round counter
dim round_2 as byte ' round counter
dim Z_formatiert as string * 2 : Z_formatiert = "" ' Zahlen rechtsbündige formatieren
' --- Programm Anfang ------------------------------------------------------------------------------------------
locate 1,1 : lcd "Formel X 20 Runden"
locate 2,1 : lcd "--------------------"
locate 3,1 : lcd "Spur 1 ---- Runde 0"
locate 4,1 : lcd "Spur 2 ---- Runde 0"
do
if opto_1 = 1 and monoflop_1 = 0 then
incr round_1
Z_formatiert = str(round_1)
locate 3,1 : lcd "Spur 1 ---- Runde" ; format(Z_formatiert , " ")
monoflop_1 = deadtime
endif
if opto_2 = 1 and monoflop_2 = 0 then
incr round_2
Z_formatiert = str(round_2)
locate 4,1 : lcd "Spur 1 ---- Runde" ; format(Z_formatiert , " ")
monoflop_2 = deadtime
endif
loop
' --- Prozeduren, Funktionen... --------------------------------------------------------------------------------
isr_deadtime:
if monoflop_1 > 0 then decr monoflop_1
if monoflop_2 > 0 then decr monoflop_2
return
' --- Programm Ende --------------------------------------------------------------------------------------------
end
Grüßle, Hermann
Searcher
18.02.2025, 18:33
Was ich noch nicht verstehe:
* ocr0a = 78 --- Wer oder was ist das?
* compare0a --- Wer oder was ist das, warum nicht timer0?
Hi,
der Timer0 ist so konfiguriert, daß er bei einem Vergleichswert zurückgesetzt wird und nicht erst bei seinem Maximalwert von 255.
Das ist das CLEAR_TIMER = 1 bei der Timerconfiguration. Der Vergleichswert steht in dem Register OCR0A mit dem Wert 78.
Wenn der Timer bis 78 gezählt hat wird er zurückgesetzt und NICHT das Timer0/Overflow0 Interrupt Flag gesetzt, sondern das Compare0a Interrupt Flag.
Der Timer hat ja nicht seinen Maximalwert erreicht.
Der µC läuft mit 8MHz. Timer Prescale ist 1024. Der Timer läuft also mit 7812,5Hz. Pro Timerstep also 1/7812,5Hz = 0,128ms. Von 0 bis zum Wert 78 im OCR0A Register braucht er also 0,128ms * 78 = 9,984ms und noch einen Step zurück auf 0 für eine komplette Timerrunde (10,112ms). Richtiger wäre also OCR0A = 77 (komplette Timerrunde in 0,009984s) weil man dann genauer an die gewollten 10ms Abstände des Interrupts herankommt.
Gruß
Searcher
Searcher
19.02.2025, 06:25
Es gäbe noch weitere Verbesserungen, die man implementieren könnte.
Wenn in der Hauptschleife die Lichtschranken abgefragt werden, könnte es passieren, daß ein Auto mal nicht erfaßt wird. Das ist abhängig von der Laufzeit der Hauptschleife. Je länger die läuft, desto wahrscheinlicher ist es, daß ein Auto durchrutscht, ohne daß die Lichtschrankenabfrage gerade dran ist.
Könnte man zB mit Interrupts verhindern. Ich würde PCINT0 und PCINT1 dafür hernehmen. Da diese aber einmal von allen Pins des ganzen PortA und zum anderen von allen Pins des PortB ausgelöst werden können, könnte man eine Lichtschranke an den PortB umverkabeln. Das macht den Code kleiner, da man sonst extra Code zur Feststellung des auslösenden Pins eines Ports benötigt. Damit bekommt man auch wieder eine weiter ganz kleine Unsicherheit, da zwischen Interrupt und Pinbestimmung Zeit vergeht.
Wenn also ein PCINT ausgelöst wurde setzt man in der ISR ein Flag und disabled den PCINT. Das Flag wird in der in der Haupschleife abgefragt, bei abgelaufenem Monoflop die Runde gezählt und das Flag zurücksetzt. Nach Ablauf des Monoflops muß das PCINT-Flag gelöscht werden, da durch die Mehfachauslösung der Lichtschranke noch ein Interruptflag stehen könnte, daß dann ungewollt die PCINT ISR nochmal auslöst. Und dann der PCINT wieder freigeben.
So sollte das Risiko einer Fehlzählung ziemlichh minimiert sein.
Gruß
Searcher
Naubaddi
19.02.2025, 16:42
Hi,
die Fragen:
* ocr0a = 78 --- Wer oder was ist das?
* compare0a --- Wer oder was ist das, warum nicht timer0?
sind gut beantwortet, habe die Antwort aufgeschrieben bei den vielen gesammelten Infos zu BASCOM.
Das ein Fahrzeug nicht erkannt wird ist auszuscließen, 1 mal haben beide Spuren gewonnen als die Lichtschranken synchron unterbrochen wurden. Das Problem war die mehrfach Zählung weil die Abfrage so irre schnell ist.
36050
Grüßle, Hermann
Searcher
20.02.2025, 06:04
Das ein Fahrzeug nicht erkannt wird ist auszuscließen, ...
36050
Prima! Weiter viel Erfolg und Freude.
Gruß
Searcher
Powered by vBulletin® Version 4.2.5 Copyright ©2025 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.