SparkFun Forums 

Where electronics enthusiasts find answers.

Have questions about a SparkFun product or board? This is the place to be.
By Oznog
#4855
Naftie wrote:Well, I certainly need the PIC there, it also needs to send out and receive a 22kHz tone on the output for communication with the DUT. If it doensn't work good enough, I'll use a low pass on the PWM output, 0-5V to control a specific IC (if not too expensive).
Well keep in mind you have 2 PWM outputs but both their periods are tied to TMR2 which limits your options.

Oh yeah, you may want to look carefully at how much noise the buck converter makes on the power supply with these 1 amp current switching at 8KHz. You may want an LC filter on the input rather than just a cap.

In fact, I would question whether the LC filter on the output is useful. The buck converter is itself an LC filter so it's kind of doubling up. Wouldn't just using larger values for L2/C8 provide additional smoothing better than adding additional L & C components? The real problem here is the delay problems if you're trying to sense the voltage at "Output" causing oscillation.
By Naftie
#4885
It works :!:
Today the emulator from microchip came in (ICE 2000), that's really Xtremely impoving debugging.

Now I have with 8kHz PWM, from 0 to 25.5V and with the LCLCfilter shown in the scheme the following results:
  • wanted output = 13V (about halfway the range, 0.1V steps)
    going from current = 0.45A to 0A
    longest stabilizing time = 500ms
    upwards peak = 2.5V
    (PIC oscillator 8MHz internally)
With lower currents ist a bit better (peak lowers much, but time doesn't go below 350ms), and going from 0 to some current stays at around 450ms.
And that all superstable 8) .

The trick was that I corrigate big changes at max speed, and when the output comes nearer than 2V to the desired value, I use steps of 1.
This step of 1 is delayed, withouth delaying the response to big changes. Therefore when it changes a step of one, the next 10 times I don't change if i still are no more than 2V away of the desired value. If the difference is greater, it will just change the value.

