Sida 1 av 1

PWM med Pic assembler

Postat: 15 oktober 2007, 16:52:15
av PHermansson
Det här är något av en Sisyfossten för mig. Har bankat i huvudet i bordet många gånger under mina försök att skapa en väl fungerande mjukvaruPWM i assembler.
Har tagit tag i det ytterligare en gång idag, och resultatet blir en hysteriskt blinkande epilepsiframkallande RGB-diod. Hårdvaran är en 12F675 med intern oscillator. På tre av utgångarna finns anslutningarna till transistorer kopplade till en RGB-diod.
Här är koden:

Kod: Markera allt

	list      p=12f675           ; list directive to define processor
	#include <p12f675.inc>        ; processor specific variable definitions

	errorlevel  -302              ; suppress message 302 from list file

	__CONFIG   _CP_OFF & _CPD_OFF & _BODEN_OFF & _MCLRE_ON & _WDT_OFF & _PWRTE_ON & _INTRC_OSC_NOCLKOUT  

INT_VAR		UDATA_SHR	0x20   
w_temp		RES     1		; variable used for context saving 
status_temp	RES     1		; variable used for context saving
d1           RES 	1
d2           RES 	1
counter		RES 	1	;Main counter
led1		RES 	1	;Led counters
led2		RES		1
led3		RES		1

    #define     green      	GPIO,0
    #define     blue      	GPIO,1
    #define     red      	GPIO,2

;**********************************************************************
RESET_VECTOR	CODE	0x000		; processor reset vector
		goto    main              ; go to beginning of program


INT_VECTOR	CODE	0x004		; interrupt vector location
		movwf   w_temp            ; save off current W register contents
		movf	STATUS,w          ; move status register into W register
		movwf	status_temp       ; save off contents of STATUS register


; isr code can go here or be located as a call subroutine elsewhere
		decfsz	led1,1	;Decrease led counters
		goto	dec2
		bcf		red		;Shut off led if zero
dec2	
		decfsz	led2,1
		goto 	dec3
		bcf		green
dec3
		decfsz	led3,1
		goto	decC
		bcf		blue
		
decC
		decfsz	counter,1		;Decrease maincounter
		goto	contRGB			;Jump if not zero
		call	setRGB		;Reset values if zero

contRGB
		bcf		INTCON, T0IF
		movf    status_temp,w     ; retrieve copy of STATUS register
		movwf	STATUS            ; restore pre-isr STATUS register contents
		swapf   w_temp,f
		swapf   w_temp,w          ; restore pre-isr W register contents
		retfie                    ; return from interrupt


; these first 4 instructions are not required if the internal oscillator is not used
MAIN    CODE
main
		;call    0x3FF             ; retrieve factory calibration value
		;bsf     STATUS,RP0        ; set file register bank to 1 
		;movwf   OSCCAL            ; update register with factory cal value 
		;bcf     STATUS,RP0        ; set file register bank to 0

		
; remaining code goes here
		;Setup port
		bcf		STATUS, RP0
		clrf	GPIO
		movlw	07h
		movwf	CMCON
		bsf		STATUS,RP0
		clrf 	ANSEL
		movlw	b'00011000'
		movwf	TRISIO
		bcf		STATUS,RP0

		;Enable Tmr0
		clrf	TMR0
		bsf		STATUS,RP0
		movlw	b'11000000'	;
		movwf	OPTION_REG
		bcf		STATUS,RP0

		;Enable Tmr0 interrupt
		BSF		INTCON, T0IE
		BSF		INTCON, GIE
		;Set up RGB values
		call 	setRGB

MainLoop
		goto	MainLoop

setRGB
		;Setup RGB-values, preload Tmr0
		;Set interval to 100uS
		;Internal oscillator, 4MHz. Tcyc=0,00000025s*4=0,000001s 
		
		movlw	d'20'
		movwf	TMR0
		movlw	d'100'
		movwf	counter
		movlw	d'40'
		movwf	led1
		movlw	d'40'
		movwf	led2
		movlw	d'40'
		movwf	led3
		bsf		red
		bsf		green
		bsf		blue
		return

; initialize eeprom locations

EE		CODE	0x2100
		DE	0x00, 0x01, 0x02, 0x03



		END                       ; directive 'end of program'

Edit: Frågan är alltså varför dioden blinkar istället för att sänka ljusstyrkan?

Postat: 15 oktober 2007, 18:54:16
av sodjan
Vad har du gjort för att felsöka ?
Har du kört den med StopWatch i MPSIM ?

Det är så dåligt kommenterat så någon annan får läsa själva koden...

Postat: 15 oktober 2007, 19:20:10
av PHermansson
Och jag som brukar va noga med kommentarer :)
Har kört en del i PIC Simulator och tror jag hittat problemet. Intervallet för TMR0 är rätt, 100uS. Varje gång räknaren slår över ges ett interrupt och led-variablerna minskas med ett. Problemet är när en led-räknare blivit noll, när nästa interrupt kommer är den fortfarande noll och minskas då med ett, resultatet blir h'FE'. Får klura vidare, återkommer förhoppningsvis med en bättre fungerande mer kommenterad version snart.

Postat: 15 oktober 2007, 20:03:49
av sodjan
> decfsz led1,1

decfsz led1, f, så blir det tydligare.
Samma på de andra platserna...

Men, det ändrar inget i funktionen. :-)

Du får singel-steppa och se var det går snett...

> när nästa interrupt kommer är den fortfarande noll och minskas då med ett, resultatet blir h'FE'.

