Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien

PWM met pic in ASM

Pagina: 1
Acties:
  • 118 views sinds 30-01-2008
  • Reageer

  • bazzzzzz
  • Registratie: Januari 2007
  • Laatst online: 21-11 10:00
Heeeeeey,

Met de pwm code uit dit topic:
http://gathering.tweakers.net/forum/list_messages/1089031/0

Ben ik al een aardig stuk opgeschoten met het begrijpen van pwm maar kheb nog een paar vragen. Om het moodlight/ambilight topic niet al te veel te vervuilen ff een nieuw topic.

Voor de duidelijkheid de code nog ff
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
; De gebruikte macro's:

LED_AAN    macro
    BSF    PORTB,0    ;LED_ROOD
    BSF    PORTB,1    ;LED_GROEN
    BSF    PORTB,2    ;LED_BLAUW
    endm

LED_ROOD_UIT macro
    BCF    PORTB,0    
    ENDM

LED_GROEN_UIT macro
    BCF    PORTB,1    
    ENDM

LED_BLAUW_UIT macro
    BCF    PORTB,2 
    ENDM

; De gebruikte variabelen:
    cblock    0x020    ; vrije plaats voor variabelen vanaf 20
    ROOD_GEWENST    ; de gewenste waarde voor rood    |(= duty-cycle in procent * 2,55)
    GROEN_GEWENST    ; de gewenste waarde voor groen    |(kan van 0 tot 255 zijn)
    BLAUW_GEWENST    ; de gewenste waarde voor blauw    |(met stappen van 1)
    TELLER    ; de tellerwaarde waarmee bovenstaande 3 vergeleken worden
    w_temp          ; backup voor W, nodig in interrupt
    status_temp      ; backup voor status, nodig in interrupt
    endc    ; einde reeks variabelen

;____START_PROGRAMMA____________________________
    ORG    0X000    ; hier start de PIC na een reset zijn programma
    NOP            ; soms is het nodig dat hier een NOP (= niets doen) staat, voor debugtoestellen    
    GOTO    INIT    ; ga naar waar je programma begint, want op 0x004 staat de interrupt
 
;____INTERRUPT_CODE_____________________________
    ORG    0X004    ; als er een interrupt is, gaat hij naar hier
    movwf   w_temp    ; na de interrupt werkt het programma verder alsof er niets is gebeurd
    movf    STATUS,w    ; na de interrupt werkt het programma verder alsof er niets is gebeurd
    movwf    status_temp    ; na de interrupt werkt het programma verder alsof er niets is gebeurd

; zorgen dat de volgende keer weer een interrupt komt.
    movlw    .255-.39    ; na 39 instructies terug interrupt.
    movwf    TMR0
    BCF        INTCON,T0IF    ; de interrupt vlag van timerO clearen
    BSF        INTCON,GIE    ; de interrupt terug inschakelen

;hieronder de code om de PWM te doen: RGB uitschakelen indien gewenst, en na 255 keer: PWM_KLAAR
    MOVF    TELLER,W    ; de tellerwaarde in W zetten (om straks te vergelijken)
    SUBWF    ROOD_GEWENST,W    ; ROOD_GEWENST - TELLER (gewenste waarde bereikt,nul, dan led uit)
    BTFSS    STATUS,C    ; negatief, dan is carry 0 (zie datasheet bij subwf), dan volgende regel doen
    LED_ROOD_UIT    ; doe macro om led af te leggen.
    MOVF    TELLER,W    ; zelfde als bij rood
    SUBWF    GROEN_GEWENST,W
    BTFSS    STATUS,C
    LED_GROEN_UIT 
    MOVF    TELLER,W
    SUBWF    BLAUW_GEWENST,W
    BTFSS    STATUS,C
    LED_BLAUW_UIT 

    INCF    TELLER,f    ; verhoog teller met 1, als teller 0 wordt, sla volgende over
    BTFSC    STATUS,Z    ; als TELLER nul is, doe volgende regel
    goto    PWM_KLAAR    ; volledige PWM cyclus gedaan, afhandeling doen.

    movf    status_temp,w    ; na de interrupt werkt het programma verder alsof er niets is gebeurd
    movwf    STATUS    ; na de interrupt werkt het programma verder alsof er niets is gebeurd
    swapf   w_temp,f    ; na de interrupt werkt het programma verder alsof er niets is gebeurd
    swapf   w_temp,w    ; na de interrupt werkt het programma verder alsof er niets is gebeurd
    retfie                    ; return from interrupt, keer terug waarvan je kwam.

