Forum: Mikrocontroller und Digitale Elektronik Ansteuerung eines Getribeschrittmotors in abhängigkeit der Drehzahl (nonblocking)


von Daniel B. (dannyboy1994)


Lesenswert?

Hallo Leute.
Ich bin momentan wieder an einem ehemals bereits verworfenen Projekt.
Hintergrund ist die Ansteuerung mehrerer Schrittmotoren in abhängigkeit 
der Drehzahl. Einer der Motoren hat eine Auflösung von 1000 schritten, 
die anderen von jeweils nur 200.

Nachdem ich etwas mit Arduino rumgespielt habe, und das endergebniss mit 
Accelstepper und Millis so aussah das der Motor Chronisch Schritte 
verloren hat, dachte ich mir...ok versuchens wir mit ASM.

Wichtig ist dass das ganze nicht die CPU blockiert (also auf grundlage 
von interrupts), dar nachher noch ein 4x20 LCD einige Taster und ein ADC 
Kanal benutzt werden sollen.

Ziel:
Ein Schrittmotor mit Getriebe treibt eine Extruderschnecke an(nach 
anfänglicher skepsis und einigen test stellte sich herraus das der 
Stepper ab 150 grad mehr als genug Kraft dafür entwickelt)
Ein Messwandler misst  via PT1000 die temperatur der Düse und setzt 
diese in 0-5V um

Der Sollwert der Temperatur und die geschwindigkeit des Motors werden 
per Display Menü vorgegeben

Iwie beschleicht mich allerdings das gefühl das der AVR dafür zulangsam 
ist.
Der Versuch die Drehzahl in eine Zetbasis von 10micros umzurechnen (also 
160 takte) scheiterte daran das die interrupts schneller passierten als 
die Berechnung fertig war.

Der Versuch die Werte im EEPROM von welchem ich mich bis jetzt immer 
fern gehalten habe zu speichern und die Adresse an hand des Sollwerts zu 
errechnen, endete im geistigem nirvana.

Hat vllt jemand eine Zündende Idee. Egal was ich bisher versucht habe, 
das ergebniss war immer das jede kleinste nebentätigkeit (LCD.RS232) den 
AVR an sien Limit brachten und die motoren die Drehzahl nicht haltne 
konnten.

Die Impulse zu erzeugen, werte im RAM abzulegen und jeweils um die 
intervalzeit zu addieeren sheint zu funktionieren. Das Lesen aus dem 
EEPROM jedoch nicht. Es ergibt sich immer 0XFF...


Hier einmal der Code:
1
.include "m328Pdef.inc"
2
3
4
.CSEG
5
.def temp = r16
6
.def temp2 = r17
7
.def temp3 = r18
8
.def temp4 = r19
9
.def micros_lsb = r20          //micros beinhaltet die vergangenen microsekudnen *10 um mehr spielraum zwischen den interrupts zu bekommen
10
.def micros_msb = r21  
11
12
.equ extruderddr = ddrb
13
.equ extruderpin = PB1
14
.equ extruderport = portb
15
.equ debug_mode = 1            // Wenn 1 werden alle SRAM Adressen mit smulationsfreundlichen werten vorbelegt
16
.def flags = r22
17
.equ update = 0b00000001
18
19
20
.org 0x0000
21
  rjmp main
22
23
.org 0x0016 
24
  rjmp TIMER0_COMPA
25
//Ein Timer 
26
27
// Die jeweiligen Werte die für ein event nötig sind werden im sram gespeichert
28
//Die kontrolle der taktzeiten findet nur stadt wenn ein interrupt des timers aktiv war und das flag im flags register gesetzt ist
29
// Die berechnung soll nur durchgeführt werden wenn sich die solldrehzahl geändert hat
30
31
//*nicht umgesetzte und getestet ideen:
32
33
34
35
.org 0x0042
36
main:
37
38
         ldi temp, HIGH(RAMEND)            ; HIGH-Byte der obersten RAM-Adresse
39
         out SPH, temp
40
         ldi temp, LOW(RAMEND)             ; LOW-Byte der obersten RAM-Adresse
41
         out SPL, temp
42
     ldi temp, 1
43
     mov r2, temp
44
     clr r3
45
     nop
46
     rjmp setup
47
48
49
    
50
    rjmp main
