PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Wer hilft mir bei einem Programm für den AT-Mega 8?



gRaf-eny
23.03.2006, 11:31
Hi, ich habe hier momentan ein Programmier Problem, und ich hoffe ein Erfahrener Programmierer oder einer der sich mit Timern auskennt kann mir helfen:

Ich habe eine Karte auf der ein At-Mega 8 drauf ist, an ihm sind 2 Schrittmotoren angeschlossen und weiterhin 2 Poties (Ein alter Joystick).
Mein Plan war jetzt, dass wenn der Joystick neutral ist, sich kein Motor dreht.
Wenn die X Achse (ADC 1) einen Ausschlag nach links bekommt sich der Motor1 nach Links dreht und nach rechts, dann natürlich auch der Motor1 nach rechts.
Bei Vollausschlag links soll er sehr schnell laufen, bei kleinem Ausschlag entsprechend langsam. Die Übergänge möglichst mit seeeeeeeehr vielen Stufen.
Das gleiche gilt natürlich für die Y Achse und den anderen Motor.

Mein Problem ist jetzt aber, dass ich die Motoren Ansteuerung nicht parallel laufen lassen kann. Was bedeutet, dass die einzelnen Motoren nicht unabhängig voneinander ihre Geschwindigkeit verändern können.
(Ich hoffe jemand kennt das Problem, ich kann es nämlich sehr schlecht erklären…)
Jetzt hoffe ich das mir jemand mit sehr geschickter Programmierung helfen kann, oder mir jemand sagen kann ob und wie ich das Problem mit Timern umgehen kann.

Meine Idee wäre in den Timer 1 den Moter1 Code zu packen und in den Timer 2 den Code für den Motor 2, dann müsste ich in der Hauptsub „nur noch“ je nach Potiestellung das Timerintervall verändern.
Ist die Idee richtig und umsetzbar?

Eine „Lösung“ habe ich schon „fertig“, aber die hat nur 5 Unterschiedliche Geschwindigkeiten und das reicht bei weitem nicht… und sie belegt schon fast den gesamten Speicherplatz des Chips und ist von daher nicht erweiterbar.

Bin für jede Idee, ICQ-Nummer, etc. dankbar ;)

Gruß
Hagen

*hier noch ein paar daten...:
Schaltplan (das rote könnt ihr ignorieren)
http://www.bildfaenger-film.de/extern/plan.jpg

Motor B / 1

Sub Motorb
If Bdire = 1 Then
Btime = Btime + 1
Elseif Bdire = 2 Then
Btime = Btime - 1
End If

If Btime = 9 Then
Btime = 1
Elseif Btime = 0 Then
Btime = 8
End If

If Btime = 1 Then
B = B + 1
Portb.0 = 1
Portb.1 = 0
Portb.2 = 0
Portb.3 = 1
Elseif Btime = 2 Then
Portb.0 = 1
Portb.1 = 0
Portb.2 = 0
Portb.3 = 0
Elseif Btime = 3 Then
Portb.0 = 1
Portb.1 = 1
Portb.2 = 0
Portb.3 = 0
Elseif Btime = 4 Then
Portb.0 = 0
Portb.1 = 1
Portb.2 = 0
Portb.3 = 0
Elseif Btime = 5 Then
Portb.0 = 0
Portb.1 = 1
Portb.2 = 1
Portb.3 = 0
Elseif Btime = 6 Then
Portb.0 = 0
Portb.1 = 0
Portb.2 = 1
Portb.3 = 0
Elseif Btime = 7 Then
Portb.0 = 0
Portb.1 = 0
Portb.2 = 1
Portb.3 = 1
Elseif Btime = 8 Then
Portb.0 = 0
Portb.1 = 0
Portb.2 = 0
Portb.3 = 1
End If
End Sub

Motor D / 2

Sub Motord
If Ddire = 1 Then
Dtime = Dtime + 1
Elseif Ddire = 2 Then
Dtime = Dtime - 1
End If