INIT    ; hier doe ik enkele instellingen, die bij het opstarten moeten gebeuren.
    BANKSEL    TRISA    ;trisa zit in bank1
    movlw    b'11111111'    ; op poort a allemaal ingangen
    movwf    TRISA
    movlw    b'00000000'    ; op poort b allemaal uitgangen
    movwf    TRISB

    BSF    OPTION_REG,PSA    ; geen prescaler voor timer0
    BCF    OPTION_REG,T0CS    ; stel timer0 in als timer (+1 per instructie)
    MOVLW    b'10100000'    ; Timer0 interrupt aanleggen.
    movwf    INTCON

    BANKSEL    TMR0    ;bank0
    CLRF    TMR0
    MOVLW    B'00000111'    ;Disable Comparator module's
    MOVWF    CMCON

    CLRF    PORTB    ; alle uitgangen uit.
    
;____START_CODE_________________________________
MAIN    
    movlw   D'10'
    movwf   ROOD_GEWENST

    movlw   D'255'
    movwf   GROEN_GEWENST

    movlw   D'255'
    movwf   BLAUW_GEWENST

    GOTO    MAIN

PWM_KLAAR
    nop    
    LED_AAN
    RETURN

END
Let op dit is een iets wat aangepaste versie!

Wat ik niet snap is. Waarom er macro's gebruikt worden om elke kleur apart uit te zetten. Bijvoorbeeld: "LED_ROOD_UIT macro
BCF PORTB,0
ENDM"
Als je nu gewoon in de interupt bcf PORTB,0 zegt dan bespaar je toch weer 2 commando's?
En waarom is PWM klaar een subroutine? Beetje onhandig subroutines en macro's door mekaar gebruiken. Of is hier speciaal voor gekozen?

Verder over de interrupt routine. Hier wordt gekozen voor wel/geen prescaler. Maar wat heb je eigenlijk aan een prescaler? Deze interupt moet toch juist gewoon zo snel mogelijk afgehandeld zijn?
code:
1
2
3
4
5
6
7
8
9
    BSF    OPTION_REG,PSA    ; geen prescaler voor timer0
    BCF    OPTION_REG,T0CS    ; stel timer0 in als timer (+1 per instructie)
    MOVLW    b'10100000'    ; Timer0 interrupt aanleggen.
    movwf    INTCON

    BANKSEL    TMR0    ;bank0
    CLRF    TMR0
    MOVLW    B'00000111'    ;Disable Comparator module's
    MOVWF    CMCON


En over de variabele TELLER die krijgt nergens de waarde 255 maar toch heeft hij die waarde? En het nut van het STATUS register ontgaat mij ook een beetje. Het is toch eigenlijk gewoon overbodig om ook daarvan de data te backuppen en terug te zetten? De waarde in het w register daarentegen zie ik wel het nut van in.

Dan nu het tijd kritische gedeelte. Zoals ik het zie moet je ervoor zorgen zo min mogelijk commando's in de interrupt te zetten.
Waarom is er eigenljik elke 39 instructies een interrupt? Hiervoor zou je toch ook een kleiner of groter getal kunnen nemen afhankelijk van de pwm snelheid die je wil hebben?

Verder snap ik deze notatie met een punt ook niet:
movlw .255-.39 ; na 39 instructies terug interrupt.

is dit hetzelfde als movlw D"216"?

Verder over het faden wat is het makkelijkst? De gewenste waarde voor rood, groen en blauw eerst op nul zetten en dan eerst rood vol laten lopen. Dan groen laten vollopen. Dan rood weer laten leeglopen. Dan blauw laten vollopen. Groen laten leeglopen. Rood laten vollopen. Dan heb ik alle kleurencombinaties gehad lijkt mij. Maar waar zal ik wit tussen gooien?

Erg veel vragen maar er zijn vast wel mensen die op een paar het antwoord weten:P

grtz Bas

  • Zjosh
  • Registratie: November 2004
  • Laatst online: 20-11 12:58
Ik denk dat die macro's gewoon op de plek worden gezet van het aanroepen van de macro. Het zijn geen functies volgens mij.

Edit, Status register en W register moetje altijd backuppen. Als je net bezig bent met het testen of een bepaald bit in je status register hoog is, en je krijgt een interupt waar dat in verandert wordt heb je dus een fout. Als je niet test op dingen in het status register zou je het weg kunnen laten, maar ik zou het zelf zeker WEL doen, kan je een hoop gekl**t schelen.

