PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Probleme mit Timer1



Cyrus777
27.06.2011, 16:35
Hi,

Unser FTS-Projekt (https://www.roboternetz.de/community/showthread.php?52910-Projekt-fahrerloses-Transportsystem&p=509913#post509913)nähert sich langsam dem Ende.

Die induktive Spurführung klappt fast immer, also der Lenkmotor lenkt wenn er soll und auch wieder zurück. Manchmal gibt es aber ein paar Probleme. Mein betreuender Prof meinte ich soll da nen digitalen Tiefpassfilter programmieren... Ähm genau... Mal gucken ob wir das auch anders lösen können.

Aber irgendwie haut das mit dem Timer nicht so hin. Der Timer1 sollte eigentlich 10 Mal pro Sekunde den Interrupt aufrufen und zum einen überprüfen, ob die beiden induktiven Sensoren sich noch auf der Spur befinden und dann ggf. den Antriebsmotor stoppen wenn sich das FTS außerhalb der Spur befindet. Um zum anderen soll der Infrarotsensor vor dem Fahrzeug abgefragt werden ob sich ein Hindernis in einem bestimmten Abstand vor dem Fahrzeug befindet und den Antriebsmotor anhalten.

Aber als ich heute das Programm aufgespielt hatte, ging irgendwie gar nichts mehr. Weder die Taste 1 um das Programm zu starten noch der Resetknopf. Und das kam mir schon ziemlich seltsam vor. Hab es dann nochmal ein paar Mal kompiliert und aufgespielt, aber immer das gleiche Problem. Die alte Version ohne Timer ging ohne Probleme.

Man könnte das sicher auch ohne Timer machen und jeweils ne Funktion schreiben und diese vor jeder Schleife oder auch dazwischen aufrufen. Aber mit Interrupt wäre das ganze natürlich eleganter ;)

Wo könnte das Problem liegen? Die Werte für den Timer hab ich mir von dem Roboternetz Berechnungstool ausgeben lassen. Der Code für den Timer steht einmal ganz am Anfang und ganz am Ende. Der Rest ist im Prinzip nicht soo interessant da das ja halbwegs läuft.

Vielen Dank schon mal!



'Hier wird der Timer und der Teiler festgelegt
Config Timer1 = Timer , Prescale = 64



'Hier wird das Unterprogramm festgelegt, das
'in dem von ihnen eingestellten Intervall aufgerufen wird
On Timer1 Timer_irq

'Diese Vorgabe wurde berechnet um die genaue Intervallfrequenz zu erreichen
'10 Interrupts pro Sekunde
Const Timervorgabe = 40536


'Hier werden die Timer aktiviert
Enable Timer1
Enable Interrupts


Declare Sub Fahrt()
Declare Sub Kalibrierung()
Declare Sub Lenkung_von_rechts_zur_mitte()
Declare Sub Lenkung_von_links_zur_mitte()

Declare Function Tastenabfrage() As Byte


$regfile = "m32def.dat"
$framesize = 32
$swstack = 32
$hwstack = 32


Dim I As Integer
Dim N As Integer
Dim Ton As Integer

$crystal = 16000000 'Quarzfrequenz
$baud = 9600

Config Adc = Single , Prescaler = Auto 'Für Tastenabfrage und Spannungsmessung

Config Pina.7 = Input 'Für Tastenabfrage
Porta.7 = 1 'Pullup Widerstand ein


Const Ref = 5 / 1023 'Für Batteriespannungsberechnung

Dim Taste As Byte
Dim Volt As Single

' Für Motorentest
'Ports für linken Motor
Config Pinc.6 = Output 'Linker Motor Kanal 1
Config Pinc.7 = Output 'Linker Motor Kanal 2
Config Pind.4 = Output 'Linker Motor PWM
'Ports für rechten Motor
Config Pinb.0 = Output 'Rechter Motor Kanal 1
Config Pinb.1 = Output 'Rechter Motor Kanal 2
Config Pind.5 = Output 'Rechter Motor PWM
Config Timer1 = Pwm , Pwm = 10 , Compare A Pwm = Clear Down , Compare B Pwm = Clear Down
Pwm1a = 0
Pwm1b = 0
Tccr1b = Tccr1b Or &H02 'Prescaler = 8





