PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Zu große Anzahl an Pulsen bei Taktscheibe



raist
22.08.2012, 18:39
Hallo,

ich baue derzeit mit ein paar Kommilitonen im Rahmen einer Projektarbeit an einem FTS. Die Steuerung ist so ziemlich dem Asuro nachempfunden. Um die Drehzahl der asynchron Motoren genau regeln zu können, verwenden wir dabei Taktscheiben (120er Teilung). Das Problem ist, dass wir dabei eine viel zu hohe Anzahl an Pulsen bekommen. So haben wir z.B. bei 44 upm über 50000 Pulse/min gemessen (per Pin-Change Interrupt / beide Flanken). Wenn ich richtig rechne müssten es eigentlich 240 * 44 = 10560 sein. Wir haben mit dem Oszilloskop das Signal am Pin gemessen und haben eine recht saubere Rechteckspannung. Prinzipiell ist das für uns eigentlich kein Problem, weil Drehzahl und Pulse trotzdem gleichmäßig ansteigen - doppelte Drehzahl = doppelt soviele Pulse. Allerdings finden wir es jetzt nicht so wirklich schön ;) Wir verwenden einen Atmega 2560 und programmieren mit Bascom. Hier ist mal ein "Testprogramm" von uns, allerdings misst dieses nur noch eine Flanke (zumindest soll es das) und gibt die Drehzahl sekündlich aus... Sieht evtl. etwas wild aus, weil wir momentan nur "rumprobieren" (wir haben erst vor 3 Wochen angefangen uns damit zu beschäftigen)



$prog , 255 , &B11011001

$regfile = "m2560def.dat"
$hwstack = 120
$framesize = 100
$swstack = 100

$crystal = 16000000



'Timer für Zeitbezug (1 Sekunde)

Config Timer1 = Timer , Prescale = 256
Enable Timer1
On Timer1 Timing
Timer1 = 3036
'-----------------------------------

'Pin Change Interrupt

'Motor links
Config Pink.4 = Input
Portk.4 = 1

'Motor rechts
Config Pink.5 = Input
Portk.5 = 1

Enable Interrupts
Pcmsk2 = &B00110000
On Pcint2 Test
Enable Pcint2

'Variablen für Inkremente
Dim Inkr_links As Word
Dim Inkr_rechts As Word

'Variablen für vorherigen Zustand um Flanke feststellen zu können
Dim Tmp_links As Bit
Dim Tmp_rechts As Bit

Inkr_links = 0
Inkr_rechts = 0
Tmp_links = 0
Tmp_rechts = 0

'---------------------------
'PWM für beide Motoren

Config Pinc.2 = Output
Config Pinc.3 = Output
Config Pinb.4 = Output

Config Pinc.0 = Output
Config Pinc.1 = Output
Config Pinh.6 = Output

Config Timer2 = Pwm , Compare A Pwm = Clear Up , Compare B Pwm = Clear Up , Prescale = 1

Portc.2 = 0
Portc.3 = 1

Pwm2a = 60

Portc.0 = 1
Portc.1 = 0

Pwm2b = 20

'------------------------------------
Do

Loop


End

'--------------------------------------
'Interrupt für Pulse

Test:
If Pink.4 = 1 And Tmp_links = 0 Then
Incr Inkr_links
Tmp_links = Pink.4
End If

If Pink.5 = 1 And Tmp_rechts = 0 Then
Incr Inkr_rechts
Tmp_rechts = Pink.5
End If

Tmp_links = Pink.4
Tmp_rechts = Pink.5

Return

'-------------------------------------
'Timer für Zeitbezug (Umdrehungen/Sekunde) und Ausgabe

Timing:
Print Inkr_links ; " " ; Inkr_rechts
Inkr_links = 0
Inkr_rechts = 0
Return


Ich bin für jeden Tipp dankbar...

wkrug
22.08.2012, 19:31
Was sind das für Taktscheiben? Wenns welche mit mechanischen Kontakten sind gibt das ein übles Kontaktprellen.
So das der Controller beim öffnen oder schließen des Kontaktes durchaus mehrere Impulse zählen.
Die Lösung wäre eine optische Abtastscheibe zu benutzen, oder die Kontakte über eine Schaltung zu entprellen.
Bei so hohe Zyklenzahlen würde ich von einer Softwaremässigen entprellung absehen.
Zudem sichert und restorde Bascom bei jedem Interruptaufruf alle Register.
Ich würde die Interruptroutine in Assembler proggen und die Zählerwerte dann über einen RAM Speicherplatz übergeben.
Das geht mit Sicherheit fast 10 mal so schnell.

raist
22.08.2012, 20:27
Erstmal danke. Wir verwenden eine Schlitzscheibe mit Lichtschranke: http://www.shop.robotikhardware.de/shop/catalog/product_info.php?products_id=245 Was meinst du mit: "Zudem sichert und restorde Bascom bei jedem Interruptaufruf alle Register." ? Meinst du es ist für uns Anfänger machbar so eine Steuerung in absehbarer Zeit mit Assembler zu programmieren ? Wir sind wie gesagt alles totale Anfänger, klar haben wir alle schon programmiert, aber so hardwarenah war noch keiner von uns unterwegs :)