If Dtime = 9 Then
Dtime = 1
Elseif Dtime = 0 Then
Dtime = 8
End If

If Dtime = 1 Then
Portd.0 = 1
Portd.1 = 0
Portd.2 = 0
Portd.3 = 1
Elseif Dtime = 2 Then
Portd.0 = 1
Portd.1 = 0
Portd.2 = 0
Portd.3 = 0
Elseif Dtime = 3 Then
Portd.0 = 1
Portd.1 = 1
Portd.2 = 0
Portd.3 = 0
Elseif Dtime = 4 Then
Portd.0 = 0
Portd.1 = 1
Portd.2 = 0
Portd.3 = 0
Elseif Dtime = 5 Then
Portd.0 = 0
Portd.1 = 1
Portd.2 = 1
Portd.3 = 0
Elseif Dtime = 6 Then
Portd.0 = 0
Portd.1 = 0
Portd.2 = 1
Portd.3 = 0
Elseif Dtime = 7 Then
Portd.0 = 0
Portd.1 = 0
Portd.2 = 1
Portd.3 = 1
Elseif Dtime = 8 Then
Portd.0 = 0
Portd.1 = 0
Portd.2 = 0
Portd.3 = 1
End If
End Sub

Der Gärtner
23.03.2006, 13:53
2 Timer, für jeden Motor einer, müsste klappen.

Was ich nicht ganz erkennen kann ist, ob du die Potis an einen ADC angeschlossen hast oder nicht. Wenn Ja, dann kannst du ja den ADC-Wert für die Timer gleich mehr oder weniger übernehmen. 255 = Max, 0 = min oder so... Wie die Werte dann umgesetzt werden ist dann dein Ding.

Logik für deine Ansteuerung dann:




if (X_Value > 128) { //rechts lenken
power_Motor_links = (....)*(Y_Value);
power_Motor_rechts = (....)*(Y_Value-faktor);
}

if (X_Value <= 128) { //links lenken
power_Motor_links = (....)*(Y_Value-faktor);
power_Motor_rechts = (....)*(Y_Value);
}



Mal ein Ansatz... Denk dran, dass der Faktor nicht zu groß werden darf... am besten so wählne, dass bei Volllenkung genau in die Räder sich gleich schnell aber in unterschiedliche Richtungen drehn. (Faktor auch von X abhängig, nicht nur Y!!)

Du brauchst außerdem eine Motorroutine, die abhängig von den errechneten Werte die Motoren vorwärts oder rückwärts lenkt.



Motor_A(int power) { //power 0-255
if (power>128) { //vorwärts
dir = 1;
TimerA_value = (...)*((power-128)*k+d);
}
if (power<128) { //rückwärts
dir = 0;
TimerA_value = (...)*(-power*k+d);
}

//Hier die Timer Füttern!!

}


Ich weis, es ist C-Style und nicht basic, aber du müstest es lesen können :)

gRaf-eny
24.03.2006, 13:00
Ja X und Y Achse sind jeweils GetADC
von 400 bis 549 links
550 bis 589 stop
590 bis 1000 rechts


Timer0 ist nun so eingestellt, dass die Frequenz vom Quarz, durch den Prescaler, durch 8 geteilt wird.
(Beim Prescaler kann man Teilungen von 1 , 8 , 64, 256, oder 1024 einstellen).

Das würde doch heißen, das ich nur 5 stufen habe, oder?

Der Gärtner
24.03.2006, 19:12
Hm ich bin ein PICler und hab k.a. was die ATMEL für prescaler haben, oder wie die timer gefüttert werden drum hab ich ja die "(...)" - klammern im code eingefügt. damit "bastelst" du dir dann deine Wunschtimerwerte wie du sie brauchst. beim 0-Punkt würd ich noch den timer stoppen fällt mir grad ein. (Enable weg)