[ Voor 60% gewijzigd door Zjosh op 20-02-2007 17:44 ]


Verwijderd

Hierboven staat al een mooie uitleg van wat vragen.. Macro's gebruik je om code leesbaarder te maken voor mensen die het programma niet geschreven hebben, in dit geval mss overbodig maar je kan al snel op een stuk code lopen waarvan je bij god niet weet wat het moet doen.

Prescalers dienen om je TIMER aan te passen, dwz de tijd waarop de timer 1 "tick" krijgt, bv prescaler 0, elke 4µs gaat de timer met 1 verhogen, prescaler 2, elke 8µs, prescaler 4, elke 16µs enz enz.
Dit heeft dus NIETS te maken met de snelheid waarmee je interrupt uitgevoerd word, enkel en alleen het interval waarmee je interrupt AANGEROEPEN word.

Dat van die teller kan ik ook ff niet goed aan uit, zie niet direct een duidelijke waarde die erin gestoken wordt. Mss gaan ze van de standaardwaarde van een register uit (is dat bij een pic mss 0xFF bij reset? no idea) in elk geval geen mooie praktijk..

De ".255" of ".39" of whatever notatie bepaalt dat je een decimaal getal bedoelt, en geen hexadecimaal. Net zoals je bv 0xFF zou schrijven, zodat je compiler weet waarover je het hebt.

  • Zjosh
  • Registratie: November 2004
  • Laatst online: 20-11 12:58
Die teller wordt volgens mij niet geset, omdat na 1 cyclus door de pwm deze teller op de goede waarde staat. Hij overflowt vanzelf, en dan gaat alles gewoon normaal. Ik vind de pwm manier die ze hier gebruiken alleen een beetje appart, ik gebruikte altijd DECFSZ of DECFSS, misschien eens goed in de instructies datasheets kijken.. ik denk dat je 1 instructie er uit kan optimalisteren.

  • bazzzzzz
  • Registratie: Januari 2007
  • Laatst online: 21-11 10:00
de teller begint inderdaad gewoon bij 0. Enne decfsz is niet nodig omdat hier " INCF TELLER,f "gebruikt wordt. Hoe zouw ik de prescaler anders in kunnen stellen? niet dat het nu nodig is...

En heeft nog iemand wat uitleg over de timing?

  • Zjosh
  • Registratie: November 2004
  • Laatst online: 20-11 12:58
Het gaat mij er juist om dat je door gebruik te maken van DECFSZ je een efficienter programma kan schrijven. Je zet namelijk 3keer een waarde in w per interupt, dat is het voordeel van asm, je kan alles heel optimaal maken. Als je optimalisaties niet zo belangrijk vind, moet je gewoon lekker in c gaan programmeren, ik doe het zelf ook. Je hebt zelf een stuk minder hersen kraken, en gewoon sneller wat voormekaar.

Verwijderd

Heb je zo ook geen incfsz? kan je in je interrupt ook al twee regels vervangen door 1.

I agree met het bovenstaande trouwens, assembler programmeren doe je om iets zo efficient mogelijk te maken (of om perfect te weten wat je nu eigenlijk aan het doen bent)

  • bazzzzzz
  • Registratie: Januari 2007
  • Laatst online: 21-11 10:00
jep incfsz bestaat ook gewoon. En idd het kan nog wat compacter maar dat verander ik gaande weg wel. Eerst zorgen dat het lekker draait zoals ik het wil en begrijp en dan het wat efficienter laten draaien:P

Verwijderd

Das uiteindelijk ook de bedoeling.
Probleem is, als je een 700 tal regels ASM code hebt, je soms niet veel zin hebt om nog te gaan filteren :+

  • jerbro
  • Registratie: September 2001
  • Niet online
Er wordt elke 39 instructies een interrupt aangeroepen, omdat de code gemaakt is om een PWM frequentie van ongeveer 100 Hz te krijgen.
Zie ook de post van naftebakje in het topic waar de code vandaan komt.
naftebakje schreef op donderdag 24 november 2005 @ 17:34:
Ik ben trouwens tot de conclusie gekomen dat om ongeveer op 100Hz aan te sturen, ik om de 10.000 instructie's een pwm cycle moet hebben gedaan (1.000.000 instructies/sec). Een resolutie van 255 wil zeggen 255 keer checken of de led's nog niet uit moeten, dus kom ik uit dat er 39 instructies tijd is om 1) mijn led's aan te sturen (gewenste met tellerwaarde vergelijken, eventueel uitschakelen) en 2) de rest van het programma uit te voeren. Dan heb ik (door afronding) na 255 keer geteld te hebben 55 instructies tijd om alles af te handelen (de gewenste waarden aanpassen, eventueel faden,...) en daarna een nieuwe pwm cyclus te starten, zo stuur ik mijn ledjes netjes op 100Hz aan.