I = 0
Sound Portd.7 , 400 , 450 'BEEP
Sound Portd.7 , 400 , 800 'BEEP
Sound Portd.7 , 400 , 450 'BEEP
Print
Print "**** RN-CONTROL 1.4 *****"
Print "Das neue Experimentier- und Roboterboard"
Print "Weitere passende Zusatzboards bei www.robotikhardware.de"
Print
Do




Taste = Tastenabfrage()
If Taste <> 0 Then

Select Case Taste
Case 1
Call Fahrt


End Select
Sound Portd.7 , 400 , 500 'BEEP
End If

Waitms 100
Loop

End




'Diese Unterfunktion fragt die Tastatur am analogen Port ab
Function Tastenabfrage() As Byte
Local Ws As Word

Tastenabfrage = 0
Ton = 600
Start Adc
Ws = Getadc(7)
' Print "Tastenabfrage anpassen!ADC Wert ws=" ; Ws
If Ws < 500 Then
Select Case Ws
Case 400 To 450
Tastenabfrage = 1
Ton = 550
Case 330 To 380
Tastenabfrage = 2
Ton = 500
Case 260 To 305
Tastenabfrage = 3
Ton = 450
Case 180 To 220
Tastenabfrage = 4
Ton = 400
Case 90 To 130
Tastenabfrage = 5
Ton = 350

End Select
Sound Portd.7 , 400 , Ton 'BEEP

End If



End Function






Sub Fahrt()
'Testprogramm zur induktiven Spurführung


Config Porta = Input

Local Links As Word
Local Rechts As Word
Local Sensor_lichtschranke As Word


Start Adc

'Lenkungskalibrierung

Call Kalibrierung

'Lenkungskalibrierung Ende

Portb.0 = 0 'Antrieb ein
Portb.1 = 1
Portd.5 = 1
Pwm1a = 1023

Do


Links = Getadc(2)
Rechts = Getadc(3)


If Links < 700 And Rechts >= 700 Then
'"rechts neben der Spur"

Do

Links = Getadc(2)
Rechts = Getadc(3)

Portc.6 = 1 'bestimmt Richtung 0,1 Gegen Uhrzeiger (Rechtsdrehung)
Portc.7 = 0
Portd.4 = 1

Pwm1b = 1023

Loop Until Links < 700 And Rechts < 700
'Mitte
Pwm1b = 0

'Drehung von rechts zur Mitte
Call Lenkung_von_rechts_zur_mitte



'***************************

Links = Getadc(2)
Rechts = Getadc(3)

Elseif Links >= 700 And Rechts < 700 Then
'"links neben der Spur"

Do

Links = Getadc(2)
Rechts = Getadc(3)
Portc.6 = 0 'bestimmt Richtung 0,1 Gegen Uhrzeiger (Rechtsdrehung)
Portc.7 = 1
Portd.4 = 1

Pwm1b = 1023

Loop Until Links < 700 And Rechts < 700
'Mitte
Pwm1b = 0

'Drehung von links zur Mitte
Call Lenkung_von_links_zur_mitte

End If


Loop



End Sub

Sub Kalibrierung()
'Programm zur Kalibrierung der Lenkung in Mittelstellung
Local Sensor_lichtschranke As Word

Portc.6 = 1 'bestimmt Richtung 0,1 Gegen Uhrzeiger (Rechtsdrehung)
Portc.7 = 0
Portd.4 = 1

Wait 3

Pwm1b = 0

Portc.6 = 0 'bestimmt Richtung 0,1 Gegen Uhrzeiger (Rechtsdrehung)
Portc.7 = 1
Portd.4 = 1

Do
Sensor_lichtschranke = Getadc(4)
Pwm1b = 1023
Loop Until Sensor_lichtschranke < 800

Pwm1b = 0

End Sub



Sub Lenkung_von_rechts_zur_mitte()
'Programm zur Drehung des Lenkmotors von rechts zur Mitte
Local Sensor_lichtschranke As Word
Portc.6 = 0 'bestimmt Richtung 0,1 Gegen Uhrzeiger (Rechtsdrehung)
Portc.7 = 1
Portd.4 = 1