51
52
debugging:
53
push temp
54
ldi temp, 0x02
55
sts soll_RPM_extruder, temp
56
pop temp
57
call extruderpuls
58
rjmp loop
59
60
61
setup:
62
timer_setup:
63
ldi temp, 160
64
sts OCR1AL, temp
65
ldi temp, 0x09
66
sts TCCR1B, temp
67
ldi temp, 0x02
68
sts TIMSK1, temp
69
sei
70
71
ldi temp, debug_mode
72
cpi temp, 1
73
breq debugging
74
call extruderpuls
75
rjmp loop
76
77
78
79
///////////////////////////////////////////////////////Hauptschleife////////////////////////////////////////////
80
loop:
81
82
call check_timings
83
rjmp loop
84
85
86
87
check_timings:
88
89
push temp                    //temp sichern
90
push temp2                    //temp2 sichern
91
92
mov temp, flags                  //flagregister laden
93
sbrs temp, 0                  //wenn bit 0 gesetzt ist, trat ein interrupt auf und die micros wurden aktuallisiert
94
rjmp skipped_all
95
cbr flags, update
96
//Extrudermotor        
97
lds temp, extrudermotor_MSB            //msb aus RAM laden
98
cp temp, micros_MSB              //und mit micros msb vergleichen
99
brne skipped_EX                  //wenn MSB nicht gleich ist ->abbruch
100
lds temp, extrudermotor_LSB            //LSB laden
101
cp temp, micros_LSB              //mit micros vergleichen
102
brne skipped_ex
103
104
lds temp, extrudermotor_LSB            //LSB laden
105
cp temp, micros_LSB              //mit micros vergleichen
106
breq extruderpuls_true
107
rjmp skipped_ex
108
extruderpuls_true:
109
rcall extruderpuls
110
111
skipped_ex:                  //vergleich von Extruder nicht Wahr oder puls bereits ausgeführt
112
113
114
//////HIER DER SELBE CODE WIE OBEN FÜR JEDEN WETEREN MOTOR
115
116
117
skipped_all:
118
119
pop temp2
120
pop temp
121
122
123
ret
124
125
/////////////////////////////////////////////MOTORIMPULSE UND AKTUALISIERUNG//////////////////////////////
126
extruderpuls:
127
////////////////////////////////////////////IMPULSERZEUGUNG
128
sbi extruderddr, extruderpin
129
sbi extruderport,extruderpin
130
push temp
131
ldi temp, 3
132
bla1:
133
dec temp                        //mindestimpuls 1 microsekunde also 16 takte
134
cpi temp, 0
135
brne bla1
136
cbi extruderport, extruderpin
137
rcall extruder_time_calculation
138
139
////////////////////////////////////////////UPDATE
140
141
//Extruderwert mit den werten aus dem ram aktuallisieren und addieren
142
143
lds temp, extrudermotor_LSB      //LSB in temp 1 lesen
144
lds temp2,extrudermotor_LSB_soll  //LSB des Sollwertes
145
lds temp3, extrudermotor_MSB
146
lds temp4, extrudermotor_MSB_soll
147
148
149
add temp, temp2            //addition des LSB 
150
adc temp3, temp4
151
sts extrudermotor_LSB, temp      //neuen Wert speichern
152
sts extrudermotor_MSB, temp3
153
154
pop temp
155
ret
156
157
158
159
extruder_time_calculation:
160
//////////////////////////////////////////Anhand der Drehzahl die Zeit als faktor von 10 micors berechnen
161
162
163
//Nur ausführen wenn Flag 2 in flags gesetzt ist (update_request_extruder)
164
//Es ergibt sich folgende formel 100000/(RPM/60*STEPPS)
165
166
//Bei 1 RPM un d 200 steps auflösung ergibt sich ein wert von 30.000
167
//Bei 100 RPM ergibt sich ein wert von 300
168
//bei 60 RPM ein Wert von 500
169
170
//Dar der Extruder ein Getribemotor 1:5 ist
171
//ergibt sich (100.000/(RPM/60x1000)
172
//somit für 60 RPM ein Wert von 100
173
//für 1 RPM ein Wert von 6000
174
//für 100RPM ein Wert von 60
175
176
177
//Idee wurde verworfen
178
//Daten sind im EEPROM gespeichert
179
//Adresse 1 enstpsricht 1 RPM und aufwärts
180
181
push temp
182
push temp2
183
push temp3
184
push temp4
185
186
lds temp, soll_RPM_extruder
187
188
189
cpi temp, 1
190
breq RPM1
191
cpi temp, 2
192
breq RPM2
193
cpi temp, 3
194
breq RPM3
195
196
rjmp ende
197
RPM1:
198
ldi temp3, LOW(ex1MSB)
199
ldi temp4, HIGH(ex1MSB)
200
201
out EEARH, temp4
202
out EEARL, temp3
203
sbi EECR, EERE
204
in temp2, EEDR          //HIGHBYTE gelsen
205
206
ldi temp3, LOW(ex1LSB)
207
ldi temp4, HIGH(ex1LSB)
208
209
out EEARH, temp4
210
out EEARL, temp3
211
sbi EECR, EERE
212
in temp, EEDR          //LSB gelsen
213
214
sts extrudermotor_LSB_soll, temp
215
sts extrudermotor_MSB_soll, temp2
216
rjmp ende
217
RPM2:
218
ldi temp3, LOW(ex2MSB)
219
ldi temp4, HIGH(ex2MSB)
220
221
out EEARH, temp4
222
out EEARL, temp3
223
sbi EECR, EERE
224
in temp2, EEDR          //HIGHBYTE gelsen
225
226
ldi temp3, LOW(ex2LSB)
227
ldi temp4, HIGH(ex2LSB)
228
229
out EEARH, temp4
230
out EEARL, temp3
231
sbi EECR, EERE
232
in temp, EEDR          //LSB gelsen
233
234
sts extrudermotor_LSB_soll, temp
235
sts extrudermotor_MSB_soll, temp2
236
rjmp ende
237
RPM3:
238
ldi temp3, LOW(ex3MSB)
239
ldi temp4, HIGH(ex3MSB)
240
241
out EEARH, temp4
242
out EEARL, temp3
243
sbi EECR, EERE
244
in temp2, EEDR          //HIGHBYTE gelsen
245
246
ldi temp3, LOW(ex3LSB)
247
ldi temp4, HIGH(ex3LSB)
248
249
out EEARH, temp4
250
out EEARL, temp3
251
sbi EECR, EERE
252
in temp, EEDR          //LSB gelsen
253
254
sts extrudermotor_LSB_soll, temp
255
sts extrudermotor_MSB_soll, temp2
256
rjmp ende
257
258
259
260
ende:
261
pop temp4
262
pop temp3
263
pop temp2
264
pop temp
265
ret
266
267
268
269
270
271
//////////////////////////////////////////////////Interruptroutinen///////////////////////////////////////////
272
TIMER0_COMPA:
273
ldi temp, 1
274
add micros_lsb, r2
275
adc micros_msb, r3
276
ldi temp, 160                  //160 Takte ohne prescaler bei 16 mhz ergibt einen eine auflösung von 10 micros
277
sts OCR1AL, temp
278
sbr flags, update                //Zähler wurde aktuallisiert, also Flag setzen um im loop die motoren mit dem neuen Wert zu vegleichen
279
reti
280
281
282
283
284
285
//Die RAM Adressen
286
.DSEG                ; Umschalten auf das SRAM Datensegment
287
debbuging:            .BYTE  1
288
extrudermotor_LSB:       .BYTE  1        //Zeitpunkt des nächsten events
289
extrudermotor_MSB:        .BYTE  1
290
291
extrudermotor_LSB_soll:     .BYTE  1        //Zeitdifferenz anhand der Drehzahl
292
extrudermotor_MSB_soll:     .BYTE  1
293
294
soll_RPM_extruder:   .BYTE  1
295
296
297
298
.ESEG
299
300
ex1MSB:    .db 0x17
301
ex1LSB:    .db 0x70      //6000      also 60.000 micros
302
ex2MSB:    .db 0x0B
303
ex2LSB:    .db 0xB8      //3000
304
ex3MSB:    .db 0x07
305
ex3LSB:    .db 0xD0      //2000
306
ex4MSB:    .db 0x05
307
ex4LSB:    .db 0xDC      //1500
308
309
ex5MSB:  .db  0x04
310
ex5LSB:  .db  0xB0      //1200
311
312
ex6MSB:  .db  0x03
313
ex6LSB:  .db  0xE8      //1000
314
315
ex7MSB:  .db  0x03
316
ex7LSB:  .db  0x58      //856
317
318
ex8MSB:  .db  0x02
319
ex8LSB:  .db  0xEE      //750
320
321
ex9MSB:  .db  0x02
322
ex9LSB:  .db  0x9A      //666
323
324
ex10MSB:.db  0x02
325
ex10LSB:.db  0x58      //600
326
327
ex11MSB:.db  0x02
328
ex11LSB:.db  0x21      //545
329
330
ex12MSB:.db  0x01
331
ex12LSB:.db  0xF4      //500
332
333
ex13MSB:.db  0x01
334
ex13LSB:.db  0xCC      //460
335
336
ex14MSB:.db  0x01
337
ex14LSB:.db  0xAD      //429
338
339
ex15MSB:.db  0x01
340
ex15LSB:.db  0x90      //400
341
342
ex16MSB:.db  0x01
343
ex16LSB:.db  0x77      //375
344
345
ex17MSB:.db  0x01
346
ex17LSB:.db  0x60      //352
347
348
ex18MSB:.db  0x01
349
ex18LSB:.db  0x4D      //333
350
351
ex19MSB:.db  0x01
352
ex19LSB:.db  0x3B      //315
353
ex20MSB:.db  0x01
354
ex20LSB:.db  0x2C      //300
355
356
ex21MSB:.db  0x01
357
ex21LSB:.db  0x1E      //286
358
359
ex22MSB:.db  0x01
360
ex22LSB:.db  0x10      //272
361
362
ex23MSB:.db  0x01
363
ex23LSB:.db  0x04      //260
364
365
ex24MSB:.db  0x00
366
ex24LSB:.db  0xFA      //250
367
368
ex25MSB:.db  0x00
369
ex25LSB:.db  0xF0      //240

