Ik ben bezig met een servosturing. Hiervoor maak ik gebruik van de X, Y, Z pointers.

Het eerste programma dat ik schreef werkte perfect, maar was veel te groot. Nu probeer ik het dus kleiner maar het wil niet echt lukken. Het kan niet met interrupts gezien ik er dan zo een 20 nodig ga hebben uiteindelijk..

De servo gaat heel kort even aan en stopt daarna met reageren. Er komen geen pulsen meer uit de avr.


;// werkend op 8MHz

.include "m8def.inc"

.org 0x0000
	rjmp reset


reset:
	ldi	temp,low(RAMEND)
	out	SPL,temp						; Set stack pointer to last internal RAM location
	ldi	temp,high(RAMEND)
	out	SPH,temp
		
	ldi	temp,0b10010000
	out	UCR,temp						; Rx INT, Rx Enable, Tx Enable
	ldi	temp,(8000000/(16*9600)-1)
	out	UBRRL,temp						; 9600 Baud (8 MHz crystal)
	ldi temp, 0
	out UBRRH, temp
	sei									; Enable global interrupts
					
										;einde uart deel


	;servo vectors definieren
	ldi		r30, 0x90					;Vector Z
	ldi		r31, 0x00


	;registers definieren
	.def	s2ms = 	r17
	.def	sup = 	r18
	.def	srvo = 	r19
	.def	temp1 = r20
	.def	temp2 = r21
	.def	temp3 = r22
	.def	temp = 	r16

	;Poorten instellen
	ldi		temp, 0b11111111			;Alle (beschikbare) poorten als uitgang
	out		DDRB, temp

	ldi		temp, 0b00000000			;poorten laag
	out		PORTB, temp


	;servo's beginstand geven
beginstand:
	inc		sup	
	ldi		temp, 127
	st		Z+, temp
	cpi		sup, 8
	brne	beginstand
	clr		sup

	ldi		r30, 0x90		;Vector Z op 0
	ldi		r31, 0x00

;// EINDE INSTEL GEDEELTE





main:								;alles doen in 18ms totaal


          ldi  R25, $CE
WGLOOP0:  ldi  R24, $E8
WGLOOP1:  dec  R24
          brne WGLOOP1
          dec  R25
          brne WGLOOP0

	ldi		r30, 0x90		;Vector Z op 0
	ldi		r31, 0x00



	clr		s2ms
	clr		srvo
	ldi		temp, 0b11111111			;poorten hoog
	out		PORTB, temp

	rjmp	Servo1



//SERVO'S 2MS UPDATEN

Servo:
	clr		srvo
	rjmp	Servo1

S1:
	cpi		srvo, 7
	breq	servo2ms
	inc		srvo
	lsl		temp1
Servo1:
	ld		temp,Z+			;In temp Servostand laden en servostandplaats 1 verhogen
	cp		temp, s2ms		;Vergelijk of huidige stand gelijk is aan servostand
	brlo	S1			
	sbr		temp1, 1 	
	rjmp	S1



;// 2ms/254 wachten totaal
servo2ms:

	out		PORTB, temp1

	ldi		r30, 0x90		;Vector Z op 0
	ldi		r31, 0x00
	clr		temp1

	inc		s2ms
	cpi		s2ms, 254
	brne	Servo
	rjmp	main


//EINDE SERVO'S 2MS UPDATEN



;// USART DATA ONTVANGEN

Iemand een idee waar het fout gaat? Het gaat dus maar heel even goed, en daarna valt het uit.

Het simuleren gaat echter perfect(haal even de wait loops eruit en verklein een paar getallen).

Je wilt 20 servo's besturen via interrupts, en bewaart de standen in SRAM en telkens updaten?

beginstand:
	inc		sup

sup moet je op 0 zetten voordat je omhoog gaat tellen.
In reset kunnen de registers willekeurige data bevatten.

	clr		sup
beginstand:
	inc		sup

Nu telt ie met zekerheid vanaf 0.

	ldi		r30, 0x90					;Vector Z
	ldi		r31, 0x00

Dit kun je ook zo doen.

	ldi		XL, 0x90					;Vector X
	ldi		XH, 0x00

Z is eigenlijk voor flash, zie SPM. (kan wel op SRAM, alleen ik ondervond een keer problemen.) X en Y (en eventueel W register paar r24/r25.) op SRAM gebruiken.

Zonder inhoudelijk naar je code gekeken te hebben:

Je enabled interrupts, maar hebt nergens interrupt vectors gedefinieerd. Dat is niet handig. Nou zet je (als ik het zo 1-2-3 bekijk) alleen de UART IRQ aan, dus het zou goed moeten gaan zoalng je die niet gebruikt. Blijft een beetje tricky om het zo te doen.

