PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Drehzahl- und Geschwindigkeitsmessung ATMEGA88 BASCOM



therealosram
01.08.2014, 00:36
Hallo an das Forum,

Ich weiß, hier verwenden die meisten Leute C oder Assembler.
Ich würde aber gerne weiter in BASCOM Programmieren, da es VB ähnelt und ich damit beruflich zu tun habe.

Ich würde gern für eine Fahrende Bierkiste Drehzahl und Geschwindigkeit auslesen.
Der Bau der Geber stellt kein Problem dar. Die Zündung und die Antriebswelle sollen pro Umlauf nur ein Signal abgeben, aber ich verstehe die Funktionsweise der Timer nicht.

Mein Plan ist den Timer1 laufen zu lassen, die Drehzahl aus der Differenz eines alten und neuen Wertes zu errechnen und bei Erreichen des Geschwindigkeitssensor den Timer auf null zu setzen.

Der Timer läuft hoch, aber die Interrupts lösen anscheinend nicht aus

hier der Code:


$regfile = "m88def.dat"
$crystal = 16000000
$hwstack = 40
$swstack = 40
$framesize = 40

'Display Einrichten
Config Lcdpin = Pin , _
Db4 = Portb.0 , Db5 = Portd.7 , Db6 = Portd.1 , Db7 = Portd.0 , E = Portb.4 , Rs = Portb.5

Config Lcd = 16 * 2

Dim Drehzahl As Word
Dim Geschwindigkeit As Word
Dim D_timer_1 As Single
Dim D_timer_2 As Single
Dim G_timer As Single
Dim Timer_multi As Single

Config Pind.2 = Input 'drehzahl
Config Pind.3 = Input 'Geschwindigkeit

Portd.2 = 1
Portd.3 = 1

On Int0 Dreh_route
On Int1 Gesw_route
On Timer1 Timer_over

Config Int0 = Rising
Enable Int0
Config Int1 = Rising
Enable Int1
Enable Interrupts

Enable Timer1
Start Timer1

Config Timer1 = Timer , Edge = Rising , Prescale = 1024 'so niedrig, dass erlangsam zählt

Timer_multi = 1

Do
Cls
Upperline : Lcd Drehzahl ; " " ; Geschwindigkeit
Lowerline : Lcd D_timer_1 ; " " ; Timer1
Waitms 20
Loop

End

Dreh_route:
D_timer_2 = Tcnt1 * Timer_multi
If D_timer_2 > D_timer_1 Then Drehzahl = D_timer_2 - D_timer_1
D_timer_1 = D_timer_2
Return

Gesw_route:
G_timer = Timer1 * Timer_multi
Geschwindigkeit = G_timer
Timer1 = 0
Timer_multi = 0
Return

Timer_over:
Timer_multi = Timer_multi + 1
If Timer_multi > 100 Then Timer_multi = 1
Return

End

Michael
01.08.2014, 12:10
Die Edge-Option solltest du beim Timer weglassen, wenn du ihn nicht als Counter benutzt.
Die Berechnung der Drehzahl sieht mir auch nicht gut aus. Hier willst du den Timerwert erfassen (Periodendauer) und daraus den Kehrwert errechnen (Frequenz = Drehzahl) Der Überlauf kommt nur, wenn die Drehzahl zu niedrig ist.

Gruß, Michael

therealosram
21.10.2014, 22:43
Nochmals hallo an das Forum.

Ich verzweifel hier echt und versteht die Timer irgendwie nicht. Auch die verschiedenen Tutorials zu den Timer raff ich nicht. Vielleicht denk ich auch nicht genug um die Ecke.

Ich möchte nur gleichzeitig die Drehzahl von Motor 500-8000 (0,002-0,000125sec/puls) und der Achse 1-20 (1-0,05sec/puls) auslesen.
Nehm ich dann alle drei Timer und lasse einen bis zum Überlauf zählen und zähle dann die anderen zusammen?
Zu was würdet ihr mir raten, unabhängig in welcher Sprache ihr arbeitet. Ich möchte nur das System verstehen.

Grüße