: Bearbeitet durch Moderator
von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Daniel B. schrieb:
> Hier einmal der Code
Lies bitte das nächste mal die Bedienungsanleitung, die über jedem 
Texteingabefeld steht:
1
Antwort schreiben
2
Wichtige Regeln - erst lesen, dann posten!
3
    Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang
4
5
Formatierung (mehr Informationen...)
6
    [c]C-Code[/c]
7
    [avrasm]AVR-Assembler-Code[/avrasm]

Und lies auch die Bedienungsanleitung zum Forum Projekte&Code:
1
Forum: Projekte & Code
2
3
Hier könnt ihr eure Projekte, Schaltungen oder Codeschnipsel vorstellen
4
und diskutieren. Bitte hier keine Fragen posten!

Daniel B. schrieb:
> Wichtig ist dass das ganze nicht die CPU blockiert (also auf grundlage
> von interrupts)
Natürlich blockiert gerade ein Interrupt die CPU. Denn solange ein 
Interrupt aktiv ist und Rechenzeit verbraucht, kann kein zweiter 
Interrupt kommen.

> Iwie beschleicht mich allerdings das gefühl das der AVR dafür zulangsam
> ist.
Wenn ich mir den Code so überschlägig ansehe, beschleicht mich das 
Gefühl, dass da was in Richtung Semaphorenproblem unterwegs sein könnte:
1
cp temp, micros_MSB //und mit micros msb vergleichen
2
brne skipped_EX //wenn MSB nicht gleich ist ->abbruch
3
4
--- hier kommt ein Interrupt. Was passiert, wenn micros_LSB vorher 0xff war? 
5
6
lds temp, extrudermotor_LSB //LSB laden
7
cp temp, micros_LSB //mit micros vergleichen