@spcutler: I'm really sorry for hijacking your topic, but now you know it's possible. If you want the sourcecode of the supply regulator, just ask. The comments are mainly in dutch (I'm a Belgian), and it's written in assembly. But It shouldn't be too hard to understand.
By spcutler
#4893
@spcutler: I'm really sorry for hijacking your topic, but now you know it's possible.
No problem at all! In fact, I couldn't have hoped for a more useful discussion. I've just been sitting back and trying to absorb it all.

I would love to take a look at the source, even in Dutch. I'll send you a PM with my email address.

Much thanks go to you, Oznog, and SOI_Sentinel for an extremely informative discussion.

-Scott
By Naftie
#5025
Here you go, this is the code for my switching supply. I've made also a change to the hardware, a resistor of 10k with a condensator of 100pF in parallel is now used instead of the resistor of 680 ohms. That seems to work good enough.
Code: Select all
;PIC 16F88 at 8MHz internal oscillator

;this is a macro:
t0p2	macro	;timer 0 instellen op prescaler 4
	bcf	OPTION_REG,PS2
	bcf	OPTION_REG,PS1
	bcf	OPTION_REG,PS0
	endm



main
	movlw	.130		; 13 volts is the wanted value, 0-25.5V makes it this easy
	movwf	U
mainlus
;put in whateaver you want to add to the regulator, for example I²C to receive wanted value
	call	regellus
	goto	mainlus


;This is the regulatig loop (= regellus) to measure the output, make an average of the 
;measurements, and change the PWM according to the difference.
regellus
	t0p2	; this is a macro, to set prescaler of timer0 to 2
	movfw	U
	movwf	PWMv	;set wanted value in PWMv
	movwf	PWMverschil	;To use it, I put wanted value in PWMdifference(=verschil)

; Here the average is made out of 4 measurements, and I also measure I (current).
foutgemiddelde
	call	ad		; I measure
	movwf	Igemeten	; measured value in Imeasured

	bcf		ADCON0,5		; U measure
	bsf		ADCON0,4		; U measure
	bsf		ADCON0,3		; U measure
	t0p2
	movlw	0FFh-.10	; 10*4 instructies wait ==> 2Oµs
	movwf	TMR0
	bcf		INTCON,TMR0IF	; interrupt clearen
adwait
	btfss	INTCON,TMR0IF	; 20µs done
	goto 	adwait				; then A/D

	call 	ad		; U measure
	movwf	PWM1	
	call 	ad		
	addwf	PWM1,f	; add both
	rrf		PWM1,f	; divide by 2

	call 	ad		; U measure
	movwf	PWM2	
	call 	ad		
	addwf	PWM2,f	; add both
	rrf		PWM2,f	; divide by 2

	movfw	PWM1
	addwf	PWM2,f	; optellen
	rrf		PWM2,f	; delen door 2

;next loop: first measure I
	bsf		ADCON0,5		; Meet I
	bcf		ADCON0,4		; Meet I
	bcf		ADCON0,3		; Meet I
;/
	movf	PWM2,w	;set measured (and averaged) value
	movwf	Ugemeten ; save the value, to transmit later via I²C

	subwf	PWMverschil,f	;compare measured-wanted value

	btfss	STATUS,C		; if C is zero
	goto	negatief		; result negative

positief	; result positive: send out more
; depending on the difference measured/wanted, I mak e bigger/smaller change
	movlw	.3	
	subwf	PWMverschil,w	; fill staturregister, don't change PWMverschil
	btfss	STATUS,C
	goto	pos0	;difference less than 0,1V, no change
	movlw	.25		
	subwf	PWMverschil,w	; statusregister vullen, PWMverschil blijft behouden
	btfss	STATUS,C
	goto	pos1		;difference less than 2,5, change 1 step
	movlw	.50		
	subwf	PWMverschil,w	; statusregister vullen, PWMverschil blijft behouden
	btfss	STATUS,C
	goto	pos2		; verschil between 2,5V en 5V, change 2 steps
	movlw	.65		
	subwf	PWMverschil,w	; statusregister vullen, PWMverschil blijft behouden
	btfss	STATUS,C
	goto	pos3		;verschil tussen 5V en 6,5V, change 5 steps

posmax	; difference greater than 6.5V, then increase with half the difference
	rrf		PWMverschil,w
	addwf	PWMuit,f
	goto	poslus

pos1	;verschil kleiner dan 1V
	movf	neg,f
	btfss	STATUS,Z
	goto	pos0
	incf	PWMuit,f	;verschil tussen 10 en 20, dan PWMuit 1 aanpassen
	btfsc	STATUS,Z	; if PWMuit is 0
	decf	PWMuit,f	;	went too far
	movlw	.10
	movwf	neg		;10 next times there's a little change, don't do it
	goto	PWMaangepast

pos0	;So if a change of 1 step is done, the next 10 times a change of 1 step would
;normally been done, it isn't done. So the regulator won't oscillate, value of 10 is 
;experimentally found. Big changes on output (remove load for example) will not be influenced by this.
	decf	neg,f
	goto 	PWMaangepast

pos2	; verschil tussen 1,5V en 3,5V
	incf	PWMuit,f	
	btfsc	STATUS,Z	; als PWMuit 0 is
	decf	PWMuit,f	;	te ver gegaan
	incf	PWMuit,f
	btfsc	STATUS,Z	; als PWMuit 0 is
	decf	PWMuit,f	;	te ver gegaan
	goto	poslus

pos3	; verschil tussen 3,5 en 5V
	incf	PWMuit,f	
	btfsc	STATUS,Z	; als PWMuit 0 is
	decf	PWMuit,f	;	te ver gegaan
	incf	PWMuit,f	
	btfsc	STATUS,Z	; als PWMuit 0 is
	decf	PWMuit,f	;	te ver gegaan
	incf	PWMuit,f	
	btfsc	STATUS,Z	; als PWMuit 0 is
	decf	PWMuit,f	;	te ver gegaan
	incf	PWMuit,f	
	btfsc	STATUS,Z	; als PWMuit 0 is
	decf	PWMuit,f	;	te ver gegaan
	incf	PWMuit,f
	btfsc	STATUS,Z	; als PWMuit 0 is
	decf	PWMuit,f	;	te ver gegaan
	goto	poslus

poslus
	clrf	neg
	clrf	pos
	goto	PWMaangepast

negatief	; resultaat negatief: minder uitsturen
;in negative, the max is decreasing 5 steps, because that's usually slower than
;increasing, so bigger steps would make it oscillate.

; negative result is inverted
	COMF	PWMverschil,w
	ADDLW	.1		;+1 to compensate borrow
	MOVWF	PWMverschil	
; /juiste uitkomst
	movlw	.3		
	subwf	PWMverschil,w	; statusregister vullen, PWMverschil blijft behouden
	btfss	STATUS,C
	goto	neg0	;verschil kleiner dan 0,1V, niet aanpassen
	movlw	.20
	subwf	PWMverschil,w	; statusregister vullen, PWMverschil blijft behouden
	btfss	STATUS,C
	goto	neg1	; verschil kleiner dan 1,5V	
	movlw	.50
	subwf	PWMverschil,w	; statusregister vullen, PWMverschil blijft behouden
	btfss	STATUS,C
	goto	neg2	; verschil tussen 1,5V en 3,5V	

	goto	neg3

neg1	;verschil kleiner dan 1V
	movf	neg,f
	btfss	STATUS,Z
	goto	neg0
	movf	PWMuit,f
	btfsc	STATUS,Z	; als PWMuit 0 is
	incf	PWMuit,f	; 1 van maken (na dec weer 0)
	decf	PWMuit,f
	movlw	.10
	movwf	neg		;aantal keer niet deze lus doen
	goto	PWMaangepast

neg0	;na neg1 gedaan te hebben, moeten we een vertraging hebben,
;om oscillaties te voorkomen. Om toch snel te reageren op grote
;veranderingen doen we een aantal keer neg1 niet na neg1 gedaan te
;hebben, komen we in een andere lus dan neg1, wordt dit ongedaan.
	decf	neg,f
	goto 	PWMaangepast

neg2	;verschil tussen 1V en 3,5V
	movf	PWMuit,f
	btfsc	STATUS,Z	; als PWMuit 0 is
	incf	PWMuit,f	; 1 van maken (na dec weer 0)
	decf	PWMuit,f
	btfsc	STATUS,Z	; als PWMuit 0 is
	incf	PWMuit,f	; 1 van maken (na dec weer 0)
	decf	PWMuit,f
	goto	neglus

neg3	;verschil tussen 3,5V en 7.5V
	movf	PWMuit,f
	btfsc	STATUS,Z	; als PWMuit 0 is
	incf	PWMuit,f	; 1 van maken (na dec weer 0)
	decf	PWMuit,f
	btfsc	STATUS,Z	; als PWMuit 0 is
	incf	PWMuit,f	; 1 van maken (na dec weer 0)
	decf	PWMuit,f
	btfsc	STATUS,Z	; als PWMuit 0 is
	incf	PWMuit,f	; 1 van maken (na dec weer 0)
	decf	PWMuit,f
	btfsc	STATUS,Z	; als PWMuit 0 is
	incf	PWMuit,f	; 1 van maken (na dec weer 0)
	decf	PWMuit,f
	btfsc	STATUS,Z	; als PWMuit 0 is
	incf	PWMuit,f	; 1 van maken (na dec weer 0)
	decf	PWMuit,f
	goto	neglus

neglus
	clrf	neg
	clrf	pos
	goto	PWMaangepast
		
		
PWMaangepast
	call	PWM

	return
;/regellus

;analog reading of the value:
ad
	bsf		ADCON0,2	;start de conversie
adklaar
	btfsc	ADCON0,2
	goto	adklaar		;wachten tot AD conversie gedaan is
	movf	ADRESH,w
	return		
;/ad


;hier volgt een routine om de PWM te sturen, in PWMuit moet een byte zitten die de
;duty-cycle aanduidt, 0 resulteert in 0V, .255 met 25.5V. 
;De f(PWM) is 8kHz, en TMR2 wordt gebruikt voor PWM.
PWM
	movf	PWMuit,w	
	movwf	CCPR1L	;duty-cycle juist zetten.
	return
;/pwm

User avatar
By phalanx
#5090
Naftie wrote:It works :!:
longest stabilizing time = 500ms

Just a suggestion... I would look into coding a PID control loop for your voltage correction. When tuned properly it will give you a very fast response time. You can also modify it to improve slew rates or overshoot.

Microchip has an application note dealing with it. Even a custom coded PID loop isn't too involved and there are tons of websites out there that will tell you how to optimize it.

-Bill
By Naftie
#5101
Well, I've worked with PID's in school...and it takes weeks to get a good result out of it...
And how will I include that in assembly code??
Edit: Nothing found on PID controllers written in assembly. Anyone knows if it's possible, and where can I find someting about it?

And the load can be anything between 0 and 1A or so, now it works just fine within the needed specifications, I'm not really looking forward to start whoule over again with my code...

But I'll take a look, and if its good, and I have some spare time, I will try it.
By lorix
#6145
Dear Naftie, can you upload entire schematic ? i don't understand the way for drive the nfet trought the capacitor with only 5 volt of the Pic