Ich ging von 255 und nicht 1000 als maximalwert deines Potis aus - du musst noch die abfragen anpassen wenns wirklich so hoch ist!

lanic
24.03.2006, 19:58
hey!

ich versteh noch nicht warum du nur einen so kleinen bereich hast beim ADC eingang hast du den spannungsteiler richtig berechnet referenzspannung eingestellt oder nicht ? normaler weise müßtest du dann den vollen bereich bekommen.

oder verstehe ich dein problem falsch?

gRaf-eny
05.04.2006, 01:26
also ich hab keine ahnung lanic...
aber aufjedenfall ist der wert vom adc wenn der potie ganz links ist 400; mitte 560 bis 580 (variert); und rechts 1000

Ich habe mal mein Wusch Programm in VisualBasic programmiert und versucht euch das mal gut darzustellen...
hier der download
http://www.bildfaenger-film.de/extern/BAS_VB.zip
bitte guckt euch das mal an!

Ich komme mit Bascom sowas nicht zurecht... DANKE!

gRaf-eny
08.04.2006, 18:41
hat es sich denn mal wer angeguckt?
bitte tut das mal, wenn ihr es noch nicht habt...
ich bräuchte ne lösung bis ende diesen monats :(

sonst muss ich mir noch ne karte bauen, die ich mit vb übern rechner ansteuern kann

gRaf-eny
13.04.2006, 22:25
50€ für ein wenig programmieren!
fairer deal?
ICQ: 94-587-861

Hanni
13.04.2006, 23:36
Mal so als Denkansatz:

In Interupt Routinen gehört mit sicherheit nix längeres ...
Also definitiv nich der "Code für Moror X"

Rainerd
14.04.2006, 03:22
Hi gRaf-eny,

Hanni hat recht. ISR's immer so kurz wie möglich.
Nebenbei sind 2 Timer ganz schlecht bei so Zeitkritischen Aufgaben, da die sich immer in die Quere kommen.

Leider gibst Du sehr wenig Infos zu Deinem Projekt (Proz, Quarz, was soll das Prog sonst noch machen, wie sieht der jetzige Quellcode aus (nicht nur Schnipsel),usw.).

Nach dem Schaltplan siehts nach einem ATMega8 aus ... Quarz wohl 16 MHz.
Meines erachtens musst Du das anders anpacken. Vergiss als erstes mal VB auf dem PC. Der Atmel kann kein Multitasking (na, ok .. Windows auch nicht wirklich ;) ), also machen wir das einfach ganz schnell hintereinander.

Ich würde einfach erstmal die ISR entschlacken, indem die Halbschritte des Motors im Hauptprogramm schonmal in ein Array hinterlegt werden.
Außerdem würde ich in diesem speziellen Fall einen Timer immer zu festen Zeiten über die ISR laufen lassen.



' Hier die einzelnen Pins für die Motoren. Ein Array pro Pin reicht für beide Motoren
' Bit-Arrays gehen leider nicht. Würde mit Tricks gehen .. aber ist schon zu spät für mich (Uhrzeit) ;)
'******** Initialisierung *************

Dim Motorflag As Byte ' Welcher Motor ist gerade dran (1=Motor 1 ; 2=Motor 2)?
Dim Pause(2) As Word ' Pausenzähler (Geschwindigkeit Mot 1+2). Max. Wert 65535 !
Dim Hschritt(2) as Byte ' Halbschrittzähler
Din Direction(2) as Byte
Dim ISRZaehler(2) As Word
Dim MotorA(8) As Byte
Dim MotorB(8) As Byte
Dim MotorC(8) As Byte
Dim MotorD(8) As Byte
Dim I as Byte

' Da ich nicht weiß, was Schrittmotoren für eine Frequenz verkraften, gehe ich
' hier jetzt mal von 50 Hz aus. Da beide Motoren abwechselnd bedient werden,
' also eine Frequenz der ISR von 100 Hz
' Da reicht Timer0 (bei 16 MHz)
Config Timer0 = Timer, Prescale = 1024
Const Timervorgabe = 100
On Timer0 Timer_irq

