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).
RES
RES
Je wilt 20 servo's besturen via interrupts, en bewaart de standen in SRAM en telkens updaten?
beginstand:
inc supsup moet je op 0 zetten voordat je omhoog gaat tellen.
In reset kunnen de registers willekeurige data bevatten.
clr sup
beginstand:
inc supNu telt ie met zekerheid vanaf 0.
ldi r30, 0x90 ;Vector Z
ldi r31, 0x00Dit kun je ook zo doen.
ldi XL, 0x90 ;Vector X
ldi XH, 0x00Z 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 supsup moet je op 0 zetten voordat je omhoog gaat tellen.
In reset kunnen de registers willekeurige data bevatten.clr sup beginstand: inc supNu 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, 0x00Dit kun je ook zo doen.
ldi XL, 0x90 ;Vector X ldi XH, 0x00Z 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...
RES
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)
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%)]
RES
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)
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.
RES
RES
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.