: Bearbeitet durch Moderator
von Daniel B. (dannyboy1994)


Lesenswert?

Nabend Lothar. Das mit dem Quellcode tut mir Leid.

Wärst du bitte so freundlich den Thread zu verschieben.


Sollte in diesem Moment ein Interrupt auftreten, wäre meines Erachtens 
nach der ganze Impuls verloren und die Berechnung des nächsten Updates 
würde ins nirvana laufen.
Dar aber diese Prüfung nur durchlaufen wird wenn das flag demensprechend 
gesetz ist und folglich vorher kürzlich ein Interrupt stattgefunden hat, 
ist die möglichkeit das hier d er nächste interrupt auftritt sehr 
gering, außer die Hauptschleife un Prüfung bis zu diesem Punkt wird 
länger als 160 takte.

Sollte man den Fall dass das LSB 1 größer ist folglich auch noch mit 
abfangen? um auf Nummer sicher zu gehen.


Weiter komme ich auch nicht mit der Zueisung des Wertes anhand der 
Drehzahl.

Eine Berechnung dauert deutlich zu lange. Und die im EEPROM abgelegten 
Werte unter ESEG liefern beim lesen (testweise nur 1-3 Umdrehungen im 
Code implementiert) immer den Wert 0xFFFF zurück.


Gruß Daniel

von H.Joachim S. (crazyhorse)


Lesenswert?

Daniel B. schrieb:
> TIMER0_COMPA:
> ldi temp, 1
> add micros_lsb, r2
> adc micros_msb, r3
> ldi temp, 160                  //160 Takte ohne prescaler bei 16 mhz
> ergibt einen eine auflösung von 10 micros
> sts OCR1AL, temp
> sbr flags, update                //Zähler wurde aktuallisiert, also Flag
> setzen um im loop die motoren mit dem neuen Wert zu vegleichen
> reti

Kurz drübergeschaut - was ist mit dem SREG?
und:
sts OCR1AL, temp
dürfte auch nicht tun, was du erwartest. Du musst OCR1AH und OCR1AL 
schreiben.

von Daniel B. (dannyboy1994)


Lesenswert?

Spielst du darauf an dass das SREG nicht gesichert wurde?

Ich habe es mal folgendermaßen geändert und assembliert
1
TIMER0_COMPA:
2
push temp
3
in temp, SREG
4
push temp
5
ldi temp, 1
6
add micros_lsb, r2
7
adc micros_msb, r3
8
ldi temp, 160                  //160 Takte ohne prescaler bei 16 mhz ergibt einen eine auflösung von 10 micros
9
sts OCR1AL, temp              //OCRA1H bleibt null dar Timer 1 ein 16biit timer ist, allerdings
10
// nur bis 160 im CTC Mode gezählt wird
11
sbr flags, update                //Zähler wurde aktuallisiert, also Flag setzen um im loop die motoren mit dem neuen Wert zu vegleichen
12
pop temp
13
out SREG, temp
14
pop temp
15
reti

von H.Joachim S. (crazyhorse)


Lesenswert?

Daniel B. schrieb:
> Das Lesen aus dem
> EEPROM jedoch nicht. Es ergibt sich immer 0XFF...

Hast du sie denn überhaupt in den Chip gebrannt?
Die Erzeugung des eep-files brennt diese erstmal nicht in den Chip beim 
flashen.
Und was sollen die Daten überhaupt im Eeprom? Konstanten holt man am 
besten aus dem flash.

von MaWin (Gast)


Lesenswert?

Daniel B. schrieb:
> Iwie beschleicht mich allerdings das gefühl das der AVR dafür zulangsam
> ist

Wie hoch soll denn die Drehzahl sein ? Und wieviele Schrittimpulse 
braucht der Treiber dafür, Vollschritte oder Mikroschritte.

Und warum ein Motor mit 1000 und mehrere (wieviel ist mehrere) mit 200.

Mich beschleicht das Gefühl, als ob es nicht um mehrere 
Extruderschnecken geht, sondern ein AVR einen 3d-Drucker bewegen soll 
und ZUSÄTZLICH die Extruderschnecke. Die wiederum mal extrudiert und mal 
innehält (sogar zurückzieht um ein gutes Abreissen zu bewirken).

Egal was, ein Schrittmotor schafft kaum mehr als 1000 Schritte pro 
Sekunde, und ein AVR in der Zeit 16000 Befehle. Das kann ihn nur 
überfordern, wenn man den Überblick beim Programmieren verliert. 
Assembler ist ein guter Schritt um den Überblick zu verlieren. 
Arduinocode auch.

Legt man das zeitkritische in eine Interruptroutine:
1
Timer1CompA:
2
  push r2,r26,r27
3
  ld r26,ptrlow
4
  ld r27,ptrhigh
5
  ld r2, X+
6
  out portb,r2
7
  ld r2, X+