Op 17 februari 2008 00:32:28 schreef RES:
Je wilt 20 servo's besturen via interrupts, en bewaart de standen in SRAM en telkens updaten?

Juist niet via interrupts gezien ik daar geen ruimte voor heb. Wel idd 20 servo standen opslaan in het sram

Hij doet nu:

18ms code uitvoeren, dan 2ms doorlopen tot alle servo's zijn bekeken en dus de juiste tijd de juiste stand hoog.

beginstand:
	inc		sup

sup moet je op 0 zetten voordat je omhoog gaat tellen.
In reset kunnen de registers willekeurige data bevatten.

	clr		sup
beginstand:
	inc		sup

Nu telt ie met zekerheid vanaf 0.

Hmm, ik zat dat idd nog even doen. Opzich loopt hij goed door in de test. Zou idd anders kunnen zijn in de avr door de reset.

	ldi		r30, 0x90					;Vector Z
	ldi		r31, 0x00

Dit kun je ook zo doen.

	ldi		XL, 0x90					;Vector X
	ldi		XH, 0x00

Z is eigenlijk voor flash, zie SPM. (kan wel op SRAM, alleen ik ondervond een keer problemen.) X en Y (en eventueel W register paar r24/r25.) op SRAM gebruiken.

Ah, vandaar, ook even veranderen dus!

Op 17 februari 2008 06:21:51 schreef Marco69:
Zonder inhoudelijk naar je code gekeken te hebben:

Je enabled interrupts, maar hebt nergens interrupt vectors gedefinieerd. Dat is niet handig. Nou zet je (als ik het zo 1-2-3 bekijk) alleen de UART IRQ aan, dus het zou goed moeten gaan zoalng je die niet gebruikt. Blijft een beetje tricky om het zo te doen.

Stukje code van de UART heb ik eruit gesloopt gezien dat verder toch niets doet voor de werking.

[edit]
Ik heb het zojuist aangepast. De code werkt voor ongeveer één seconde goed, je ziet dat er een goed signaal doorheen gaat. Echter valt hij daarna uit.

Marco69:
Zojuist heb ik de uart eruit gehaalt, nu blijft hij het correct doen. Dat was het dus! :)

[edit2]
Helaas, het idee duurt 2ms te lang... :(

2mS te lang? Dan clock je een paar MHz hoger :)

ps. Als je een puls maakt van 2 msec, staan die servo's niet in de middenstand, dan moet je een 1.5msec puls maken. (T=20msec)

Op 17 februari 2008 17:08:57 schreef RES:
ps. Als je een puls maakt van 2 msec, staan die servo's niet in de middenstand, dan moet je een 1.5msec puls maken. (T=20msec)

Weet ik.

Totaal 20ms. 1ms voor de ene kant, 2 voor de andere kant.

Ik wacht in mijn code 18ms en kijk daarna in max. 2ms wanneer welke servo uit moet. Gaat perfect.

Alleen met het nieuwe idee kost dit mij veel teveel clockcycles.

Paar MHz hoger kan niet want hij loopt dan al op 16MHz in die berekening.

Met hexapod loopt ondertussen wel, alleen is de code niet al te netjes.

[Bericht gewijzigd door LED-Maniak op (11%)]

Paar MHz hoger kan niet want hij loopt dan al op 16MHz in die berekening.

Dat stond er niet bij... :)

Je kunt wellicht wel een aantal servo's samen nemen. Als ik het mij goed herinner hebben die dingen een PWM achtige sturing, waarbij de duty cycle de 'stand' aangeeft.

Als je alle servo's nou eens op hetzelfde moment laat beginnen met 'hoog' en in een loopje kijkt welke van de 20 op een gegeven moment naar 'laag' moet? Op 16MHz is die AVR zo snel dat je een paar μS (denk ik) die je te laat zou kunnen zijn niet terug gaat vinden. Dat gaat sneller dan alles achter elkaar. Of heb ik je nou echt verkeerd begrepen?

(overigens: ik gok er zomaar op dat als je die mega echt op 5V voedt, dat die ook nog wel iets harder loopt dan 16MHz. Wel buiten spec en ik weet niet hoe belangrijk bedrijfszekerheid van je bouwproject is...)

Dat doe ik op het moment idd ook:

-18ms pauze alles laag.
- alles hoog
- 2ms loop, tussen die loop kijken wanneer welke servo zijn tijd heeft bereikt
- alles uiteindelijk laag

[Bericht gewijzigd door Henry S. op (71%)]