radbruch
22.08.2012, 20:41
Das Sichern der Register beim Aufruf der ISR kann man mit nosave verhindern. In der Bascom-Hilfe wirds erklärt und auch der Code zum Sichern der unbedingt notwendigen Register kann dort kopiert werden.

WL
22.08.2012, 20:42
Ich würde auf die Timerroutine tippen.
Der Vorgabewert (3036) wird nur zum Programmstart gesetzt (muß auch in die ISR).
Der Print in der Timer-ISR ist auch nicht gut.
So wird das nicht 1 Sekunde ergeben.

In der ISR nur die Variablen (für den Print zusätzliche Merker) setzen und den Print in die Hauptschleife.

wkrug
23.08.2012, 10:03
...Interruptaufruf alle Register
So ein ATMEL Controller hat 32 Register.
Bascom sichert ganz am Anfang der Interruptroutine alle diese auf dem Stack und holt sie am Ende wieder vom Stack runter.
PUSH R0
PUSH R1
IN R1,SREG
PUSH R1
PUSH R2
PUSH R3
...
PUSH R31

; Deine Interruptroutine

POP R31
....
POP R3
POP R2
POP R1
OUT SREG,R1
POP R1
POP R0

Das sind schon mal 66 Prozessortakte die bei jedem Interruptaufruf verloren gehen.

Meinst du es ist für uns Anfänger machbar so eine Steuerung in absehbarer Zeit mit Assembler (http://www.rn-wissen.de/index.php/AVR_Assembler_Einführung) zu programmieren ?
Wenn Ihr schon mal irgendwas in Assembler gemacht habt ist das kein Problem. Der AVR Assembler kennt nicht viele Befehle.
Zudem lässt BASCOM inline Assembler zu. Das bedeutet Ihr könnt das komplette Programm in BASCOM schreiben und nur für die Zeitkritischen Sachen Assembler verwenden.
Im Prinzip handelt es sich bei Euch ja nur um Inkremente, bzw. Die Addition um +1.
Das geht in Assembler mit ADD bzw. ADC oder ADIW.
Dann müssen nur die alten Werte aus dem RAM in benutzen Register geladen werden.
Das geht mit LD bzw. LDS.
Sowie die Ergebnisse wieder ins RAM zurückgeschrieben werden also ST bzw. STS.

Die Variablen - Speicherplätze kannst Du in BASCOM ja fest vorgeben, dann kann Bascom die aktuellen Werte direkt als Variable auslesen.

Um das sichern des SREG und der benutzten Register musst Du dich allerdings selber kümmern.
Ich würde da mal einen Geschwindigkeitserhöhung um den Faktor 10 prognostizieren.

Simulieren sollte mit AVR Studio möglich sein. Hab ich aber mit BASCOM noch nicht gemacht, ich selber progge in "C".

raist
23.08.2012, 17:00
@WL: Danke für den Tipp mit dem Timer, hat zwar in dem Fall nix gebracht, aber ansonsten hätten wir jeden Timer falsch programmiert ;)
@wkrug: Ich werd mir das am Wochenende mal genauer anschauen, hatte bisher wie gesagt noch nix damit zu tun.

raist
25.08.2012, 23:06
Hallo nochmal,

ich habe mir die Sache mit Assembler jetzt einmal angeschaut. Dabei verstehe ich noch nicht so ganz welche Register ich während der ISR alle sichern muss. Also SREG muss ich so wie ich das sehe auf jedenfall sichern. Die Register R4, R5, R6, R8, R9, R28 und R29 sollte ich laut dem Artikel "Assembler Einführung für Bascom User" auf rn-wissen am besten einfach in Ruhe lassen. Muss ich dann nur die Register sichern die ich während der ISR verwende oder auch welche die ich gerade irgendwo anders im Programm z.B. der Main Loop verwende ? Würde folgendes z.B. ausreichen:

ON pcint2 isr NOSAVE

isr:
$asm
PUSH r24
IN r24, SREG
PUSH r24

... mach was tolles mit r24

POP r24
OUT r24, SREG
POP r24
end asm

wkrug
25.08.2012, 23:40
Kurze Antwort:
Wenn Du nur Register r24 nutzen willst reicht das.
Da Du aber Additionen mit ergebnissen größer 255 brauchst würd ich mir das Register r25 mit dazu holen.
INC r24; Register R24 wird um 1 erhöht
BRNE notad; es wird geguckt ob r24 0 ist = Überlauf
INC r25; wenn r24 0 ist wird r25 inkrementiert
notad:
; hier geht dann das Programm weiter

OUT r24, SREG ist falsch rum. Muss heissen OUT SREG, r24.