8
  out portc,r2
9
  ld r2, X+
10
  add t1cmpal,r2
11
  ld r2, X+
12
  adc t1cmp1h,r2
13
  st ptrlow,r26
14
  pop r27,r26,r2
15
  reti
Diese kleine Routine ändert beim nächsten Timer 1 compare interrupt die 
Ports B und C auf vorbereitete Werte und programmiert den Timer um so 
dass er in n ticks wieder auslöst.

Welchen Wert die ports bekommen und wie viele ticks veegehen sollen bis 
sie sich wieder ändern steht in eindm Array;
1
struct
2
{
3
  uint8_t portbvalue;
4
  uint8_t portcvalue;
5
  uint16_t ticks;
6
}
7
preparedevents[64];
Diesen buffer muss nun das Hauptprogramm in seiner Schleife rechtzeitig 
füllen, aber nie überfüllen, also mehr als 63 vorab berechnet haben. Das 
Hauptprogramm arbeitet aber zeitunkritisch, kann in C programmiert 
werden.

Wer so programmiert, kann 8 Motoren simultan mit 500000 Schrittimpulsen 
pro Sekunde steuern, das kann nicht zu langsam sein.

von Daniel B. (dannyboy1994)


Lesenswert?

H.Joachim S. schrieb:
> Daniel B. schrieb:
>> Das Lesen aus dem
>> EEPROM jedoch nicht. Es ergibt sich immer 0XFF...
>
> Hast du sie denn überhaupt in den Chip gebrannt?
> Die Erzeugung des eep-files brennt diese erstmal nicht in den Chip beim
> flashen.
> Und was sollen die Daten überhaupt im Eeprom? Konstanten holt man am
> besten aus dem flash.



Die Daten hätte ich in den EEPROM ausgelagert, dar sie sich nie ändern 
werden. Das Ansprechen einer Adresse im Flash, mit Hilfe des Z-Pointers 
war für mich shcon immer recht undurchsichtig. Wenn du mich hier 
erleuchten kannst, wäre das natürlich auch eine möglichkeit.

MaWin schrieb:
> Daniel B. schrieb:
>> Iwie beschleicht mich allerdings das gefühl das der AVR dafür zulangsam
>> ist
>
> Wie hoch soll denn die Drehzahl sein ? Und wieviele Schrittimpulse
> braucht der Treiber dafür, Vollschritte oder Mikroschritte.
>
> Und warum ein Motor mit 1000 und mehrere (wieviel ist mehrere) mit 200.
>

Das mit den 1000 Schritten kommt daher, dass der Motor ein Getriebe mit 
der übersetzung 1:5 antreibt,w elches dann die Schnecke bewegen soll.


> Mich beschleicht das Gefühl, als ob es nicht um mehrere
> Extruderschnecken geht, sondern ein AVR einen 3d-Drucker bewegen soll
> und ZUSÄTZLICH die Extruderschnecke. Die wiederum mal extrudiert und mal
> innehält (sogar zurückzieht um ein gutes Abreissen zu bewirken).
>
Der AVR soll am ende folgende tätigkeiten bewältigen:
-Extrudermotor antreiben mit ca 20-30 Umdrehungen. Erste Tests zeigten 
das dieser Drehzahl bereich prinzipiell ausreichend wäre. Getestet wurde 
es quick und dirty mit der Arduino Lib "Accel_stepper"
-2 weitere Nema Stepper (200 schriite pro Umdrehung) in gemächlichen 
Tempo, zum Aufrollen des ganzen
-Ein Relais für eine Wasserpumpe
- 2 Relais für 2 Heizzonen
-2 temperaturfühler welche ein 0-5V Signal aus 0-10V über einen 
Spannungsteiler liefern.
-1 MOSFET für die Hopperkühlung
-1 MOSFET für einen "blas das restliche Wasser weg"- Lüfter
-1 LCD 4x20 das nur bei änderungen aktualisiert werden soll und Infos 
über Drehzahl des Extruders, Temperatur, Drehzahl des Wicklers geben 
soll und als Bedienelement mit 3 simplen Tastern realisiert wird


> Egal was, ein Schrittmotor schafft kaum mehr als 1000 Schritte pro
> Sekunde, und ein AVR in der Zeit 16000 Befehle. Das kann ihn nur
> überfordern, wenn man den Überblick beim Programmieren verliert.
> Assembler ist ein guter Schritt um den Überblick zu verlieren.
> Arduinocode auch.
>
Der Schritt weg von Arduino und hin zu Assembler war derart begründet, 
dass man hier einfach eher einen überblick darüber aht welche Recourcen 
gerade was bewerkstelligen und sich nciht mit so prezisen Aussagen wie 
"möglichst häufg aufrufen" zufreiden geben muss.


