Name: | Mr. Helge B |
Company: | |
Web Site: | |
Code:
Helge B shares this code:
; PIC 3-Phase generator - buen-AT-operamail-com ; I borrowed and altered the table lookup and it's driver code. It is Copyright 1995 Eric Smith ; Fixed PWM frequency 3-phase sine generator for electric motors etc.. The output
; frequency are generated by jumps in the sine lookup table. For example the lowest
; frequency will repeat each value 16 times (4096 values). The highest will do 15 and 16
; jumps (only 16.5 values - maybe too few, not tested). All others generated by
; combinations of repeat/jump. The code is not tested in practice.
; Electric motors needs the voltage to follow the frequency. Therefore each sine value is
; multiplied by a factor (gain). The frequency (speed) and the gain variables are
; INDEPENDENT in the code. The simplest and most suitable would be to right rotate the
; gain into the speed variable. At a gain of 255 the controller would output 36 values a
; revolution at full voltage. If one want some voltage boost (motor torque) at particular
; conditions that is easy to implement too. Of course it would be interesting to monitor
; the speed of the motor and REDUCE voltage to save power on battry apps.
; This code generates 3 values ranging from 2 - 128 and 128-254. 128 is 0 volt and
; corresponds to the 50% PWM ratio (bridge). A separate PWM controller is required as
; it have to output some thousand pulses a second at 255 resolution The PWM controller
; should have fixed instruction number, master the time and clock the sine generator
; (handshake). It is an good idea to centre the PWM pulses to avoid simultaneously
; switching (noise) No speed ramping (frequency increment) is implemented, it should
; correspond the mecanical application. Hovever increasing the speed variable by one
; each revolution would be no problem. It is possible to alter the speed/gain at each
; PWM pulse, be aware! The 3 motor voltages should be output simultaneosly at the end.
; 08.09.01: PWM data preparation:
; Convertion of the voltage values into 4 delays and 2 data bytes. The purpose is to do
; as much processing as possible in the generator controller. At the same time not too
; much data should be created because of the transfer time to the PWM. The delays
; represent time between changes and the data is what to be output. The sum of all
; delays always is 256. Note: they are complements to 256 and 0 must be treated as
; zero delay. Usual method: before counting them up (incfsz), initially subtract 1 from all.
; Before counting down, add 1 to all. (Use decf/incf instead of movf at data transfer)
; Now, simply load 4 'counter' and 2 'data' registers in the PWM. Count first UP to
; zero, output data one, count next and so on. The third data output is given to be all
; set. This method introduce small errors, but i believe they are unessential to this
; application. Remember to compensate (at the other end) for the data transfer dead time.
; To implement centered pulses the 4 delays must initially be loaded twice, and second copy
; count DOWN at the 'mirror part'. The data must be inverted (comf). This also requires twice
; as fast controller. A 20MHz controller is beginning to reach the limit here if you want
; reasonable switching frequency (>3KHz). Another idea i had was to do the first PWM half in
; the generator, and the second in the PWM as the generator carry out processing.
; Note that there is only 3 outputs, but 6 are necessary for 3 phase output bridges. The
; additinal 3 signals are kind of inverted versions, but cross over delay must be insterted. That
; is a very short period where none of the transistor pairs are on, to protect them. I have no idea
; how long this period should be, but a very long period would decrease the dynamic range of the
; PWM. If someone has any experience about this, please let me know! Also ideas about fast
; paralell data transfers PIC to PIC wanted. The cross over delay and inverted signals could either
; be made in the PWM controller or in the transistor driver stage (depending on delay value). I think
; the PIC would do it most nice but, again, it's pretty busy.
; Outputs are delay1-4 and data 1-2.
; 04.19.03: Edited the text to make it more readable. The project have rested for a while,
; but I am now working on it again. Some things i found out:; The 'third data' to be all PWM's set is unnecessary. Guess what, no current would flow in the
; output bridge! Also the first and last delay can be added as one. So there's 3 or 4 delays, and TWO; data bytes required to control each 3 phase PWM period.; The 'whole inverter' can be implemented into a 20MHz PIC16C5X!! The idea is that no matter the
; distribution of delay values at output, one of them is always greater than 63. (256/4). So at 20MHz,
; there's room to do the processing during the longest delay, maintaining approx. 4KHz PWM frequency.
list p=16c55a
; Include file, change directory if needed
include "p16c5x.inc"
zero EQU H'0008'
temp EQU H'0009'
angle EQU H'000A'
gain EQU H'000B'
volt1 EQU H'000C'
volt2 EQU H'000D'
volt3 EQU H'000E'
speed EQU H'000F'
lsbpos EQU H'0010'
delay0 EQU H'0011'
delay1 EQU H'0012'
delay2 EQU H'0013'
delay3 EQU H'0014'
delay4 EQU H'0015'
data0 EQU H'001A'
data1 EQU H'001B'
data2 EQU H'001C'
; Start at the reset vector
org 0x000
GOTO start
sinetbl:
addwf PCL,f
retlw 000h
retlw 003h
retlw 006h
retlw 009h
retlw 00Ch
retlw 010h
retlw 013h
retlw 016h
retlw 019h
retlw 01Ch
retlw 01Fh
retlw 022h
retlw 025h
retlw 028h
retlw 02Bh
retlw 02Eh
retlw 031h
retlw 033h
retlw 036h
retlw 039h
retlw 03Ch
retlw 03Fh
retlw 041h
retlw 044h
retlw 047h
retlw 049h
retlw 04Ch
retlw 04Eh
retlw 051h
retlw 053h
retlw 055h
retlw 058h
retlw 05Ah
retlw 05Ch
retlw 05Eh
retlw 060h
retlw 062h
retlw 064h
retlw 066h
retlw 068h
retlw 06Ah
retlw 06Bh
retlw 06Dh
retlw 06Fh
retlw 070h
retlw 071h
retlw 073h
retlw 074h
retlw 075h
retlw 076h
retlw 078h
retlw 079h
retlw 07Ah
retlw 07Ah
retlw 07Bh
retlw 07Ch
retlw 07Dh
retlw 07Dh
retlw 07Eh
retlw 07Eh
retlw 07Eh
retlw 07Fh
retlw 07Fh
retlw 07Fh
retlw 07Fh
sort clrf data0 ;Subroutine to sort PWM data. (see driver comments)
movf volt1,w
movwf delay0 ;Presume volt1 is greatest
bsf data0,0 ;And set it's output
movf volt2,w
subwf delay0,w ;Test volt2 against volt1
btfsc STATUS,Z ;Equal?
bsf data0,1 ;Yes, just set that bit too (They share delay)
btfsc STATUS,C ;Volt2 greater?
goto test3 ;No, go testing volt3
rlf data0,f ;Yes, change output (Carry known to be zero)
movf volt2,w
movwf delay0 ;And correct delay
test3 movf volt3,w
subwf delay0,w ;Test volt3 against the greatest
btfsc STATUS,Z ;Equal?
bsf data0,2 ;Yes, just set that bit too (They share delay)
btfsc STATUS,C ;Volt3 greater?
goto diff ;No, go calculate difference
clrf data0
bsf data0,2 ;Yes, set that output
movf volt3,w
movwf delay0 ;And correct delay
diff movf delay0,w ;Get result
subwf zero,w ;Complement and..
addwf volt1,f ;..calc. DIFFERENCE to next (included voltage(s) are zeroed and excluded in next sort)
addwf volt2,f
addwf volt3,f
retlw d'0'
start:
clrf zero
clrf angle
clrf lsbpos
movlw d'127'
movwf speed ; Desired motor frequency. Values above 127 may generate too few sine values?? (<36 a revolution)
movlw d'255'
movwf gain ; Desired motor voltage. Should follow the frequency (max desired speed -> gain=255)
frame movf angle,w
movwf temp ; copy the angle
btfsc temp,6 ; is angle in the 2nd or 4th quadrant?
subwf zero,w ; yes, complement it to reduce to 1st or 3rd
andlw 07fh ; reduce to 1st quadrant
call sinetbl ; get magnitude
clrf volt1 ; empty the output
bcf STATUS,C ; Multiply the gain..
btfsc gain,0
addwf volt1,f
rrf volt1,f
bcf STATUS,C
btfsc gain,1
addwf volt1,f
rrf volt1,f
bcf STATUS,C
btfsc gain,2
addwf volt1,f
rrf volt1,f
bcf STATUS,C
btfsc gain,3
addwf volt1,f
rrf volt1,f
bcf STATUS,C
btfsc gain,4
addwf volt1,f
rrf volt1,f
bcf STATUS,C
btfsc gain,5
addwf volt1,f
rrf volt1,f
bcf STATUS,C
btfsc gain,6
addwf volt1,f
rrf volt1,f
bcf STATUS,C
btfsc gain,7
addwf volt1,f
rrf volt1,w
btfsc temp,7 ; was angle in 3rd or 4th quadrant?
subwf zero,w ; yes, complement it
xorlw d'128' ; align to center
movwf volt1
movlw d'85' ; 120 degrees offset for phase 2
addwf angle,w
movwf temp
btfsc temp,6 ; is angle in the 2nd or 4th quadrant?
subwf zero,w ; yes, complement it to reduce to 1st or 3rd
andlw 07fh ; reduce to 1st quadrant
call sinetbl ; get magnitude
clrf volt2 ; empty the output
bcf STATUS,C ; Multiply the gain..
btfsc gain,0
addwf volt2,f
rrf volt2,f
bcf STATUS,C
btfsc gain,1
addwf volt2,f
rrf volt2,f
bcf STATUS,C
btfsc gain,2
addwf volt2,f
rrf volt2,f
bcf STATUS,C
btfsc gain,3
addwf volt2,f
rrf volt2,f
bcf STATUS,C
btfsc gain,4
addwf volt2,f
rrf volt2,f
bcf STATUS,C
btfsc gain,5
addwf volt2,f
rrf volt2,f
bcf STATUS,C
btfsc gain,6
addwf volt2,f
rrf volt2,f
bcf STATUS,C
btfsc gain,7
addwf volt2,f
rrf volt2,w
btfsc temp,7 ; was angle in 3rd or 4th quadrant?
subwf zero,w ; yes, complement it
xorlw d'128' ; align to center
movwf volt2
movlw d'170' ; 240 degree offset for phase 3
addwf angle,w
movwf temp
btfsc temp,6 ; is angle in the 2nd or 4th quadrant?
subwf zero,w ; yes, complement it to reduce to 1st or 3rd
andlw 07fh ; reduce to 1st quadrant
call sinetbl ; get magnitude
clrf volt3 ; empty the output
bcf STATUS,C ; Multiply the gain..
btfsc gain,0
addwf volt3,f
rrf volt3,f
bcf STATUS,C
btfsc gain,1
addwf volt3,f
rrf volt3,f
bcf STATUS,C
btfsc gain,2
addwf volt3,f
rrf volt3,f
bcf STATUS,C
btfsc gain,3
addwf volt3,f
rrf volt3,f
bcf STATUS,C
btfsc gain,4
addwf volt3,f
rrf volt3,f
bcf STATUS,C
btfsc gain,5
addwf volt3,f
rrf volt3,f
bcf STATUS,C
btfsc gain,6
addwf volt3,f
rrf volt3,f
bcf STATUS,C
btfsc gain,7
addwf volt3,f
rrf volt3,w
btfsc temp,7 ; was angle in 3rd or 4th quadrant?
subwf zero,w ; yes, complement it
xorlw d'128' ; align to center
movwf volt3
call sort ;Format voltages to PWM delays and data to disengage PWM controller.
movf delay0,w
movwf delay1 ;Store first delay
movf data0,w
movwf data1 ;Store first data
call sort
movf delay0,w
movwf delay2 ;Store second delay
movf data0,w
iorwf data1,w ;Include first and..
movwf data2 ;..store second data (Third data is given to be simply all switched on)
clrw ;Find the third delay by checking data. If all set -> zero. (Shared with another)
btfss data2,0
movf volt1,w
btfss data2,1
movf volt2,w
btfss data2,2
movf volt3,w
movwf delay3
addwf delay1,w ;Calculate the fourth delay (sum of previous and this delay -> 256)
addwf delay2,w
subwf zero,w ;Complement
movwf delay4
movf speed,w ; Lookup table pattern generator..
addwf lsbpos,f
btfsc STATUS,DC
incf angle,f
swapf speed,w
andlw d'15'
addwf angle,f
goto frame
END
See also Pages:
Code:
;---===>>> Version 27/8-2004 ; PWM generator inside same chip! Improved sorting procedure (some register names are not descriptive because of this). ; This program runs on a PIC16C57 and creates the six PWM signals necessary to drive a power transistor bridge including ; dead time generation. Of course a hardware interface is required between the PIC and the power transistors. ; I have tested the code driving a 1.1Kw tree phase motor (without load), and it seems to work just fine. ; Maximum PWM frequency would be X-tal.freq/4/256 resoulution/4 inst.loop = 20MHz/4/256/4= 4.88KHz ; The software PWM loop code is located at the end and works as the main program. It outputs the transistor gate ; data to PORTB, loops the delay time, and also has a third role calling the sine generator subroutine at the right ; time. In other words the PWM is using values calculated during the previous PWM period. Because of this, a copy of ; all necessary register values are passed to a second set of registers each period. It similar to interrupt handling, ; but since the PWM period is a known value it can be triggered from the main program, ie the PWM loop. ; Initially, during the first PWM period, the PORTB outputs are switched off until the generator has run once. ; There is no proper speed control implemented yet, just some simple test code (a button acc/dec control part) ; I used for testing purposes. ; NOTE: I previously mentioned that data values passed to the output bridge containing the values 111 was not ; necessary to drive the bridge, but It's wrong. The motor windings create returning currents ; immediately after each PWM pulse, and this current must be passed back to the motor during the time no PWM ; pulses are on. This is similar to the flyback diodes used when driving DC motors in PWM, and without this ; current return path, the motor might not run very well. ; The code listed here includes the necessary flyback states. ; Please send me an email if you find errors or other problems with this program. list p=16c57 ; Include file, change directory if needed include "p16c5x.inc" zero EQU H'0008' temp EQU H'0009' angle EQU H'000A' gain EQU H'000B' volt1 EQU H'000C' volt2 EQU H'000D' volt3 EQU H'000E' speed EQU H'000F' lsbpos EQU H'0010' delay1 EQU H'0011' delay2 EQU H'0012' delay3 EQU H'0013' delay4 EQU H'0014' data1 EQU H'0015' dataX EQU H'0016' data2 EQU H'0017' pwm_o2 EQU H'0018' pwm_o3 EQU H'0019' pwm_o4 EQU H'001A' del_o2 EQU H'001B' del_o3 EQU H'001C' del_o4 EQU H'001D' exe_o EQU H'001E' exeproc EQU H'001F' ; Start at the reset vector org 0x000 GOTO init sinetbl: addwf PCL,f retlw 000h retlw 003h retlw 006h retlw 009h retlw 00Ch retlw 010h retlw 013h retlw 016h retlw 019h retlw 01Ch retlw 01Fh retlw 022h retlw 025h retlw 028h retlw 02Bh retlw 02Eh retlw 031h retlw 033h retlw 036h retlw 039h retlw 03Ch retlw 03Fh retlw 041h retlw 044h retlw 047h retlw 049h retlw 04Ch retlw 04Eh retlw 051h retlw 053h retlw 055h retlw 058h retlw 05Ah retlw 05Ch retlw 05Eh retlw 060h retlw 062h retlw 064h retlw 066h retlw 068h retlw 06Ah retlw 06Bh retlw 06Dh retlw 06Fh retlw 070h retlw 071h retlw 073h retlw 074h retlw 075h retlw 076h retlw 078h retlw 079h retlw 07Ah retlw 07Ah retlw 07Bh retlw 07Ch retlw 07Dh retlw 07Dh retlw 07Eh retlw 07Eh retlw 07Eh retlw 07Fh retlw 07Fh retlw 07Fh retlw 07Fh sort movf volt1,w ;Finding the greatest voltage. Result in delay2. subwf volt2,w movf volt2,w btfss STATUS,C movf volt1,w movwf delay2 subwf volt3,w movf volt3,w btfsc STATUS,C movwf delay2 movf delay2,w subwf volt1,f ;..calc. DIFFERENCE to next (included voltage(s) are zeroed and excluded in next sort) btfsc STATUS,Z ;Set the PWM bits bsf data2,0 subwf volt2,f btfsc STATUS,Z bsf data2,1 subwf volt3,f btfsc STATUS,Z bsf data2,2 retlw d'0' init clrf PORTB ;Switch off PWM drivers movlw B'00000000' tris PORTB movlw d'8' ;increment TMR0 at each program cycle option clrf zero clrf angle clrf lsbpos clrf exe_o ; Initial jump. movlw d'4' movwf speed ; Desired motor frequency. Values above 127 may generate too few sine values?? (<36 a revolution) movlw d'8' movwf gain ; Desired motor voltage. Should follow the frequency (max desired speed -> gain=255) process movf angle,w movwf temp ; copy the angle btfsc temp,6 ; is angle in the 2nd or 4th quadrant? subwf zero,w ; yes, complement it to reduce to 1st or 3rd andlw 07fh ; reduce to 1st quadrant call sinetbl ; get magnitude clrf volt1 ; empty the output bcf STATUS,C ; Multiply the gain.. btfsc gain,0 addwf volt1,f rrf volt1,f bcf STATUS,C btfsc gain,1 addwf volt1,f rrf volt1,f bcf STATUS,C btfsc gain,2 addwf volt1,f rrf volt1,f bcf STATUS,C btfsc gain,3 addwf volt1,f rrf volt1,f bcf STATUS,C btfsc gain,4 addwf volt1,f rrf volt1,f bcf STATUS,C btfsc gain,5 addwf volt1,f rrf volt1,f bcf STATUS,C btfsc gain,6 addwf volt1,f rrf volt1,f bcf STATUS,C btfsc gain,7 addwf volt1,f rrf volt1,w btfsc temp,7 ; was angle in 3rd or 4th quadrant? subwf zero,w ; yes, complement it xorlw d'128' ; align to center movwf volt1 movlw d'85' ; 120 degrees offset for phase 2 addwf angle,w movwf temp btfsc temp,6 ; is angle in the 2nd or 4th quadrant? subwf zero,w ; yes, complement it to reduce to 1st or 3rd andlw 07fh ; reduce to 1st quadrant call sinetbl ; get magnitude clrf volt2 ; empty the output bcf STATUS,C ; Multiply the gain.. btfsc gain,0 addwf volt2,f rrf volt2,f bcf STATUS,C btfsc gain,1 addwf volt2,f rrf volt2,f bcf STATUS,C btfsc gain,2 addwf volt2,f rrf volt2,f bcf STATUS,C btfsc gain,3 addwf volt2,f rrf volt2,f bcf STATUS,C btfsc gain,4 addwf volt2,f rrf volt2,f bcf STATUS,C btfsc gain,5 addwf volt2,f rrf volt2,f bcf STATUS,C btfsc gain,6 addwf volt2,f rrf volt2,f bcf STATUS,C btfsc gain,7 addwf volt2,f rrf volt2,w btfsc temp,7 ; was angle in 3rd or 4th quadrant? subwf zero,w ; yes, complement it xorlw d'128' ; align to center movwf volt2 movlw d'170' ; 240 degree offset for phase 3 addwf angle,w movwf temp btfsc temp,6 ; is angle in the 2nd or 4th quadrant? subwf zero,w ; yes, complement it to reduce to 1st or 3rd andlw 07fh ; reduce to 1st quadrant call sinetbl ; get magnitude clrf volt3 ; empty the output bcf STATUS,C ; Multiply the gain.. btfsc gain,0 addwf volt3,f rrf volt3,f bcf STATUS,C btfsc gain,1 addwf volt3,f rrf volt3,f bcf STATUS,C btfsc gain,2 addwf volt3,f rrf volt3,f bcf STATUS,C btfsc gain,3 addwf volt3,f rrf volt3,f bcf STATUS,C btfsc gain,4 addwf volt3,f rrf volt3,f bcf STATUS,C btfsc gain,5 addwf volt3,f rrf volt3,f bcf STATUS,C btfsc gain,6 addwf volt3,f rrf volt3,f bcf STATUS,C btfsc gain,7 addwf volt3,f rrf volt3,w btfsc temp,7 ; was angle in 3rd or 4th quadrant? subwf zero,w ; yes, complement it xorlw d'128' ; align to center movwf volt3 movf speed,w ; Lookup table pattern generator.. addwf lsbpos,f btfsc STATUS,DC incf angle,f swapf speed,w andlw d'15' addwf angle,f ;-------------This code was used to control speed in test setup movlw d'10' ;BEGIN temporary button control (not included in process time) subwf angle,w btfsc STATUS,C goto skipbut movf PORTA,w movwf temp movlw d'1' btfsc temp,2 addwf gain,f btfsc STATUS,C decf gain,f bsf STATUS,C btfsc temp,3 subwf gain,f btfss STATUS,C incf gain,f bcf STATUS,C rrf gain,w movwf speed skipbut ;END temporary button control (not included in process time) ;-------------This code was used to control speed in test setup clrf data2 ;Sorting PWM data clrf delay4 call sort ;Find first PWM data and delay. Subtract delay from volt1-3 movf data2,w movwf data1 ;Store first PWM data movf delay2,w movwf delay1 subwf delay4,f call sort ;Find second PWM data and delay movf delay2,w btfsc STATUS,Z decf delay2,f ;Convert 0 to 255 movf delay2,w subwf delay4,f movlw d'255' ;Find third delay from data pattern (if all set ->255) btfss data2,0 movf volt1,w btfss data2,1 movf volt2,w btfss data2,2 movf volt3,w movwf delay3 subwf delay4,f ;Fourth delay= 256-Del1-Del2-Del3 movf data1,w ;Format 6 PWM outputs (for bridge) and make the deadtime data (dataX) movwf dataX comf data1,w andlw D'7' movwf temp swapf temp,w addwf data1,f comf data2,w andlw D'7' movwf temp swapf temp,w addwf dataX,f addwf data2,f clrf exeproc movlw d'63' ;Check within what PWM delay the process can be executed (64*4=256 cycles max) addwf delay4,w rlf exeproc,f ;The result is copied from carry bit movlw d'63' addwf delay3,w rlf exeproc,f movlw d'63' addwf delay2,w rlf exeproc,f comf exeproc,f movlw d'63' ;The generator process time to subtract from the PWM loop (63*4) btfsc exe_o,0 ;Where to get back to the PWM loop goto E2 btfsc exe_o,1 goto E3 btfsc exe_o,2 goto E4 goto cycle ;Initial jump. E2 addwf del_o2,f ;add process time and clear execution flag clrf exe_o nop nop nop nop goto L2 E3 addwf del_o3,f clrf exe_o nop nop goto L3 E4 addwf del_o4,f clrf exe_o goto L4 cycle clrf PORTB ;'000'000' movf delay2,w movwf del_o2 movf delay3,w movwf del_o3 movlw B'01110000' movwf PORTB ;'111'000' movf delay4,w movwf del_o4 movf dataX,w movwf pwm_o2 movf data2,w movwf pwm_o3 andlw B'00000111' ;'000'111' movwf pwm_o4 movf exeproc,w movwf exe_o movf data1,w L1 andlw B'01110000' incfsz delay1,f goto L1 movwf PORTB ;'110'000' movf data1,w nop movwf PORTB ;'110'001' - Data1 btfsc exe_o,0 goto process L2 movf pwm_o2,w incfsz del_o2,f goto L2 movwf PORTB ;'100'001' - DataX movf pwm_o3,w nop movwf PORTB ;'100'011' - Data2 btfsc exe_o,1 goto process L3 movf pwm_o4,w incfsz del_o3,f goto L3 movwf PORTB ;'000'011' movlw B'00000111' nop movwf PORTB ;'000'111' btfsc exe_o,2 goto process L4 nop incfsz del_o4,f goto L4 goto cycle END
Questions: