I want to generate a sine wave using PWM signal fed to a switches on a H-Bridge circuit. I have researched and found that the best way is to sine modulate the PWM signal using a look up table holding sine values ( which can be done by using a timer counter unit to generate a high frequency triangle wave , and counter to compare at a value taken form the LUT).
My question is what is the best way generate the data for the LUT and how do I store the sine values in hex on a 8 bit macro ,to be loaded in the compare register of the comparator ?
Press enter 64 times per quadrant. paste the results into your Source code, in a CONST Array declaration, ( along with the Eqn line, as a comment for revision purposes.)
Typically you store one quadrant and reverse scan direction, and reverse sign to build the 4 quadrants.
Comments: CCalc uses ;; as an Eqn block delimiter, and repeated enters repeat the lack Eqn block on the stack. Above sets 64 steps per quadrant, and 255 as Full scale. The +0.5 takes care of rounding
To improve your Sine precision, you should match the highest slopes to a natural slope in the timebase - that drops the errors on that portion of the sine, and drops the distortion.
You could also at the same time easily analyse how much the rounded 8 bit value differs from the ideal value and possibly select slightly different points to reduce the average error.
On Sun, 14 Oct 2007 19:36:43 -0000, ratemonotonic wrote:
I use Excel to generate and normalize the sine values, then Word to format them for inclusion into the program using a series of find and replace operations.
I'm including a little routine below with a pre-calculated sine table that might be of use to you.
Tom
;-------------------------------------------------------- ; ; VF_Controller.asm ; ; Voltage-Frequency Converter ; ; PIC 12F683 firmware ; to drive my VF Controller Mk II circuit ; ; V1.00: tested OK with scope on breadboard. ; did not test it with the switching ; hardware yet. ; ; tjl Sep 20,2007 ; ;-------------------------------------------------------- ; ; This program implements a half-bridge voltage-frequency ; speed controller for small single phase shaded pole ; induction motors. ; ; Speed range is from approx 60 Hz to 20 Hz, with the ; voltage reduced by the following formula: ; ; motor V = design V * motor freq / design freq ; ; The wiper of a pot connected between +5v and ground ; is connected to physical pin 3. The pot setting ; determines the motor speed. ; ; Active low -> open outputs on physical pins 7 and 6 ; drive the high side and low side half-H switches, ; respectively. ; ; A half-cycle sinewave is synthesized via PWM, and ; appears as an active high PWM signal on physical ; pin 5. ; ; Connect pins 7 and 6 to the cathodes of optoisolator ; LEDs, and the PWM pin paralleled to the anodes through ; a 330 ohm series resistor. ; ; Use the optoisolator transistors to drive a high side ; P-channel MOSFET and a low side N-channel MOSFET. ; ; Connect the motor between the junction of the two ; MOSFETs and neutral. ; ;-------------------------------------------------------- ; ; Physical pin 3 (AN3) - Speed pot ; Physical pin 5 (CCP1) - PWM output ; Physical pin 6 (GP1) - Neg Switch (active low) ; Physical pin 7 (GP0) - Pos Switch (active low) ; ;-------------------------------------------------------- ; ; 12F683 RAM: ; 96 bytes in bank0, 0x20-0x7f ; 32 bytes in bank1, 0xa0-0xbf ; ; Program memory: ; 2k 14-bit words, 0x000-0x7ff ; ; Data EEPROM: ; 256 bytes, accessed through DE decls or ; the four EExxx registers ;
org 0x2100 SineTbl de 0,13,25,37,50,62,74,86 de 98,109,120,131,142,152,162,171 de 180,189,197,205,212,219,225,231 de 236,240,244,247,250,252,254,255 de 255,255,254,252,250,247,244,240 de 236,231,225,219,212,205,197,189 de 180,171,162,152,142,131,120,109 de 98,86,74,62,50,37,25,13
VoltTbl de 255,247,240,233,227,221,215,210 de 205,200,195,191,186,182,178,174 de 171,168,164,161,158,155,152,149 de 147,144,142,139,137,135,133,131 de 129,126,125,123,121,119,118,116 de 114,113,111,110,108,107,106,104 de 103,102,101,99,98,97,96,95 de 94,92,92,90,90,89,88,87
; Un-init RAM
cblock 0x20 w_bup ; save W and STATUS from ISR stat_bup semaphore ; semaphore set by ISR when TMR0 times out rawspeed ; raw ADC speed pot measurement value speedval ; speed value to load into TMR0 sineptr ; SineTbl pointer sineval ; from SineTbl voltval ; from VoltTbl pwmvalhi ; high byte of sine x volt mult pwmvallo ; low byte of sine x volt mult running temp0 temp1 temp2 temp3 endc
;-------------------------------------------------------- ; ; Program code begins here ; ;--------------------------------------------------------
org 0 ; processor reset vector
goto main org 0x04 ; interrupt vector goto Int_Svc_Rtn ;-------------------------------------------------------- ; ; Interrupt service routine ; ;--------------------------------------------------------
Int_Svc_Rtn movwf w_bup ; save the W and STATUS regs movf STATUS,W movwf stat_bup btfss INTCON,T0IF ; TMR0 overflow? goto enableints ; no, just enable ints and return bcf INTCON,T0IF movf speedval,W ; reload the TMR0 preset movwf TMR0 movlw 1 movwf semaphore ; tell SendCycle that an int has occurred enableints movf stat_bup,W ; restore the W and STATUS regs movwf STATUS movf w_bup,W bsf INTCON,GIE ; enable system interrupts retfie
;-------------------------------------------------------- ; ; Main program routine begins here ; ;-------------------------------------------------------- main
; Disable system interrupts
bcf INTCON,GIE ; set the internal oscillator to 8 MHz
bank1 movlw 0x71 movwf OSCCON bank0 ; init I/O & ADC movlw 0x07 movwf CMCON0 ; 0,1,2 are digital I/O bank1 movlw b'01011000' ; AN3 analog, others digital I/O, Fosc/16 movwf ANSEL movlw b'00010011' ; Preset PosSw and NegSw as inputs movwf TRISIO bank0 movlw b'00001101' ; AN3, left-justified,ADON movwf ADCON0 bcf GPIO,PWMpin ; set PWM output low ; set up PWM
call StartPWM ; begin clrf running ; force parm init at first GetSpeed call call Dly1Sec ; 1 sec pause to let HV pwr supply settle mainloop
SendCycle ; set pwm from sine table and volts tbl, ; wait for interrupt, set next step's vals clrf sineptr sclp1 movf sineptr,W ; get sine value call EERead movwf sineval call PWMcalc ; calc PWM from sine & pre-calc'd volts val call LoadPWM ; set new PWM duty cycle movf semaphore,F ; wait for TMR0 interrupt btfsc STATUS,Z goto $-2 clrf semaphore incf sineptr,F ; loop through the sine table movlw 64 ; (SineTbl size) subwf sineptr,W btfss STATUS,Z goto sclp1 return EERead ; EEPROM read. Enter with addr in W, ; exit with data in W bank1 movwf EEADR bsf EECON1,RD movf EEDAT,W bank0 return SetPosPhase ; Open PWM path to Q1
Just use your favorite programming language to write a program to spit out the values, which you can write into or redirect into a file (to be pasted or included into the source code). Try it-- you'll use this technique again and again.
Best regards, Spehro Pefhany
--
"it's the network..." "The Journey is the reward"
speff@interlog.com Info for manufacturers: http://www.trexon.com
Embedded software/hardware/analog Info for designers: http://www.speff.com
ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here.
All logos and trade names are the property of their respective owners.