> Legt man das zeitkritische in eine Interruptroutine:Timer1CompA:
>   push r2,r26,r27
>   ld r26,ptrlow
>   ld r27,ptrhigh
>   ld r2, X+
>   out portb,r2
>   ld r2, X+
>   out portc,r2
>   ld r2, X+
>   add t1cmpal,r2
>   ld r2, X+
>   adc t1cmp1h,r2
>   st ptrlow,r26
>   pop r27,r26,r2
>   reti
> Diese kleine Routine ändert beim nächsten Timer 1 compare interrupt die
> Ports B und C auf vorbereitete Werte und programmiert den Timer um so
> dass er in n ticks wieder auslöst.
>
> Welchen Wert die ports bekommen und wie viele ticks veegehen sollen bis
> sie sich wieder ändern steht in eindm Array;struct
> {
>   uint8_t portbvalue;
>   uint8_t portcvalue;
>   uint16_t ticks;
> }
> preparedevents[64];
> Diesen buffer muss nun das Hauptprogramm in seiner Schleife rechtzeitig
> füllen, aber nie überfüllen, also mehr als 63 vorab berechnet haben. Das
> Hauptprogramm arbeitet aber zeitunkritisch, kann in C programmiert
> werden.
>
> Wer so programmiert, kann 8 Motoren simultan mit 500000 Schrittimpulsen
> pro Sekunde steuern, das kann nicht zu langsam sein.

von H.Joachim S. (crazyhorse)


Lesenswert?

Daniel B. schrieb:
> ldi temp3, LOW(ex1MSB)
> ldi temp4, HIGH(ex1MSB)
>
> out EEARH, temp4
> out EEARL, temp3
> sbi EECR, EERE
> in temp2, EEDR          //HIGHBYTE gelsen
>
> ldi temp3, LOW(ex1LSB)
> ldi temp4, HIGH(ex1LSB)
>
> out EEARH, temp4
> out EEARL, temp3
> sbi EECR, EERE
> in temp, EEDR          //LSB gelsen

Naja, Assembler mache ich seit Jahren fast nicht mehr, es gibt auch nur 
ganz selten wirklich Grund dafür.

Ohne Gewähr, etwa so:
ldi zl, low (2* ex1MSB)
ldi zh, high (2* ex1MSB)   //Adresse deiner Konstanten nach Z
lpm temp2, z+              //high Byte lesen
lpm temp, z                //low Byte lesen

Byte order beachten, muss man sich in Hochsprachen nicht drum kümmern, 
in Assembler schon.
Viele "temps" erhöhen auch nicht gerade die Lesbarkeit, Fehler nehmen 
auch deutlich zu.

von Daniel B. (dannyboy1994)


Lesenswert?

> Byte order beachten, muss man sich in Hochsprachen nicht drum kümmern,
> in Assembler schon.
> Viele "temps" erhöhen auch nicht gerade die Lesbarkeit, Fehler nehmen
> auch deutlich zu.

Ist dir aus dem stehgreif eine möglichkeit bekannt über den folgenden 
wertebereich anhand der adresse wie über eine lsite in python via index 
zu zugreifen?

von Falk B. (falk)


Lesenswert?

Daniel B. schrieb:
> Iwie beschleicht mich allerdings das gefühl das der AVR dafür zulangsam
> ist.

Lächerlich ;-)
Der langweilt sich zu Tode, wenn man ihn nicht in naivster Noob-Manier 
mit sinnlosen Warteschleifen blockiert. Das schafft man auch in ASM.

Und nebenbei, lange Quelltexte gehören in den Anhang, siehe 
Netiquette,

von Thomas F. (igel)


Lesenswert?

Daniel B. schrieb:
> Ist dir aus dem stehgreif eine möglichkeit bekannt über den folgenden
> wertebereich anhand der adresse wie über eine lsite in python via index
> zu zugreifen?

Schau mal hier. Daraus lässt sich das gewünschte bestimmt 
zusammenbasteln.

https://www.mikrocontroller.net/articles/AVR-Tutorial:_Mehrfachverzweigung

von Daniel B. (dannyboy1994)


Angehängte Dateien:

Lesenswert?

Nabend zusammen. Ich habe mir die Mehrfachverzeigungn mit dem Zpointer 
einmal angesehen und eta rumprobiert mit dem Simulator. Ein segen das 
AVR Studio 4 noch auf WIndows 10 läuft :D

Der verweis auf diesen Link war mehr als Hilfreich.

Ich habe euch das getestete Programm mal in den Anhang gepackt.

Die Sprugtabelle werde ich jetzt dann noch entsprechend erweitern.
Im Allgemeinen Funktioniert diese Methode einwandfrei.

Und alles wird im verlgeich zu endlosen
cpi rxx,xx
breq
...
wesentlich übersichtlicher.

Ich habe die entsprechenden Werte für die Register zum Verlgeichen mit 
den 10ermicros nun fest in den Code integriert. Bei dieser 
vorgehensweise mit Z-Pointer halte ich es aktuell erst mal nicht für 
nötig diese auszulagern, dar das laden nur wiedr Taktzyklen kosten 
würde.
Die Entscheidung und der Sprung läuft innerhalb weniger takte durch und 
kann fast beliebig erweitert werden.


An diesem Punkt, an dem die Motordrehzahl des Extruders erst einmal 
soweit funktionstüchtig ist, wäre es denke ich Zeit um den Code etwas 
aufzuräumen.

Seht ihr auf Anhieb stellen, an denen ich das ganze etwas 
übersichtlicher gestalten kann?
Wäre für jeden Tipp dankbar.

möchte ungern mit dem nächsten Teil vortfahren ohne hier erst einmal 
Ordnung geschaffen zu haben.

von Daniel B. (dannyboy1994)


Angehängte Dateien:

Lesenswert?

Ich habe gerade versucht ein paar kleinigkeiten zu ändenr.

