Servus miteinander, es geht um eine Schrittmotoransteuerung. Für den Anfang möchte ich mit einer linearen Rampe beginnen. Trapezform. Zum Einsatz kommt ein Atmega168. Meine Programmiererfahrung in C reicht für diesen Zweck nicht ganz aus. Deshalb lese ich mich zur Zeit in der Thematik (Interrupt, Timer, usw.) einwenig durch. Allerdings habe ich schon mal einige Fragen die zum Allgemeinverständnis dienen. 1. Überlegung: die Funktion einer trapezförmigen Rampe im Main-Teil in einer While aufstellen und die entsprechenden Werte an dem Ausgangspin, wo der Motor angeschlossen ist für die Richtung, Stromabsenkung, Frequenz und Ein/Aus, ausgeben. Welche Probleme sind möglicherweise damit verbunden? Timing = Schrittverlust? 2. Überlegung: Interrupt, hier Timer1. Die Berechnung der entsprechenden Werte für die Rampe in der ISR Welche Probleme sind hierbei damit verbunden? Timing = Schrittverlust? Frequenzabhängigkeit? Was passiert in einem Bereicht in dem die Frequenz ganz klein ist, unterhalb des 1. Überlaufs? 3. Überlegung: Interrupt, hier durch zwei Timer. Der eine für die Berechnung, der zweite für die Frequenz. Meine Überlegung hier ist die, dass die zwei Timer aufeinander abgestimmt sind und keine Timingprobleme auftreten dürften. Auch hier wieder die Frage zu dem kleinen Bereich aus der 2. Überlegung. Ich hoffe ihr könnt mir ein wenig dabei helfen die Unklarheiten zu beseitigen. Danke schon mal Christian
1. Main Programm - Das Setzen der Ausgangspins wird möglicherweise nicht so regelmäßig bei hohen Frequenzen und Du kannst in deiner Schleife nicht viel anderes tun, also kein LCD bedienen oder sonstiges. 2. Timer : Die beste Lösung Du solltest den Timer aber nicht so verwenden, dass nur ein Interrupt ausgelöst wird, sondern der Timer soll beim Erreichen der Schwelle den Ausgang setzen. Die ISR setzt dann den Ausgang zurück (es braucht ja nur einen kurzen Puls), macht die Berechnungen (nicht in Float !!) und setzt den Timer für die nächste Zählung auf. Ganz kleine Frequenzen werden normalerweise nicht verwendet, der Schrittmotor startet schon mit einer Minimal-Frequenz (die Rampe startet nicht bei null). Du kannst mit dem Simulator die Dauer der ISR bestimmen, das ergibt dann deine höchste Frequenz, die zu erzeugen kannst. 3) 2 x Timer Unnötig und kompliziert.
Hi, Die Application Note AVR446 von Atmel beschäftigt sich mit der Thematik. Sourcecode gibt es auch dazu. http://www.atmel.com/products/AVR/mc/?family_id=607 Reinhard
.. danke für die Infos. Werd noch mal auf euch zu kommen wenns an die Programmiererei geht. Servus Christian
Servus miteinander, nachdem ich mich einigermaßen in die Schrittmotor und Timerthematik eingelesen habe, steht nun Linearrampe. Allerdings gibt es noch einige Problemstellen deren Lösung ich nicht finde. Zu Beginn der aufsteigenden Rampe kann ich mit dem Oszi eine höhere Frequenz, wie über dem restlichen Verlauf der Rampe, sehen. Im Anhang kann man in etwa erkennen was ich damit meine. Nun habe ich momentan keine Ahnung woher diese Ungleichmäßigkeit kommen kann. Auch bin ich mir über die richtige Datentypenwahl nicht ganz sicher.
1 | // ********************* Variablen ***********************************
|
2 | unsigned int f0=303; |
3 | volatile float f, fc, Match; |
4 | unsigned char Fahrt_Flag; |
5 | unsigned long Pos_x=0, Pos_P1=0, a, fm=18000; |
6 | |
7 | // ********************* Prototypen ***********************************
|
8 | void ATOUL(unsigned char *DFeld, int feldlaenge); // Prototype Arry to unsigned long |
9 | void ULTOA(unsigned long Value); |
10 | static unsigned long wurzel(unsigned long x); |
11 | |
12 | // ***********************ISR zum Zählen der Schritte *******************
|
13 | ISR(TIMER1_COMPB_vect) // ISR Zählen der Matches |
14 | {
|
15 | PORTB |= (1<<PB2); // Motor-Takt AN |
16 | |
17 | OCR1A=Match; |
18 | // ----------- Zählen der Schritte in beiden Richtungen -------------
|
19 | Pos_ist++; |
20 | if(Rechtsfahrt_Flag==0) |
21 | {
|
22 | Pos_akt--; |
23 | }
|
24 | else
|
25 | Pos_akt++; |
26 | |
27 | // ----------- Timer ausschalten ---------------------------------
|
28 | if((Pos_soll == Pos_ist) || (MotorAN_ADC == 0) || (MotorAN_LS == 0)) |
29 | {
|
30 | TIMSK1=0; // Timer Interrupt COMPARE MATCH B aus |
31 | }
|
32 | |
33 | PORTB &=~ (1<<PB2); // Motor-Takt AUS |
34 | }
|
35 | |
36 | static unsigned long wurzel(unsigned long x) |
37 | {
|
38 | register unsigned long xr; // result register |
39 | register unsigned long q2; // scan-bit register |
40 | register unsigned char f; // flag (one bit) |
41 | |
42 | xr = 0; // clear result |
43 | q2 = 0x40000000L; // higest possible result bit |
44 | do
|
45 | {
|
46 | if((xr + q2) <= x) |
47 | {
|
48 | x -= xr + q2; |
49 | f = 1; // set flag |
50 | }
|
51 | else{ |
52 | f = 0; // clear flag |
53 | }
|
54 | xr >>= 1; |
55 | if(f){ |
56 | xr += q2; // test flag |
57 | }
|
58 | } while(q2 >>= 2); // shift twice |
59 | if(xr < x){ |
60 | return xr +1; // add for rounding |
61 | }
|
62 | else{ |
63 | return xr; |
64 | }
|
65 | }
|
66 | |
67 | void schrittmotor(unsigned char *DFeld,int feldlaenge) // SUB-Befehl Schrittmotor |
68 | {
|
69 | MotorAN_ADC=1; // Flag |
70 | MotorAN_LS=1; // Flag |
71 | Fahrt_Flag=1; // Flag |
72 | |
73 | f=f0; |
74 | a=10000; |
75 | Pos_P1=10200; |
76 | |
77 | Match=0; |
78 | OCR1A=0; |
79 | |
80 | // *********************** Konvertierung der Daten in long int ***************
|
81 | if(Schrittmotor_flag == 0) |
82 | {
|
83 | ATOUL(DFeld,feldlaenge); |
84 | }
|
85 | |
86 | // -------- Timer Init -------------------------------------------------------------------
|
87 | if(Schrittmotor_flag==1) |
88 | {
|
89 | TIMSK1 = 0b00000100; // Timer Interrupts COMPARE MATCH B = bit2 |
90 | TCCR1A = 0b00000000; // Pin disconnect |
91 | TCCR1B = 0b00001001; // Timer Start: Mode 4 = bit3, Teiler 1 = bit1 |
92 | PORTD &= ~(1<<PD0); // Motor an ( low aktiv ) |
93 | }
|
94 | |
95 | while(Schrittmotor_flag==1) |
96 | {
|
97 | // -------- Aufsteigend -----------------
|
98 | if(Fahrt_Flag==1) // 1 = Aufsteigend |
99 | {
|
100 | f = wurzel(2*Pos_ist*a); |
101 | Match= F_CPU/f; |
102 | |
103 | if(Pos_ist >= Pos_P1) |
104 | {
|
105 | fc=f; |
106 | Fahrt_Flag=2; |
107 | }
|
108 | }
|
109 | |
110 | // -------- Konstant -----------------
|
111 | if(Fahrt_Flag==2) // 2 = Konstant |
112 | {
|
113 | Match= F_CPU/fc; |
114 | PORTB |=(1<<PB4); // LED gelb AN |
115 | |
116 | if(Pos_ist>=(Pos_soll-Pos_P1)) |
117 | {
|
118 | Fahrt_Flag=3; |
119 | }
|
120 | }
|
121 | |
122 | // -------- Absteigend -----------------
|
123 | if(Fahrt_Flag==3) // 3 = Absteigend |
124 | {
|
125 | PORTB &= ~(1<<PB4); // LED gelb AUS |
126 | |
127 | f = wurzel(2*a*(Pos_soll-Pos_ist)); |
128 | Match= F_CPU/f; |
129 | |
130 | if(Pos_ist >= Pos_soll) |
131 | {
|
132 | PORTD |= (1<<PD0); // Motor aus |
133 | }
|
134 | }
|
135 | } // Ende while |
136 | Schrittmotor_flag=0; |
137 | } // Ende Schrittmotor |
Vielen Dank für die Bemühung. Ich würde mich auch darüber freuen wenn der eine oder andere ein Wort darüber verlieren könnte, was ich evtl am Programmierstil verbessern könnte. Gruß Christian
Ich vermute, dass in der Berechnung von Match irgendetwas überläuft. Es ist auch sicher nicht ideal, diese als float type zu verwenden. Der wurzel Algorithmus ergibt long. Warum dann wieder auf float konvertieren und dann bei der Zuweisung
1 | OCR1A=Match; |
auf unsigned int (16 bit) ? Zum Programmierstil gibts sicher viele Tips, z.B. - verwenden von #defines für die PINS z.B.
1 | #define MSTEP_PIN PB2
|
2 | #define MSTEP_PORT PORTB
|
3 | |
4 | MSTEP_PORT |= _BV(MSTEP_PIN); // Motor-Takt AN |
- ich liebe switch anweisungen, z.B :
1 | switch(Fahrt_Flag) { |
2 | case 1 : // Ansteigend |
3 | ....
|
4 | break; |
5 | case 2 : // konstant |
6 | ....
|
7 | break; |
8 | default:
|
9 | }
|
oder noch besser
1 | #define RAMP_UP (1)
|
2 | #define RAMP_DOWN (3)
|
3 | #define CONST_MOTION (2)
|
4 | |
5 | switch(Fahrt_Flag) { |
6 | case RAMP_UP : // Ansteigend |
7 | ....
|
8 | break; |
9 | case CONST_MOTION : // konstant |
10 | ....
|
11 | break; |
12 | default:
|
13 | }
|
:
Bearbeitet durch User
wo hast du denn bitte post_ist und post_akt her. und hast du bitte das programm in ganzer form?
franck schrieb: > wo hast du denn bitte post_ist und post_akt her. und hast du bitte das > programm in ganzer form? Da kann man mal sehen, wie die Zeit vergeht ;-) Aber wenn Du ein Programm für ATmega88/168/328 suchst: http://www.mino-elektronik.de/Generator/takte_impulse.htm#bsp7 ff.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.