Besserwessi
22.10.2014, 19:44
Die Drehzahlen werden üblicherweise in Umdrehungen pro Minute angegeben, je Sekunde ist das dann nur 1/60 der Umdrehungen bzw. Pulse. Ggf. kann aber der Aufnehmer mehr als 1 Puls je Umdrehung geben.

Der Übliche weg ist es einen Timer durchlaufen zu lassen, und dann jeweils die Zeiten auszulesen und die Differenzen zu bilden. Den Timer sollte man dabei nicht zurücksetzen, sondern besser den Überlauf richtig berücksichtigen - das ist nicht so schwer, aber ggf. je nach Compiler / Sprache etwas verschieden. Wie das in C geht sieht man etwa in Wissens Artikel unter Timer(AVR) - Input Capture. Wegen der recht verschiedenen Drehzahlen wird bei nur einem 16 Bit timer die Auflösung für die hohe Drehzahl eher klein. Da wäre es schon hilfreich die Auflösung des Timers in Software zu erweitern (zählen der Überläufe) oder ggf. alternativ die Zeit für mehr als 1 Periode zu Messen.

Wenn der µC 2 16 Bit Timer hätte, könnte man auch je Drehzahl einen Timer nutzen und so ohne die Erweiterung der Auflösung auskommen. Ein 8 bit Timer hilft aber nicht weiter, denn da kann man auch gleich den 16 Bit timer auf 32 Bit erweitern und damit alle erledigen.

therealosram
23.11.2014, 14:41
Hier jetzt mal der aktuelle Code.


$regfile = "m88def.dat"
$prog &HFF , &HE2 , &HDF , &HF9 ' generated. Take care that the chip supports all fuse bytes.
$hwstack = 128
$framesize = 128
$swstack = 128

Config Lcdpin = Pin , Db4 = Portc.3 , Db5 = Portc.2 , Db6 = Portd.0 , _
Db7 = Portd.1 , E = Portb.4 , Rs = Portb.5
Config Lcd = 16 * 2
Cursor Off

Config Timer1 = Timer , Prescale = 64

Config Int0 = Falling
Config Int1 = Falling

On Int0 Ges 'Geschwindigkeit
On Int1 Dre 'Drehzahl
On Timer1 Timer_irq

Enable Int0
Enable Int1
Enable Timer1

Config Sda = Portc.4
Config Scl = Portc.5
Config Portd.2 = Input
Config Portd.3 = Input
Config Portd.0 = Output

Pind.2 = 1
Pind.3 = 1

Dim G_pre As Long
Dim G_set As Word
Dim G_calc As Single
Dim G_out As Integer

Dim D_pre As Long
Dim D_set As Word
Dim D_out As Integer

Do
Upperline : Lcd " " ; D_out ; " " ; G_calc ; " "
Lowerline : Lcd " " ; Timer1 ; " "
Waitms 1000
Loop

Ges:
G_calc = G_set - G_pre
G_pre = G_set
G_set = Timer1
Return

Dre:
D_out = D_set - D_pre
D_pre = D_set
D_set = Timer1
Return

Timer_irq:
D_pre = D_pre - 65535
G_pre = G_pre - 65535
Return


End

Was mach ich falsch, dass er die Trigger INT0/1 gegen Masse nicht erkennt und die Differenz zwischen den 'pre" und 'set' nicht ausgibt?

malthy
23.11.2014, 15:11
Hi,

unabhängig von allem anderen: Du musst die Interrupts noch global einschalten


Enable Interrupts

Gruß
Malte

Searcher
23.11.2014, 15:12
Hallo,



Was mach ich falsch, dass er die Trigger INT0/1 gegen Masse nicht erkennt und die Differenz zwischen den 'pre" und 'set' nicht ausgibt?

Gibt er nichts aus oder nur das falsche? Auf jeden Fall fehlt das "Enable Interrupts". Ob der Rest paßt habe ich nicht überprüft.

Gruß
Searcher

Besserwessi
23.11.2014, 15:54
Die Art wie Überläufe berücksichtigt werden sieht interessant aus - könnte aber fast funktionieren (2^16 ist einer mehr). Ein Problem gibt es ggf. mit einem Überlauf beim Ergebnis, da nur integer. Der grobe Fehler ist erst einmal das fehlende globale einschalten der Interrupts.