Do
Sensor_lichtschranke = Getadc(4)
Pwm1b = 1023
Loop Until Sensor_lichtschranke < 800

Pwm1b = 0

End Sub

Sub Lenkung_von_links_zur_mitte()
'Programm zur Drehung des Lenkmotors von links zur Mitte
Local Sensor_lichtschranke As Word

Portc.6 = 1 'bestimmt Richtung 0,1 Gegen Uhrzeiger (Rechtsdrehung)
Portc.7 = 0
Portd.4 = 1

Do
Sensor_lichtschranke = Getadc(4)
Pwm1b = 1023
Loop Until Sensor_lichtschranke < 800

Pwm1b = 0

End Sub

'Timer
Timer_irq:
Timer1 = Timervorgabe

'Hier könnte nun ihre beliebige IRQ-Routine stehen
'Dabei sollte man darauf achten das diese nicht mehr Zeit
'benötigt, als das Intervall zuläßt

Dim Links As Word
Dim Rechts As Word
Dim Ifr As Word


Links = Getadc(2)
Rechts = Getadc(3)

If Links >= 700 And Rechts >= 700 Then
'Außerhalb Der Spur
Portd.5 = 0
Pwm1a = 0
Else
Portd.5 = 1
Pwm1a = 1023
End If

'Infrarotsensor Abfrage
Ifr = Getadc(0)
Ifr = Ifr / 4

If Ifr >= 128 Then
Portd.5 = 0
Pwm1a = 0
Else
Portd.5 = 1
Pwm1a = 1023

End If

Return

Searcher
27.06.2011, 19:41
Hallo,
ich blick da nicht ganz durch, jedoch sind mir zwei Dinge aufgefallen.

1. Am Anfang setzt Du den Prescaler für Timer1 auf 64. Später wird er durch "Tccr1b = Tccr1b Or &H02" auf 8 geändert
2. Die Timervorgabe wird in der ISR gesetzt. Ungewöhnlich und beabsichtigt? Funktioniert das? Würd ich irgendwo bei der Initialisierung machen.

PS: Die $ Compiler Direktiven würd ich auch an den Anfang setzen, um es dem Compiler leichter zu machen :-)

EDIT Zwei Zeilen über der TCCR1B zuweisung wird der Timer1 nochmal auf Phase Correct PWM konfiguriert. Denke, das da noch eine Überarbeitung nötig ist

Gruß
Searcher

Cyrus777
27.06.2011, 20:19
Hi Searcher,

Danke für die Hinweise!
Ja ich weiß, ich hätte mal noch ein paar mehr Kommentare in den Code schreiben sollen, damit klarer wird was da überhaupt passiert :-/

Das Bild des FTS in dem verlinkten Post auf der 2. Seite ist zwar nicht mehr ganz aktuell da dort weder die Sensorik für die Lenkachse noch die Sensorik für die Spurführung eingebaut ist, aber für die Erklärung dürfte es aureichen.

Also kurz zum Programm: Vorne am FTS ist ein IFR-Sensor. Der hängt am Port 0. Dann gibts für die Spurführung zwei nebeneinder befindliche Spulen, die sich unter dem Fahrzeug befinden und einen Kupferdraht abtasten, auf dem ein Impuls läuft. Sie hängen am Port 2 und 3 und heißen im Programm Links und Rechts, bzw werden die analogen Werte unter diesen Variablennamen abgespeichert. Sind beide Spulen direkt über dem Draht, wird eine bestimmte Spannung von jedem Sensor ausgegeben die einem analogen Wert von so 400 bis 600 entspricht. Ist ein Sensor auserhalb des Drahtes, wird ein analoger Wert von 777 ausgegeben. Also wenn z.b. der linke Sensor 600 und der rechte Sensor 777 zeigt, weiß das Programm, dass das FTS rechts von der Spur ist und lenkt entsprechend.