Beim Simulieren ist mir nun etwas aufgefallen.

Ich nutze ein Flag in R22 bit 1 um zu signalisieren das sich die 
solldrehzahl geändert hat.

nun versuche ich , wie oben im screenshot ersichtlich, folgenden befehl 
zu überspringen via sbrc anweisung.
1
cbi extruderport, extruderpin
2
sbrc flags, ex_rpm_change                //Wenn Solldrehzahl unverändert ist nächsten sprung übrspringen
3
rcall extruder_time_calculation

allerdings ist laut register view das flag dauerhaft gesetzt....wenn das 
flag gesetzt ist dürfte die anweisung ja auch nicht übersprungen 
werden...er tut allerdings selbiges. Im Anhang auch noch mal die ASM

von Daniel B. (dannyboy1994)


Angehängte Dateien:

Lesenswert?

Der oben genannte Fehler war wieder einmal die stolperfalle mit cbr und 
sbrc
, und wurde durch folgende Lösung ersetzt

" sbi flags, 1<<update"

in dem ich bei den sbi und cbi befehlen eine 1 an die gewollte stelle 
durchreiche.

Ich habe das ganze um einige Flags erweitert, sowie versucht etwas 
aufzuräumen.

Außerdem ist jetzt bereits die zweite Motorsteuerung des Motors "pully" 
mit intigriert. Die ASM hänge ich direkt mal wieder an.

Stechen euch Schönheitsfehler ins Auge? Oder Dinge die ihr anders lösen 
würdet?

Als nächstes würde ich das einlesen des ADC intigrieren und die 
speicherung und umsetzung des Wertes in eine Temperatur.
Berechnungen sind für mich immer eine leichte Herrausforderung, dar es 
oft nicht ohne division funktioniert, und das doch einiges an Takten in 
Anspruch nimmt.

von Daniel B. (dannyboy1994)


Angehängte Dateien:

Lesenswert?

Nabend zusammen. Nach dem das takten der Motoren soweit funktioniert 
hat, wollte ich nun das ganze ein wenig Erweitern. Die Motoren sollten 
erst einmal nur laufen wenn entsprechende eingänge gesetzt sind. Bei 
gesetztem Eingang sollte das Programm in "power_extruder" springen und 
den enable pin auf low ziehen wlecher an den A4988 treiber angeshclossen 
ist.

Nun sitze ich schon einige Zeit hier...eigentlich sollten dei Pulse ganz 
nrmal weiter erzeugt werden, und der enable pin enschedet ob der motor 
läuft, oder nicht. Dieser wird gesetzt wenn der Eingang 
"extruder_switch" HIGH ist..
und so dentreiber aktivieren. leider funktioniert das ganze nicht so wie 
es sollte.

Er springt egal in welchem Zustand sich der Pin befindet immer in den 
zweig für das deaktivieren des Motors...

Hätte jemand eventuell Lust sich das ganze nocheinmal anzusehen?
Ich stehe irgendwie auf dem schlauch..

Irgendetwas muss ich übersehen haben...

Ih hänge den Code einmal an diesen Post an.



Update:
Nachdem ich einige Fehler entdecken konnte, sieht es nun so aus:

Wenn der Etruder und der pully aktiviert werden läuft alles soweit. wird 
der pully deaktiviert wird der ausgang nicht wieeder gesetzt. Auch 
scheint es bei beiden motoren das Problem mit dem "xxx_running" flag zu 
geben.. teilweise scheint de stack über zu laufen, dar er wieder nach 
0x00 springt...

von H.Joachim S. (crazyhorse)


Lesenswert?

Das Problem ist, dass nicht viele Lust haben, sich zum Spass mit 
Assembler zu beschäftigen - es ist nun mal unübersichtlicher und die 
Logik nicht so leicht zu verstehen und damit Fehler zu erkennen.
Ich bin nach wie vor der Meinung, dass du hier kaum eine Zeile Assembler 
benötigst.

von Daniel B. (dannyboy1994)


Lesenswert?

Guten Abend Joachim.

Mit C habe ich mich nie wirklich befasst, bzw herumgequält. Allein die 
Art ein bit in einem Register zu setzen und das geklammer, haben meine 
nerven strapaziert.

Ich denke ich werde noch ein wenig Zeit investieren, und sollte ich 
absolut nicht mehr weiter kommen, und keiner mehr eine idee haben...muss 
ich wohl oder übel in den saueren Apfel beißen.

In Arduino habe ich schon so einiges umgesetzt. Allerdings vertraue ich 
der IDE und allem waa im hintergrund abläuft nicht so recht, was 
zeitkritische sachen betrifft.

Einsteigerfreundlich ist es, aber Aussagen wie "so oft wie möglich 
aufrufen" klingen für mich nicht sonderlich vertrauenserweckend. Die Lib 
AccelStepper scheint nicht auf interrupts o.Ä zurück zu greifen.

Auch denke ich das ich in egal welcher Programmeirsprache auf 
stolpersteine stoßen werde. ASM wurde mir zu Schulzeiten einmal in einem 
kleinem Crashkurs nahegelegt, und ich hat einfach dieses "genau wissen 
das die MCU gerade macht" schon immer fasziniert.

Gruß
Daniel

von Thomas F. (igel)


Lesenswert?