Schließlich gibt es ggf. noch eine seltenes Problem wenn der Timer Überlauf und der Int0/1 fast gleichzeitig kommen. Da ist es nicht so einfach zu entscheiden ob der Überlauf vor oder hinter dem Interrupt kommt. Ich fürchte der Prescaler von 64 reicht noch nicht aus um da seltene Fehler zu vermeiden. Wie das richtig gehen kann, steht im RN-Wissen unter Timer(AVR), da allerdings unter Ausnutzung der Hardware ICP Funktion.

therealosram
23.11.2014, 18:48
Oh man. Wie so oft lag das Problem zwischen den Ohren.
Oder wie hier mal jemand schrieb: "uC machen nicht immer was sie sollen, aber alles was man ihnen sagt..."

Jetzt gehts.
Hab bei 8000 U/min = 16 clicks und bei 1000 U/min = 130 Clicks. Die Genauigkeit reicht völlig aus, da ich eh nur 1000er Schritte brauch.
Dafür ist dann die Geschwindigkeit genauer messbar. Bis zu 65535. Soll etwa 3-60 Km/h anzeigen.

Ist für ne Fahrende Bierkiste ;)

oberallgeier
23.11.2014, 18:52
... etwa 3-60 Km/h ... Ist für ne Fahrende Bierkiste ...Uuuups - oder hicks? Formula Bierkiste?

therealosram
23.11.2014, 18:56
... etwa 3-60 Km/h ... Ist für ne Fahrende Bierkiste ...
Uuuups - oder hicks? Formula Bierkiste?

Ich empfehle Youtube zum Thema 'Fahrende Bierkiste' zu befragen ;)

malthy
23.11.2014, 19:22
Na dann Prost! Poste mal ein Foto wenn sie fertig ist ... :-)

therealosram
23.11.2014, 20:26
Die Kiste ist schon fertig. Läuft ca 50. Reicht auch, jetzt brauch ich nur noch Tacho und Drehzahlmesser. Mit welcher Seite sollte man hier Bilder Posten?

therealosram
24.11.2014, 22:02
Hallo ans Forum.
Da ich mir das auch selber immer wünsche hier der fertige und vor allem laufende Code mit Anmerkungen


$regfile = "m88def.dat"
$hwstack = 128
$framesize = 128
$swstack = 128

Config Timer1 = Timer , Prescale = 8
Config Timer0 = Timer , Prescale = 1024

'Die Sensoren sollen auf Masse-Kontakt auslösen
Config Int0 = Falling
Config Int1 = Falling

'Auf Sensoren anspringen
On Int0 Ges 'Geschwindigkeit
On Int1 Dre 'Drehzahl

'Auf Timer-Überläufe anspringen
On Timer1 Timer1_irq
On Timer0 Timer0_irq

'Den ganzen Kram anschalten
Enable Int0
Enable Int1
Enable Timer1
Enable Timer0
Enable Interrupts

'Ports configurieren
Config Sda = Portc.4
Config Scl = Portc.5
Config Portd.2 = Input
Config Portd.3 = Input
Config Portd.5 = Output
Config Portd.6 = Output
Config Portd.7 = Output
Config Portb = Output

Pind.2 = 1
Pind.3 = 1

'Variablen festlegen
Dim C1 As Byte
Dim C0 As Byte
Dim G_pre As Long
Dim G_set As Long
Dim G_out As Long
Dim G_out_2 As Long
Dim G_out_3 As Long
Dim G_out_calc As Single

Dim D_pre As Long
Dim D_set As Long
Dim D_out As Long
Dim D_out_2 As Long

Dim Zehner As Byte
Dim Einer As Byte


C1 = 0
C0 = 0
Do
'Abwägung, wieviele LED's je nach Drehzahl leuchten sollen
Select Case D_out_2
Case Is < 146 '>7000
Portb = &B111111XX
Portd.7 = 1
Portd.6 = 1
Portd.5 = 1

Case Is < 170 '>6000
Portb = &B111111XX
Portd.7 = 1
Portd.6 = 1
Portd.5 = 0

Case Is < 205 '>5000
Portb = &B111111XX
Portd.7 = 1
Portd.6 = 0
Portd.5 = 0