Um dann wieder für die Geradeausfahrt die Mittelstellung der Lenkachse zu finden haben wir ne Lichtschranke an Port 4, die sich direkt über dem roten Zahnrad der Lenkachse befindet. Die zeigt eine Spannung an wenn das rote Zahnrad nicht in der Mitte ist und keine Spannung, wenn es in der Mitte ist. Deswegen das "Loop Until Sensor_lichtschranke < 800". Wir haben auch noch nen Poti an der Lenkachse, um nen bestimmten Lenkwinkel zu erreichen, aber der wird im Moment nicht benutzt. Die Spurfolgung hat auch so ganz gut geklappt.

Zu 1.: Ah okay, ist mir gar nicht aufgefallen. Ich hatte das Programm ursprünglich aus dem RN-Control Testprogramm gebastelt. Kann ich die Zeile mit dem "Tccr1b" dann einfach weglassen? Oder braucht man das?
Zu 2.: Den Quellcode für die Timevorgabe hab ich direkt vom Programm rnAVR von roboternetz.de übernommen, das mir auch die Werte für den Prescaler und die Timevorgabe gegeben hat. Ich weiß nicht wie alt das Programm ist und ob es fehlerfreien Quellcode erzeug, hab es über die Suchfunktion gefunden. Ich kenn mich mit Interrupts leider gar nicht aus und hab das am Wochenende mal in nem Buch bzw im RN-Wiki nachgelesen. Also ob es funktioniert kann ich nicht genau sagen, da sich mit dem Timer gar nichts mehr getan hat.

Kann es vielleicht auch sein dass der Quellcode im ISR zu lang ist und der Prozessor es gar nicht schafft den 10 Mal pro Sekunde abzuarbeiten und es deswegen Probleme gibt, sprich er noch gar nicht fertig ist ihn abzuarbeiten, ihn aber erneut aufrufen will? Ich hab auch irgendwo mal gelesen dass man da eigentlich keine allzu langen Befehle reinschreiben sollte. Eigentlich würde es auch reichen wenn er nur ein Interrupt pro Sekunde hat.

Searcher
27.06.2011, 20:31
Hallo,


Den Quellcode für die Timevorgabe hab ich direkt vom Programm rnAVR von roboternetz.de übernommen, das mir auch die Werte für den Prescaler und die Timevorgabe gegeben hat

Hab ich nicht überprüft; wird aber OK sein.

Denke, daß das eigentlich Problem ist, das Du den Timer1 für deinen Timerinterrupt benutzen willst. Ich hatte in meiner ersten Antwort noch ein EDIT hinzugefügt. Der Timer1 wird wohl auch noch für Motor PWM gebraucht.

Gruß
Searcher

Cyrus777
27.06.2011, 20:51
Ah Danke!

Oh, das ist natürlich blöd mit dem PWM. Daran will ich lieber nicht rumfummeln.
Hm dann werd ich das am besten mal überarbeiten und einfach Timer0 für den Interrupt benutzen, auch wenn dort das niedrigste 61 Interrupts pro Sekunde sind.

Searcher
27.06.2011, 21:26
Hi,

Kann es vielleicht auch sein dass der Quellcode im ISR zu lang ist und der Prozessor es gar nicht schafft den 10 Mal pro Sekunde abzuarbeiten
Bin selbst (noch?) kein BASCOM Freak und deshalb sollten meine Aussagen besser bestätigt werden;):

In der ISR wird wohl die meiste Zeit mit den GETADC verbraten werden. Der ADC ist mit Prescale=Auto konfiguriert. Hab das mal im Simulator nachgeschaut. Bascom macht daraus einen ADC Takt von 125000Hz. Für eine Single Conversion werden 13 ADC-Takte gebraucht also ca 104µs. Nun schätze ich ganz grob, daß die Abarbeitung der ISR sicher unter 1ms bleibt.

Abgesehen davon bin ich selbst mit dem BASCOM Kommando GETADC in einer ISR nicht glücklich geworden. Bin gespannt auf Deine Erfahrung.

Wenn Dir 60 Mal pro Sekunde mit Timer0 zu schnell ist, könnte man einen Zähler in der ISR hochzählen lassen und nur jedes sechstes Mal die komplette Routine durchlaufen lassen. Dann hat man zwar auch 60 Interrupts, wobei aber nur bei 10 pro Sekunde viel Zeit verbraucht wird.

Gruß
Searcher