Dan heb ik je probleem verkeerd begrepen... Sorry voor de non-oplossing :)

Het kortste is denk ik, een timer1-interrupt op de achtergrond laten draaien en twee OCR's (A en B) gebruiken, dan heb je 18 geheugenplekken nodig (20-2, want telkens 2 in de OCR, dan op naar de volgende) Weet niet hoeveel resolutie je wilt, maar 6-bit is al heel veel (1msec/64=15.6usec stapjes) Dan zou je die 6 bits over 6*18/8 => 14 registers kunnen verdelen (iewat lastig) (32 registers in de AVR)
(of simpel via SRAM in de bytes) En bij 5-bits resolutie (32 stapjes van 31 usec) scheelt het nog eens 2 registers.(12 nodig)

Op 17 februari 2008 22:56:13 schreef RES:
Het kortste is denk ik, een timer1-interrupt op de achtergrond laten draaien en twee OCR's (A en B) gebruiken, dan heb je 18 geheugenplekken nodig (20-2, want telkens 2 in de OCR, dan op naar de volgende) Weet niet hoeveel resolutie je wilt, maar 6-bit is al heel veel (1msec/64=15.6usec stapjes) Dan zou je die 6 bits over 6*18/8 => 14 registers kunnen verdelen (iewat lastig) (32 registers in de AVR)
(of simpel via SRAM in de bytes) En bij 5-bits resolutie (32 stapjes van 31 usec) scheelt het nog eens 2 registers.(12 nodig)

Hm, ik zie dat toch niet helemaal voor me hoe je dat bedoelt.

Die eerste timer timed de 20ms? En de OCR's de 2ms?

Resolutie kan idd nog wel flink omlaag.

Ik zit nu met dit hersenspinsel:

- 14ms wachten
- Poort A hoog alle 8 checken, duur van 2ms alles laag.
- Poort B hoog alle 8 checken, duur van 2ms alles laag.
- Poort C hoog alle 8 checken, duur van 2ms alles laag.
- terug naar 14ms wachttijd

14 + 2*3 = 20ms

Dus telkens na elkaar updaten. Dan komen ze allemaal aan de 20ms en allemaal aan de 2ms, alleen dan na elkaar ipv alles tegelijk.

Controller heeft dan een zee van tijd over om andere dingen te doen.

Je laat een timer1 rondjes draaien van 20 msec via een interrupt.(in de interrupt timer1 counter resetten) (T=20msec -> f=50Hz) en elke 20 msec de timer1 counter resetten. (bij een 8 MHz clock krijg je bijv. 20msec/(1024/8Mhz)=156 timer ticks. 156 past in een byte dus geen 16-bits getallen nodig (simpeler met cp/cpi etc.), ook meteen de max. resolutie. (eventueel delen /2 naar 78 of 39 bits resolutie.)

Die OCR's vergeten (is voor interne PWM, jij meer dan 3 PWM signalen nodig), en gewoon 20x vergelijken binnen die 20 msec (interrupt), en die getallen aanpassen(=standen servo's), dus tussen 0-155 (156) Je hebt max. 18msec (20msec-2msec) de tijd voor maximale uitslag servo's, om die 20 geheugenplekken te updaten.

Als je de resolutie deelt door 4 dan 20msec/39=0.5 msec stapjes. (is al een goed soepele beweging, maar 78 stapjes en 156 (dus res/2) merk je niet meer.) (servo's hebben minimale pulsbreedteverandering nodig = motorpooltjes, weet niet hoeveel.)

En alle pinnen (1=puls, 0=pause) updaten nadat je de SRAM locatie's hebt beschreven. (Elke 20 msec veranderen de servo's van standen.)

Nou, het is gelukt hoor! :)

Ik heb timer 1 op 14ms gezet voor een overflow.
Dan gaat hij 3x 2ms alle servo's checken = 20ms totaal.

Dan heb ik dus altijd 14ms over om andere handelingen te verrichten. Daar zou ik zelfs nog een paar set's van servo's in kwijt kunnen.

Maar, uiteraard is er nog iets wat niet klopt, en dat is:
Ik ga van 0~255, dat is in weze dus:
0 = 0ms aan
127 = helft van 2ms dus 1ms aan (helemaal links)
255 = 2ms aan (helemaal rechts)

En dus niet het midden zoals 127 eigenlijk zou moeten zijn. Dan zou ik dus eigenlijk een waarde tussen 0 en 127 moeten sturen naar avr en hier 127 bij optellen..

Ik heb op internet wat vergeleken, maar volgensmij doet iedereen het zo(van 0~255)?? Beetje raar eigenlijk.