Case Is < 255 '>4000
Portb = &B111111XX
Portd.7 = 0
Portd.6 = 0
Portd.5 = 0

Case Is < 340 '>3000
Portb = &B111110XX
Portd.7 = 0
Portd.6 = 0
Portd.5 = 0

Case Is < 510 '>2000
Portb = &B111100XX
Portd.7 = 0
Portd.6 = 0
Portd.5 = 0

Case Is < 1020 '>1000
Portb = &B111000XX
Portd.7 = 0
Portd.6 = 0
Portd.5 = 0

Case Is < 1360 '>750
Portb = &B110000XX
Portd.7 = 0
Portd.6 = 0
Portd.5 = 0

Case Is < 2030 '>500
Portb = &B100000XX
Portd.7 = 0
Portd.6 = 0
Portd.5 = 0

Case Else
Portb = &B000000XX
Portd.7 = 0
Portd.6 = 0
Portd.5 = 0

End Select


'Berechnungen der Geschwindigkeit und Ausgabe über I2C
'an einen MAX6958.

If G_out_2 < 1000000 Then
G_out_calc = 1 / G_out_2
G_out_calc = G_out_calc * 1473081
G_out_3 = G_out_calc
Else
G_out_3 = 0
End If

Zehner = G_out_3 / 10
Zehner = Zehner Mod 10
Einer = G_out_3 Mod 10

I2cstart
I2cwbyte &B01110000 'Chip-Adresse
I2cwbyte &B00000001 'Erste Adresse (Autoincr.)
I2cwbyte &B00000011 'decode
I2cwbyte &B00001000 'helligkeit
I2cwbyte &B00000011 'scan limit
I2cwbyte &B00000001 'nomal Operation
I2cstop

I2cstart
I2cwbyte &B01110000
I2cwbyte &B00100000 'Adresse
I2cwbyte Zehner 'Zehner
I2cwbyte Einer 'Einer
I2cstop

'Um bei den langen Intervallen der Geschwindigkeitsmessung
'auch geringe messen zu können, lass ich den 16bit Timer ziemlich
'schnell durchlaufen und dafür mehrmals (100x) durchlaufen
'und multipiziere mit C1.

'Der 8bit Timer sorgt in regelmäßigen Abständen dafür, dass bei
'Ergebnislosigkeit der Interupts die Zehler wieder als Ergebnis 0
'anzeigen

If C1 = 100 Then C1 = 0
If C0 = 50 Then
G_out_2 = 1000000
D_out_2 = 2500
C0 = 0
End If

Loop

'Geschwindigkeit INT
Ges:
G_out = G_set - G_pre
G_pre = G_set
G_set = C1 * 65535
G_set = G_set + Timer1
If G_out > 0 Then G_out_2 = G_out
Return

'Drehzahl INT
Dre:
D_out = D_set - D_pre
D_pre = D_set
D_set = C1 * 65535
D_set = D_set + Timer1
If D_out > 0 Then D_out_2 = D_out
Return

'Überlauf 16bit Timer
Timer1_irq:
C1 = C1 + 1
Return

'Überlauf 8bit Timer
Timer0_irq:
C0 = C0 + 1
Return


End

Searcher
25.11.2014, 06:15
Da ich mir das auch selber immer wünsche hier der fertige und vor allem laufende Code mit Anmerkungen

Super, Danke!



Mit welcher Seite sollte man hier Bilder Posten?

Beim Antworten auf einen Beitrag gibt es rechts unten einen Button "Erweitert". Beim Aktivieren bekommt man eine Vorschau auf das schon verfasste und verschiedene Icons. Mit einem Icon davon kann man Grafik einfügen und beim Klick darauf bekommt man die Auswahl zum Link einfügen oder "vom Computer hochladen". Bei letzterem braucht man also keinen externen Provider. Hat den Vorteil, daß die Bilder durch externe Einflüsse praktisch nicht verloren gehen.

Hab noch nicht durchgeblick, wann die Bilder vom Forum automatisch verkleinert werden :( und begrenze meine Bilder immer auf 600 Pixel maximale Seitenlänge und 100kB Dateigröße.

Gruß
Searcher