Ska inte spela någon roll, du har ju redan släckt dioden i det föregående varvet.

Postat: 15 oktober 2007, 20:41:04
av PHermansson
Det har du rätt i!
Har kommit en sak iaf... Hade prescalern kopplad till Tmr0 och satt till 1:2.
Om man sedan kommenterar bort OSCCAL-avsnittet funkar koden bra i simulatorn med inte i verkligheten.
Nu verkar allt fungera, slipper få epilepsi i kväll :)

Postat: 15 oktober 2007, 20:44:35
av PHermansson

Kod: Markera allt

	list      p=12f675           ; list directive to define processor
	#include <p12f675.inc>        ; processor specific variable definitions

	errorlevel  -302              ; suppress message 302 from list file

	__CONFIG   _CP_OFF & _CPD_OFF & _BODEN_OFF & _MCLRE_ON & _WDT_OFF & _PWRTE_ON & _INTRC_OSC_NOCLKOUT  

INT_VAR		UDATA_SHR	0x20   
w_temp		RES     1		; variable used for context saving 
status_temp	RES     1		; variable used for context saving
counter		RES 	1	;Main counter
led1		RES 	1	;Led counters
led2		RES		1
led3		RES		1

    #define     green      	GPIO,0	;Led output pins
    #define     blue      	GPIO,1
    #define     red      	GPIO,2

;**********************************************************************
RESET_VECTOR	CODE	0x000		; processor reset vector
		goto    main              ; go to beginning of program


INT_VECTOR	CODE	0x004		; interrupt vector location
		movwf   w_temp            ; save off current W register contents
		movf	STATUS,w          ; move status register into W register
		movwf	status_temp       ; save off contents of STATUS register

		;Go directly to dec2 if led1 is zero		
		decfsz	led1,1	;Decrease led counter 1
		goto	dec2	;Jump if not zero
		bcf		red		;Shut off led if zero
		incf	led1
dec2	
		decfsz	led2,1	;Same as above
		goto 	dec3
		bcf		green
		incf	led2
dec3
		decfsz	led3,1	;Same as above
		goto	decC
		bcf		blue
		incf	led3
		
decC
		decfsz	counter,1		;Decrease maincounter
		goto	contRGB			;Jump if not zero
		call	setRGB			;Reset values if zero

contRGB
		bcf		INTCON, T0IF
		movf    status_temp,w     ; retrieve copy of STATUS register
		movwf	STATUS           ; restore pre-isr STATUS register contents
		swapf   w_temp,f
		swapf   w_temp,w          ; restore pre-isr W register contents
		retfie                    ; return from interrupt


; these first 4 instructions are not required if the internal oscillator is not used
MAIN    CODE
main
		call    0x3FF             ; retrieve factory calibration value
		bsf     STATUS,RP0        ; set file register bank to 1 
		movwf   OSCCAL            ; update register with factory cal value 
		bcf     STATUS,RP0        ; set file register bank to 0

		
; remaining code goes here
		;Setup port
		bcf		STATUS, RP0
		clrf	GPIO
		movlw	07h
		movwf	CMCON		;Comparators off
		bsf		STATUS,RP0
		clrf 	ANSEL		;No AD
		movlw	b'00011000'	;0:2=outputs, 4:5 inputs
		movwf	TRISIO
		bcf		STATUS,RP0

		;Enable Tmr0
		clrf	TMR0
		bsf		STATUS,RP0
		movlw	b'11001000'	; X,X,internal clock, low-high, prescaler 1:2
		movwf	OPTION_REG
		bcf		STATUS,RP0

		;Enable Tmr0, general interrupt
		BSF		INTCON, T0IE
		BSF		INTCON, GIE
		;Set up RGB values
		call 	setRGB

MainLoop
		; Just hang around and wait for an interrupt

		goto	MainLoop

setRGB
		;Setup RGB-values, preload Tmr0
		;Set interval to 100uS
		;Internal oscillator, 4MHz. Tcyc=0,00000025s*4=0,000001s 
		
		movlw	d'20'	;Tmr0=20 gives 100uS between int's
		movwf	TMR0
		movlw	d'100'	;Main PWM counter
		movwf	counter
		movlw	d'90'	;Led counters, PWM on/off is N%
		movwf	led1
		movlw	d'10'
		movwf	led2
		movlw	d'10'
		movwf	led3
		bsf		red		;All leds on
		bsf		green
		bsf		blue
		return

; initialize eeprom locations

EE		CODE	0x2100
		DE	0x00, 0x01, 0x02, 0x03



		END                       ; directive 'end of program'


Postat: 15 oktober 2007, 22:41:58
av sodjan
Bara så att jag förstår här...
Ska vi leta fel i den senaste postade koden ??
I så fall vilket fel ?

Postat: 15 oktober 2007, 23:06:01
av PHermansson
:) Kanske skulle skrivit vad jag menade oxå. Den sistnämnda koden fungerar, ville bara avsluta frågeställningen med lösningen på problemet.

Postat: 15 oktober 2007, 23:15:23
av sodjan
OK, då tar vi ett par andra småsaker... :-)

- Använd BANKSEL istället för att fippla med RP0/RP1 själv.
- Använd W/F istället för 1/0 som "destination" i instruktion.

Vilket syfte har "incf led1/2/3" ?

Postat: 15 oktober 2007, 23:37:38
av PHermansson
Ok ska fixa punkt 1&2, lika bra att det blir helt rätt.
incf har som funktion att inte låta registren bli mindre än noll och bli FE som nämndes ovan, men som du påpekade har detta ingen betydelse. Ska ta bort de raderna.