Restore Halbschritt
For I=1 to 8
Read MotorA(I)
Read MotorB(I)
Read MotorC(I)
Read MotorD(I)
Next I
Motorflag = 1
Timer0 = Timervorgabe
Enable Timer0
Enable Interrupts

' *************************************
' ******** Hauptprogramm **************
Do
'(
Hier lesen wir irgendwie die ADC-Werte ein und wandeln sie in ein "verträgliches" Format
von mir aus von 400-1000 .. musst Du wissen
Der Timer springt also 100 mal pro Sekunde in die ISR .. jedes 2. mal kommt der gleiche Motor dran
In die ISR schreiben wir für jeden Motor eine "Pausenvariable", die bei jedem Einsprung hochgezählt wird.
Erreicht die Variable den Wert, den Du hier vorgibst (Geschwindigkeit), kriegt der jeweilige Motor seinen Halbschritt. Bei 1 in jedem ISR-Sprung, bei 65535 halt erst nach dem 65535zigsten Sprung. Ist das zu langsam, dann einfach den Timer schneller machen. Reicht der Endwert nicht, dann halt noch eine Zweite Variable einführen und beide hochzählen
Halbschritt
Am besten einfach rumprobieren. "ADC-Wert*irgendwas" .. keine Ahnung
Werte stehen dann in Pause(x). Richtung muss in Direction(x)
')
Loop
' ******** Hauptprogramm Ende **************
' Hier kommen die Daten für die Halbschritte
Halbschritt:
Data 1,0,0,1
Data 1,0,0,0
Data 1,1,0,0
Data 0,1,0,0
Data 0,1,1,0
Data 0,0,1,0
Data 0,0,1,1
Data 0,0,0,1

' Hier kommt die ISR
Timer_irq:

Timer0 = Timervorgabe ' Timer neu "laden"
If Motorflag = 1 Then ' Bitoperation wäre schöner aber geht nicht, da Bit 0/1 und Array ab 1 zählt
Motorflag = 2 ' müsste man dann in eine neue Variabel auslagern .. wollte ich nicht
Else
Motorflag = 1
End If
Incr ISRZaehler(Motorflag)
If ISRZaehler(Motorflag) >= Pause(Motorflag) Then
ISRZaehler(Motorflag) = 0
If Direction(Motorflag) = 1 Then
Incr Hschritt(Motorflag)
Elseif Direction(Motorflag) = 2 Then
Decr Hschritt(Motorflag)
End If
If Hschritt(Motorflag) = 9 Then
Hschritt(Motorflag) = 1
Elseif Hschritt(Motorflag) = 0 Then
Hschritt(Motorflag) = 8
End If

If Motorflag = 1 Then
Portb.0 = MotorA(Hschritt(1)) '<---- keine Ahnung, ob der Konstrukt so genommen wird
Portb.1 = MotorB(Hschritt(1)) ' Wenn nicht, musst Du ihn erst "aufdröseln"
Portb.2 = MotorC(Hschritt(1))
Portb.3 = MotorD(Hschritt(1))
Else
Portd.0 = MotorA(Hschritt(2))
Portd.1 = MotorB(Hschritt(2))
Portd.2 = MotorC(Hschritt(2))
Portd.3 = MotorD(Hschritt(2))
End If
End If
Return


Nur mal so als Denkanstoß. Ist jetzt zu spät .. können 1000 Fehler drin sein und vieles vll. einfacher zu machen sein. Vielleicht kannst Du ja ein paar Anregungen davon benutzen,
Tu mich aber langsam schwer mit denken ;)

Gruß.
Rainer

gRaf-eny
16.04.2006, 22:56
DANKE
ich werd mir das die Tage nochmal angucken und mal weiter rumprobieren,
denke das hilft mir schonmal...

auf bald!