Dat moet zeker lukken, doordat ik een interrupt gebruik moet ik in mijn "gewone" programma geen rekening houden met de PWM, alleen dat de uitvoersnelheid wat trager is (19 instructies in de interrupt, nog 20 over voor het gewone programma, dus een halvering van de snelheid). Dat is nog ruim voldoende om een babbeltje te doen met een PC (via de UART en RS232) en om een programma af te lopen.
Je zult dus die 39 ook nog kunnen veranderen, maar zeker niet kleiner dan 19, omdat anders de interruptlus niet eens geheel uitgevoerd kan worden voor de volgende interrupt weer komt.
Die 39 zul je wel groter kunnen maken, maar ook dan moet je niet te ver gaan, want dan wordt de PWM frequentie weer lager waardoor je de LED kunt zien knipperen.

De prescaler zou je anders in kunnen stellen door de bit PSA in het option register uit te zetten, en de gewenste waarde met van de prescaler met PS0, PS1, en PS2 in te stellen.

  • bazzzzzz
  • Registratie: Januari 2007
  • Laatst online: 21-11 10:00
hier zal ik eens mee gaan spelen :). Maar nu het volgende probleem. Hoe gebruik ik een schakelaar. Stel ik wil als ik S1 omzet alleen rood hebben. Hoe voorkom ik dan dat die interupt telkens langs komt? En waar moet ik mijn btfsc in gooien? In de intterupt kan niet dan gebeuren er rare dingen. Dus moet ik die gewoon elke keer tussen mijn normale code gooien? Lijkt mij niet erg efficient:P

  • naftebakje
  • Registratie: Februari 2002
  • Laatst online: 08:44
Dan moet je gewoon de gewenste waarde's voor groen en blauw op 0 zetten, en die voor rood op maximum, als S hoog wordt.
Dat de interrupt blijft lopen is de bedoeling, je normale code stuurt enkel de gewenste waarden aan, dat omzetten naar PWM gebeurt automagisch met de interrupts.

Teller blijft overigens gewoon doorlopen, na 255 is er een overflow en wordt teller weer 0 (tis 8-bits). Het zou idioot zijn om zelf em op 0 te gaan zetten als het vanzelf al gebeurt hé.
Verder is de code in elkaar geflansd om het principe duidelijk te maken, dus macro leek me handig om het zo begrijpelijk mogelijk te houden én om de mogelijkheden van de compiler te tonen (als ik het me nog goed herinner).

Om nog ff die prescaler te verduidelijken: als je bijvoorbeeld een LCD schermpje aanstuurt, en dat elke seconde wil updaten, zal je enorme vertragingen in moeten gaan bouwen, waar alles op zit te wachten. Timertje maken met de prescaler zo groot mogelijk (gaat dacht ik tot 128) en het loopt al heel wat trager.

[ Voor 18% gewijzigd door naftebakje op 21-02-2007 22:14 ]

Als de boer zijn koeien kust, zijn ze jarig wees gerust. Varkens op een landingsbaan, leiden nooit een lang bestaan. Als de boer zich met stront wast, zijn zijn hersens aangetast. Als het hooi is in de schuur, zit het wijf bij den gebuur.


  • bazzzzzz
  • Registratie: Januari 2007
  • Laatst online: 21-11 10:00
de macro's heb je denk ik gebruikt omdat je 2 blauwe leds had;) dan kan je met een commando gelijke beide aanzetten.

Mar ik heb nu al een heel stuk code en om elke keer de btfss erin te zetten leek mij een beetje omslagtig. Zeker omdat ik meerdere schakelaars eraan wil gaan hangen. En later met een A/D converter er potmeters aanhangen. In de interrupt werkt het niet dan blijft de pic hangen. Telkens controleren of de schakelaar ingeschakeld staat gaat wel gewoon goed.

En inderdaad met jou code wordt het princiepe mooi duidelijk, tis in ieder geval een goed begin om mee te gaan expirimenteren :D
Pagina: 1