Daniel B. schrieb:
1
.org 0x0042
2
main:
3
     ldi temp, HIGH(RAMEND)
4
     out SPH, temp
5
     ldi temp, LOW(RAMEND)
6
     out SPL, temp
7
...
8
     rjmp setup
9
    
10
    rjmp main

Das verwirrt: das rjmp main wird nie erreicht. Außerdem kann das .org 
entfallen.


Du hast in all deinen Routinen massen push und pop drinnen. Die brauchst 
du aber nur in einer Interruptroutine. Da hast du ja nur eine, da passt 
es auch.
Di ganzen push und pop würde ich rausnehmen.

von Thomas F. (igel)


Lesenswert?

1
TIMER1_COMPA:
2
push temp
3
in temp, SREG
4
push temp
5
...
6
ldi temp, 160          //160 Takte 
7
sts OCR1AL, temp       //OCRA1H bleibt null 
8
sbr flags, 1<<update   //Zähler wurde aktuallisiert, also Flag setzen 
9
10
pop temp
11
out SREG, temp
12
pop temp
13
reti

Das OCR muss man nicht bei jedem Interruptaufruf neu schreiben, das 
bleibt eigentlich erhalten.

von H.Joachim S. (crazyhorse)


Lesenswert?

.def sreg_bak = r2

in temp, SREG
push temp
.
.
pop temp
out SREG, temp

in sreg_bak, SREG
.
.
out SREG, sreg_bak

Kann man immer machen, wenn Register ungenutzt vor sich hingammeln.

inc temp
inc temp
inc temp

subi temp, -3

von Daniel B. (dannyboy1994)


Angehängte Dateien:

Lesenswert?

Danke. Nach dem entfernen der oushes funktionieren nun alle zustände, 
und das automatsche abschalten. Sieht die verwendung des ADC für euch in 
Ordnung aus?

Nun muss ich mir überlegen wie ich am besten das lcd ansteuere um mit 
diesen nebentätigkeiten nicht über die 160 takte hinaus zu rutschen. Ich 
denke nicht dass das display sich wärend einer übertragung gerne von 
interrupts ärgern lässt. Priorität hat hier natürlich die Genauigkeit 
der Drehzahl an den Motoren um ein gleichmäßiges ergebniss zu bekommen.

Leider ist der essumformer noch auf dem Postweg und die Treiber A4988 
ebenfalls.

Ich könnte die aktuallisierung bzw das prüfen der Impulse auch in die 
Interrupt Routine packen, allerdings denke ich wird das ganze dann sehr 
ausgebremst und de gefahr interrupts zu verpassen wäre gegeben..


Wie könnte ich die Prüfung am besten in der Art ändern,dass auch bei 
einem verpassten interupt der nächste im puls ausgelöst wird?
Dadurch würde er sie zumindest, wenn auch nicht genau nach timing, 
nachholen...

von my2ct (Gast)


Lesenswert?

Daniel B. schrieb:
> In Arduino habe ich schon so einiges umgesetzt. Allerdings vertraue ich
> der IDE und allem waa im hintergrund abläuft nicht so recht, was
> zeitkritische sachen betrifft.

Dann guck doch in den Quellcode rein - frei nach dem Motto: "Misstrauen 
ist gut, Kontrolle ist besser".

von Falk B. (falk)


Lesenswert?

Daniel B. schrieb:
> Danke. Nach dem entfernen der oushes funktionieren nun alle zustände,
> und das automatsche abschalten. Sieht die verwendung des ADC für euch in
> Ordnung aus?
>
> Nun muss ich mir überlegen wie ich am besten das lcd ansteuere um mit
> diesen nebentätigkeiten nicht über die 160 takte hinaus zu rutschen.

So ein Käse.

> Ich
> denke nicht dass das display sich wärend einer übertragung gerne von
> interrupts ärgern lässt.

Nochmal Käse.

> Ich könnte die aktuallisierung bzw das prüfen der Impulse auch in die
> Interrupt Routine packen, allerdings denke ich wird das ganze dann sehr
> ausgebremst und de gefahr interrupts zu verpassen wäre gegeben..
>
> Wie könnte ich die Prüfung am besten in der Art ändern,dass auch bei
> einem verpassten interupt der nächste im puls ausgelöst wird?
> Dadurch würde er sie zumindest, wenn auch nicht genau nach timing,
> nachholen...

Käse zum 3.

Wirf deinen Mist weg und mach es komplett NEU! Mit einem GESCHEITEN 
Konzept! Dort kommen WIRKLICH nur die zeitkritischen Sachen in eine ISR, 
der Rest läuft zyklisch in der Hauptschleife. Dann kann die 
LCD-Ansteuerung fast beliebig langsam sein.

von MaWin (Gast)


Lesenswert?

Daniel B. schrieb:
> Wie könnte ich die Prüfung am besten in der Art ändern,dass auch bei
> einem verpassten interupt der nächste im puls ausgelöst wird?

Gar nicht.
Hat ein Schrittmotor einen Schritt verpasst, kommt er aus dem Tritt und 
bleibt (Beschleunigungsrampe fehlt) ggf. ganz stehen.

Schreib einfach vernünftigen code, Methode wie oben vorgeschlagen, so 
funktionieren G-Code Router wie Mach3/grbl.

Dein Kindercode funktioniert nie.

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
Noch kein Account? Hier anmelden.