pxidr84
- 8th May 2011, 12:29
Hi everyone,
I'm currently making a 3-phase VFD. I use the PIC18F4431 with a 10MHz crystal (PLL enabled, so 10*4=40MHz).
My program works quite good, because I've tried it on a real 3-phase motor, the PIC was feeding the IGBT power module, and the motor ran very fine (thanks to Henrik for the timer reload routine).
Unfortunately, I've discover a phenomenon on the oscilloscope : I've connected a RC filter and I obtain this :
http://www.youtube.com/watch?v=z561eyX6Kmc
As you can see, sometimes the sine "jumps" randomly (it's very quick). It happens more often at high frequencies (here about 120Hz). I think it can be quite bad for the motor and the IGBT power module.
My complete code :
' PIC initialization
DEFINE OSC 40
DEFINE LCD_DREG PORTC
DEFINE LCD_EREG PORTD
DEFINE LCD_RSREG PORTD
DEFINE LCD_EBIT 0
DEFINE LCD_RSBIT 1
DEFINE ADC_BITS 10
DEFINE USE_LOWPRIORITY 1
' BAS includes
INCLUDE "DT_INTS-18.bas"
INCLUDE "ReEnterPBP-18.bas"
INCLUDE "ReEnterPBP-18LP.bas"
INCLUDE "Sine_table.bas"
' ADC registers configuration
ADCON0=%11101
ADCON1=%10000
ADCON2=%10000110
ANSEL1=%0
' PCPWM registers configuration
PTCON0=%10
PTCON1=%10000000
PWMCON1=%1
' Inverter variables
ustep var byte
vstep var byte
wstep var byte
uduty var word
vduty var word
wduty var word
freq VAR word
amp var word
copy VAR WORD
reload VAR WORD
dum VAR WORD
dum1 VAR WORD
dum2 VAR wORD
flag var bit
flag1 VAR BIT
flag2 VAR BIT
flag3 var bit
flag4 var bit
flag5 var bit
flag6 var bit
flag7 var bit
b var byte
b1 var byte
run VAR BIT
rot var BIT
menu var bit
menupos VAR BYTE
isense VAR WORD
usense VAR WORD
tsense VAR WORD
potsense var word
maxfreq var word
minfreq var word
imax var byte
pwmf var byte
res var byte
fault var byte
lastf var byte
' Default variables definition
dum1=34696
dum2=32
menupos=1
b=0
b1=0
flag=%1
flag3=%1
run=%0
fault=%0
' Reading EEPROM
read 0,rot
read 1,maxfreq.highbyte
read 2,maxfreq.lowbyte
read 3,minfreq.highbyte
read 4,minfreq.lowbyte
read 5,imax
read 6,pwmf
read 7,lastf
' PWM carrier frequency configuration
gosub pwmsub
' Create interrupt processors
ASM
INT_LIST_L macro
INT_Handler TMR0_INT,_calcint,PBP,yes
endm
INT_CREATE_L
INT_LIST macro
INT_Handler TMR1_INT,_pwmint,PBP,yes
INT_Handler INT1_INT,_faultint,PBP,yes
INT_Handler INT2_INT,_stopint,PBP,yes
endm
INT_CREATE
ENDASM
' Interrupts and timers enable
@ INT_ENABLE TMR0_INT
@ INT_ENABLE TMR1_INT
@ INT_ENABLE INT1_INT
@ INT_ENABLE INT2_INT
T0CON=%10000010
T1CON=%1
' Inverter startup
high PORTD.5
HIGH PORTE.0
pause 1000
' Turn LCD on and write custom characters to CGRAM
LCDOUT $fe,$40,$0,$4,$e,$15,$4,$4,$4,$0
LCDOUT $fe,$48,$0,$4,$4,$4,$15,$e,$4,$0
LCDOUT $fe,1
' Main program loop
mainlp:
' Start ADC conversion
ADCON0.1=%1
WHILE ADCON0.1=%1:WEND
' Store ADC results
isense.HighByte=ADRESH
isense.LowByte=ADRESL
usense.HighByte=ADRESH
usense.LowByte=ADRESL
tsense.HighByte=ADRESH
tsense.LowByte=ADRESL
potsense.HighByte=ADRESH
potsense.LowByte=ADRESL
' Security fault verifications
if isense**19218>imax then fault=1
if usense>820 then fault=2
if tsense<330 then fault=3
' Security fault tripping
IF fault>0 then goto faultsub
' Brake signal generation
if usense>770 then PORTD.7=%1
' Run
if run=%1 then
IF flag1=%0 then PWMCON0.6=%1:HIGH PORTD.6:flag1=%1
endif
' Stop
if run=%0 then
if flag1=%0 then PWMCON0=%0:LOW PORTD.6:flag1=%1
ENDIF
' FWD rotation
if rot=%1 then
if flag2=%0 THEN ustep=29:vstep=59:wstep=89:write 0,rot:flag2=%1
endif
' RWD rotation
if rot=%0 then
if flag2=%0 THEN ustep=89:vstep=59:wstep=29:write 0,rot:flag2=%1
endif
' - button
Button PORTB.6,1,128,32,b,0,ret
if menu=%0 THEN menupos=menupos-1
ret:
' + button
Button PORTB.7,1,128,32,b1,0,ret1
if menu=%0 THEN menupos=menupos+1
ret1:
' Run/stop button
if PORTD.2=%1 then
if run=%0 and menupos<6 and flag3=%0 then run=%1:flag1=%0:flag3=%1
if run=%1 and flag3=%0 then run=%0:flag1=%0:flag3=%1
endif
' FWD/RWD button
if PORTD.3=%1 then
if rot=%0 and run=%0 and flag4=%0 then rot=%1:flag2=%0:flag4=%1
if rot=%1 and run=%0 and flag4=%0 then rot=%0:flag2=%0:flag4=%1
endif
' Menu/OK button
if PORTD.4=%1 then
if menu=%0 and run=%0 and menupos>5 and flag5=%0 then menu=%1:flag5=%1
if menu=%1 and flag5=%0 then menu=%0:flag5=%1
endif
' Buttons released state
if PORTD.2=0 then flag3=0
if PORTD.3=0 then flag4=0
IF PORTD.4=0 then flag5=0
' LCD first line writing
if rot=%1 then LCDOUT $fe,$2,"+"
if rot=%0 then LCDOUT $fe,$2,"-"
LCDOUT DEC freq DIG 3,DEC freq DIG 2,DEC freq DIG 1,".",DEC freq DIG 0,"Hz"
IF run=%1 then LCDOUT rep 32\5,"RUN"
IF run=%0 then LCDOUT rep 32\4,"STOP"
' Inverter menu (LCD second line writing)
select case menupos
' Menu limits
if menupos<1 then menupos=1
if menupos>10 then menupos=10
if run=%1 then
if menupos>5 then menupos=5
endif
' Current sensing submenu
CASE 1
isense=isense**19218
lcdout $fe,$c0,$1,$20,"1 ISENS: ",DEC isense DIG 2,DEC isense DIG 1,".",DEC isense DIG 0,"A"
' Voltage sensing submenu
case 2
usense=usense**32030
lcdout $fe,$c0,$1,$0,"2 USENS: ",DEC3 usense,"V",32
' Temperature sensing submenu
case 3
tsense=(tsense-1023)/7
lcdout $fe,$c0,$1,$0,"3 TEMP: ",DEC tsense DIG 1,DEC tsense DIG 0,$df,"C",rep $20\2
' Last fault reading submenu
case 4
lcdout $fe,$c0,$1,$0,"4 LASTFAULT: ",DEC1 lastf
' Firmware reading submenu
case 5
IF run=%1 then
lcdout $fe,$c0,$1,$20,"5 FW: V2011.00"
else
lcdout $fe,$c0,$1,$0,"5 FW: V2011.00"
endif
' Maximum frequency adjust submenu
case 6
if menu=%1 then
Lcdout $fe,$c0,$3e,$3e,"A MAX: ",DEC maxfreq DIG 3,DEC maxfreq DIG 2,DEC maxfreq DIG 1,".",DEC maxfreq DIG 0,"Hz"
Button PORTB.6,1,128,4,b,0,ret2
if maxfreq>minfreq THEN maxfreq=maxfreq-1
ret2:
Button PORTB.7,1,128,4,b1,0,ret3
if maxfreq<1200 THEN maxfreq=maxfreq+1
ret3:
flag6=%0
else
lcdout $fe,$c0,$1,$0,"A MAX: ",DEC maxfreq DIG 3,DEC maxfreq DIG 2,DEC maxfreq DIG 1,".",DEC maxfreq DIG 0,"Hz"
IF flag6=%0 then write 1,maxfreq.highbyte:write 2,maxfreq.lowbyte:flag6=%1
endif
' Minimum frequency adjust submenu
case 7
if menu=%1 then
Lcdout $fe,$c0,$3e,$3e,"B MIN: ",DEC minfreq DIG 3,DEC minfreq DIG 2,DEC minfreq DIG 1,".",DEC minfreq DIG 0,"Hz"
Button PORTB.6,1,128,4,b,0,ret4
if minfreq>10 THEN minfreq=minfreq-1
ret4:
Button PORTB.7,1,128,4,b1,0,ret5
if minfreq<maxfreq THEN minfreq=minfreq+1
ret5:
flag6=%0
else
lcdout $fe,$c0,$1,$0,"B MIN: ",DEC minfreq DIG 3,DEC minfreq DIG 2,DEC minfreq DIG 1,".",DEC minfreq DIG 0,"Hz"
IF flag6=%0 then write 3,minfreq.highbyte:write 4,minfreq.lowbyte:flag6=%1
endif
' Current trip adjust submenu
case 8
if menu=%1 then
Lcdout $fe,$c0,$3e,$3e,"C ITRIP: ",DEC imax DIG 2,DEC imax DIG 1,".",DEC imax DIG 0,"A"
Button PORTB.6,1,128,8,b,0,ret6
if imax>0 THEN imax=imax-1
ret6:
Button PORTB.7,1,128,8,b1,0,ret7
if imax<150 THEN imax=imax+1
ret7:
flag6=%0
else
lcdout $fe,$c0,$1,$0,"C ITRIP: ",DEC imax DIG 2,DEC imax DIG 1,".",DEC imax DIG 0,"A"
IF flag6=%0 then write 5,imax:flag6=%1
endif
' PWM carrier frequency adjust submenu
case 9
if menu=%1 then
Lcdout $fe,$c0,$3e,$3e,"D PWMFREQ: ",DEC1 pwmf,rep $20\2
Button PORTB.6,1,128,32,b,0,ret8
if pwmf>1 THEN pwmf=pwmf-1
ret8:
Button PORTB.7,1,128,32,b1,0,ret9
if pwmf<5 THEN pwmf=pwmf+1
ret9:
flag6=%0
else
lcdout $fe,$c0,$1,$0,"D PWMFREQ: ",DEC1 pwmf,rep $20\2
IF flag6=%0 then write 6,pwmf:gosub pwmsub:flag6=%1
endif
' Reset all settings submenu
case 10
if menu=%1 then
if flag7=%0 then
rot=%1:write 0,rot
maxfreq=500:write 1,maxfreq.highbyte:write 2,maxfreq.lowbyte
minfreq=10:write 3,minfreq.highbyte:write 4,minfreq.lowbyte
imax=150:write 5,imax
pwmf=3:write 6,pwmf
Lcdout $fe,$c0,$3e,$3e,"E RESET? OK",REP $20\3:flag7=%1
endif
endif
if menu=%0 then lcdout $fe,$c0,$20,$0,"E RESET?",rep $20\6:flag7=%0
end select
goto mainlp
' PWM update interrupt (Timer 1)
pwmint:
' Timer management
T1CON.0=%0
copy.HighByte=TMR1H
copy.LowByte=TMR1L
copy=copy+reload
TMR1H=copy.HighByte
TMR1L=copy.LowByte
T1CON.0=%1
' PWM U phase calculation
uduty=sine[ustep]
uduty=(uduty<<res)**amp
' PWM V phase calculation
vduty=sine[vstep]
vduty=(vduty<<res)**amp
' PWM W phase calculation
wduty=sine[wstep]
wduty=(wduty<<res)**amp
' PWM U, V and W update
PDC0H=uduty.highbyte
PDC0L=uduty.lowbyte
PDC1H=vduty.highbyte
PDC1L=vduty.lowbyte
PDC2H=wduty.highbyte
PDC2L=wduty.lowbyte
' Phase angle calculation
@ decf _ustep,1
@ decf _vstep,1
@ decf _wstep,1
' Phase angle reinitialization
if ustep=0 then ustep=89
if vstep=0 then vstep=89
if wstep=0 then wstep=89
@ INT_RETURN
' PWM calculation interrupt (Timer 0)
calcint:
' Recalculations
if flag=%1 THEN
' Reload timer calculation
dum=dum1*dum2
reload=Div32 freq
reload=(65535-reload)+8
' U/F calculation
if freq<=500 then
amp=(freq*131)+35
ELSE
AMP=65535
ENDIF
flag=%0
ENDIF
' Frequency reference control by potentiometer
potsense=((potsense<<6)**maxfreq)+5
if potsense<>freq then freq=potsense:flag=%1
' Frequency limits
if freq<minfreq then freq=minfreq
if freq>maxfreq then freq=maxfreq
@ INT_RETURN
' PWM carrier frequency configuration subroutine
pwmsub:
if pwmf=1 then PTPERH=$f:PTPERL=$ff:res=6
if pwmf=2 then PTPERH=$7:PTPERL=$ff:res=5
if pwmf=3 then PTPERH=$3:PTPERL=$ff:res=4
if pwmf=4 then PTPERH=$1:PTPERL=$ff:res=3
if pwmf=5 then PTPERH=$0:PTPERL=$ff:res=2
return
' IPM fault interrupt
faultint:
fault=4
goto faultsub
@ INT_RETURN
' Emergency stop interrupt
stopint:
fault=5
goto faultsub
@ INT_RETURN
' Inverter fault subroutine
faultsub:
' Emergency stop of the inverter
PWMCON0=%0
T1CON.0=%0
LOW PORTD.5
low PORTD.6
low PORTD.7
low PORTE.0
write 7,fault
' Disable interrupts
@ INT_DISABLE TMR0_INT
@ INT_DISABLE TMR1_INT
@ INT_DISABLE INT1_INT
@ INT_DISABLE INT2_INT
' LCD fault display
lcdout $fe,$2,"FAULT!",rep $20\10
lcdout $fe,$c0,"CODE: ",dec fault,rep $20\9
' Fault LED blink loop
faultlp:
HIGH PORTE.1
PAUSE 500
LOW PORTE.1
pause 500
goto faultlp
The sine table :
' Sine table (4 degrees/step, 90*4=360 degrees)
sine VAR byte[90]
sine[0]=128
sine[1]=137
sine[2]=146
sine[3]=155
sine[4]=163
sine[5]=172
sine[6]=180
sine[7]=188
sine[8]=196
sine[9]=203
sine[10]=210
sine[11]=217
sine[12]=223
sine[13]=229
sine[14]=234
sine[15]=239
sine[16]=243
sine[17]=247
sine[18]=250
sine[19]=252
sine[20]=254
sine[21]=255
sine[22]=255
sine[23]=255
sine[24]=255
sine[25]=254
sine[26]=252
sine[27]=250
sine[28]=247
sine[29]=243
sine[30]=239
sine[31]=234
sine[32]=229
sine[33]=223
sine[34]=217
sine[35]=210
sine[36]=203
sine[37]=196
sine[38]=188
sine[39]=180
sine[40]=172
sine[41]=163
sine[42]=155
sine[43]=146
sine[44]=137
sine[45]=128
sine[46]=119
sine[47]=110
sine[48]=101
sine[49]=93
sine[50]=84
sine[51]=76
sine[52]=68
sine[53]=60
sine[54]=53
sine[55]=46
sine[56]=39
sine[57]=33
sine[58]=27
sine[59]=22
sine[60]=17
sine[61]=13
sine[62]=9
sine[63]=6
sine[64]=4
sine[65]=2
sine[66]=1
sine[67]=0
sine[68]=0
sine[69]=1
sine[70]=2
sine[71]=4
sine[72]=6
sine[73]=9
sine[74]=13
sine[75]=17
sine[76]=22
sine[77]=27
sine[78]=33
sine[79]=39
sine[80]=46
sine[81]=53
sine[82]=60
sine[83]=68
sine[84]=76
sine[85]=84
sine[86]=93
sine[87]=101
sine[88]=110
sine[89]=119
And if you have some ideas and suggestions to improve the program... it will be good.
Thanks. :)
I'm currently making a 3-phase VFD. I use the PIC18F4431 with a 10MHz crystal (PLL enabled, so 10*4=40MHz).
My program works quite good, because I've tried it on a real 3-phase motor, the PIC was feeding the IGBT power module, and the motor ran very fine (thanks to Henrik for the timer reload routine).
Unfortunately, I've discover a phenomenon on the oscilloscope : I've connected a RC filter and I obtain this :
http://www.youtube.com/watch?v=z561eyX6Kmc
As you can see, sometimes the sine "jumps" randomly (it's very quick). It happens more often at high frequencies (here about 120Hz). I think it can be quite bad for the motor and the IGBT power module.
My complete code :
' PIC initialization
DEFINE OSC 40
DEFINE LCD_DREG PORTC
DEFINE LCD_EREG PORTD
DEFINE LCD_RSREG PORTD
DEFINE LCD_EBIT 0
DEFINE LCD_RSBIT 1
DEFINE ADC_BITS 10
DEFINE USE_LOWPRIORITY 1
' BAS includes
INCLUDE "DT_INTS-18.bas"
INCLUDE "ReEnterPBP-18.bas"
INCLUDE "ReEnterPBP-18LP.bas"
INCLUDE "Sine_table.bas"
' ADC registers configuration
ADCON0=%11101
ADCON1=%10000
ADCON2=%10000110
ANSEL1=%0
' PCPWM registers configuration
PTCON0=%10
PTCON1=%10000000
PWMCON1=%1
' Inverter variables
ustep var byte
vstep var byte
wstep var byte
uduty var word
vduty var word
wduty var word
freq VAR word
amp var word
copy VAR WORD
reload VAR WORD
dum VAR WORD
dum1 VAR WORD
dum2 VAR wORD
flag var bit
flag1 VAR BIT
flag2 VAR BIT
flag3 var bit
flag4 var bit
flag5 var bit
flag6 var bit
flag7 var bit
b var byte
b1 var byte
run VAR BIT
rot var BIT
menu var bit
menupos VAR BYTE
isense VAR WORD
usense VAR WORD
tsense VAR WORD
potsense var word
maxfreq var word
minfreq var word
imax var byte
pwmf var byte
res var byte
fault var byte
lastf var byte
' Default variables definition
dum1=34696
dum2=32
menupos=1
b=0
b1=0
flag=%1
flag3=%1
run=%0
fault=%0
' Reading EEPROM
read 0,rot
read 1,maxfreq.highbyte
read 2,maxfreq.lowbyte
read 3,minfreq.highbyte
read 4,minfreq.lowbyte
read 5,imax
read 6,pwmf
read 7,lastf
' PWM carrier frequency configuration
gosub pwmsub
' Create interrupt processors
ASM
INT_LIST_L macro
INT_Handler TMR0_INT,_calcint,PBP,yes
endm
INT_CREATE_L
INT_LIST macro
INT_Handler TMR1_INT,_pwmint,PBP,yes
INT_Handler INT1_INT,_faultint,PBP,yes
INT_Handler INT2_INT,_stopint,PBP,yes
endm
INT_CREATE
ENDASM
' Interrupts and timers enable
@ INT_ENABLE TMR0_INT
@ INT_ENABLE TMR1_INT
@ INT_ENABLE INT1_INT
@ INT_ENABLE INT2_INT
T0CON=%10000010
T1CON=%1
' Inverter startup
high PORTD.5
HIGH PORTE.0
pause 1000
' Turn LCD on and write custom characters to CGRAM
LCDOUT $fe,$40,$0,$4,$e,$15,$4,$4,$4,$0
LCDOUT $fe,$48,$0,$4,$4,$4,$15,$e,$4,$0
LCDOUT $fe,1
' Main program loop
mainlp:
' Start ADC conversion
ADCON0.1=%1
WHILE ADCON0.1=%1:WEND
' Store ADC results
isense.HighByte=ADRESH
isense.LowByte=ADRESL
usense.HighByte=ADRESH
usense.LowByte=ADRESL
tsense.HighByte=ADRESH
tsense.LowByte=ADRESL
potsense.HighByte=ADRESH
potsense.LowByte=ADRESL
' Security fault verifications
if isense**19218>imax then fault=1
if usense>820 then fault=2
if tsense<330 then fault=3
' Security fault tripping
IF fault>0 then goto faultsub
' Brake signal generation
if usense>770 then PORTD.7=%1
' Run
if run=%1 then
IF flag1=%0 then PWMCON0.6=%1:HIGH PORTD.6:flag1=%1
endif
' Stop
if run=%0 then
if flag1=%0 then PWMCON0=%0:LOW PORTD.6:flag1=%1
ENDIF
' FWD rotation
if rot=%1 then
if flag2=%0 THEN ustep=29:vstep=59:wstep=89:write 0,rot:flag2=%1
endif
' RWD rotation
if rot=%0 then
if flag2=%0 THEN ustep=89:vstep=59:wstep=29:write 0,rot:flag2=%1
endif
' - button
Button PORTB.6,1,128,32,b,0,ret
if menu=%0 THEN menupos=menupos-1
ret:
' + button
Button PORTB.7,1,128,32,b1,0,ret1
if menu=%0 THEN menupos=menupos+1
ret1:
' Run/stop button
if PORTD.2=%1 then
if run=%0 and menupos<6 and flag3=%0 then run=%1:flag1=%0:flag3=%1
if run=%1 and flag3=%0 then run=%0:flag1=%0:flag3=%1
endif
' FWD/RWD button
if PORTD.3=%1 then
if rot=%0 and run=%0 and flag4=%0 then rot=%1:flag2=%0:flag4=%1
if rot=%1 and run=%0 and flag4=%0 then rot=%0:flag2=%0:flag4=%1
endif
' Menu/OK button
if PORTD.4=%1 then
if menu=%0 and run=%0 and menupos>5 and flag5=%0 then menu=%1:flag5=%1
if menu=%1 and flag5=%0 then menu=%0:flag5=%1
endif
' Buttons released state
if PORTD.2=0 then flag3=0
if PORTD.3=0 then flag4=0
IF PORTD.4=0 then flag5=0
' LCD first line writing
if rot=%1 then LCDOUT $fe,$2,"+"
if rot=%0 then LCDOUT $fe,$2,"-"
LCDOUT DEC freq DIG 3,DEC freq DIG 2,DEC freq DIG 1,".",DEC freq DIG 0,"Hz"
IF run=%1 then LCDOUT rep 32\5,"RUN"
IF run=%0 then LCDOUT rep 32\4,"STOP"
' Inverter menu (LCD second line writing)
select case menupos
' Menu limits
if menupos<1 then menupos=1
if menupos>10 then menupos=10
if run=%1 then
if menupos>5 then menupos=5
endif
' Current sensing submenu
CASE 1
isense=isense**19218
lcdout $fe,$c0,$1,$20,"1 ISENS: ",DEC isense DIG 2,DEC isense DIG 1,".",DEC isense DIG 0,"A"
' Voltage sensing submenu
case 2
usense=usense**32030
lcdout $fe,$c0,$1,$0,"2 USENS: ",DEC3 usense,"V",32
' Temperature sensing submenu
case 3
tsense=(tsense-1023)/7
lcdout $fe,$c0,$1,$0,"3 TEMP: ",DEC tsense DIG 1,DEC tsense DIG 0,$df,"C",rep $20\2
' Last fault reading submenu
case 4
lcdout $fe,$c0,$1,$0,"4 LASTFAULT: ",DEC1 lastf
' Firmware reading submenu
case 5
IF run=%1 then
lcdout $fe,$c0,$1,$20,"5 FW: V2011.00"
else
lcdout $fe,$c0,$1,$0,"5 FW: V2011.00"
endif
' Maximum frequency adjust submenu
case 6
if menu=%1 then
Lcdout $fe,$c0,$3e,$3e,"A MAX: ",DEC maxfreq DIG 3,DEC maxfreq DIG 2,DEC maxfreq DIG 1,".",DEC maxfreq DIG 0,"Hz"
Button PORTB.6,1,128,4,b,0,ret2
if maxfreq>minfreq THEN maxfreq=maxfreq-1
ret2:
Button PORTB.7,1,128,4,b1,0,ret3
if maxfreq<1200 THEN maxfreq=maxfreq+1
ret3:
flag6=%0
else
lcdout $fe,$c0,$1,$0,"A MAX: ",DEC maxfreq DIG 3,DEC maxfreq DIG 2,DEC maxfreq DIG 1,".",DEC maxfreq DIG 0,"Hz"
IF flag6=%0 then write 1,maxfreq.highbyte:write 2,maxfreq.lowbyte:flag6=%1
endif
' Minimum frequency adjust submenu
case 7
if menu=%1 then
Lcdout $fe,$c0,$3e,$3e,"B MIN: ",DEC minfreq DIG 3,DEC minfreq DIG 2,DEC minfreq DIG 1,".",DEC minfreq DIG 0,"Hz"
Button PORTB.6,1,128,4,b,0,ret4
if minfreq>10 THEN minfreq=minfreq-1
ret4:
Button PORTB.7,1,128,4,b1,0,ret5
if minfreq<maxfreq THEN minfreq=minfreq+1
ret5:
flag6=%0
else
lcdout $fe,$c0,$1,$0,"B MIN: ",DEC minfreq DIG 3,DEC minfreq DIG 2,DEC minfreq DIG 1,".",DEC minfreq DIG 0,"Hz"
IF flag6=%0 then write 3,minfreq.highbyte:write 4,minfreq.lowbyte:flag6=%1
endif
' Current trip adjust submenu
case 8
if menu=%1 then
Lcdout $fe,$c0,$3e,$3e,"C ITRIP: ",DEC imax DIG 2,DEC imax DIG 1,".",DEC imax DIG 0,"A"
Button PORTB.6,1,128,8,b,0,ret6
if imax>0 THEN imax=imax-1
ret6:
Button PORTB.7,1,128,8,b1,0,ret7
if imax<150 THEN imax=imax+1
ret7:
flag6=%0
else
lcdout $fe,$c0,$1,$0,"C ITRIP: ",DEC imax DIG 2,DEC imax DIG 1,".",DEC imax DIG 0,"A"
IF flag6=%0 then write 5,imax:flag6=%1
endif
' PWM carrier frequency adjust submenu
case 9
if menu=%1 then
Lcdout $fe,$c0,$3e,$3e,"D PWMFREQ: ",DEC1 pwmf,rep $20\2
Button PORTB.6,1,128,32,b,0,ret8
if pwmf>1 THEN pwmf=pwmf-1
ret8:
Button PORTB.7,1,128,32,b1,0,ret9
if pwmf<5 THEN pwmf=pwmf+1
ret9:
flag6=%0
else
lcdout $fe,$c0,$1,$0,"D PWMFREQ: ",DEC1 pwmf,rep $20\2
IF flag6=%0 then write 6,pwmf:gosub pwmsub:flag6=%1
endif
' Reset all settings submenu
case 10
if menu=%1 then
if flag7=%0 then
rot=%1:write 0,rot
maxfreq=500:write 1,maxfreq.highbyte:write 2,maxfreq.lowbyte
minfreq=10:write 3,minfreq.highbyte:write 4,minfreq.lowbyte
imax=150:write 5,imax
pwmf=3:write 6,pwmf
Lcdout $fe,$c0,$3e,$3e,"E RESET? OK",REP $20\3:flag7=%1
endif
endif
if menu=%0 then lcdout $fe,$c0,$20,$0,"E RESET?",rep $20\6:flag7=%0
end select
goto mainlp
' PWM update interrupt (Timer 1)
pwmint:
' Timer management
T1CON.0=%0
copy.HighByte=TMR1H
copy.LowByte=TMR1L
copy=copy+reload
TMR1H=copy.HighByte
TMR1L=copy.LowByte
T1CON.0=%1
' PWM U phase calculation
uduty=sine[ustep]
uduty=(uduty<<res)**amp
' PWM V phase calculation
vduty=sine[vstep]
vduty=(vduty<<res)**amp
' PWM W phase calculation
wduty=sine[wstep]
wduty=(wduty<<res)**amp
' PWM U, V and W update
PDC0H=uduty.highbyte
PDC0L=uduty.lowbyte
PDC1H=vduty.highbyte
PDC1L=vduty.lowbyte
PDC2H=wduty.highbyte
PDC2L=wduty.lowbyte
' Phase angle calculation
@ decf _ustep,1
@ decf _vstep,1
@ decf _wstep,1
' Phase angle reinitialization
if ustep=0 then ustep=89
if vstep=0 then vstep=89
if wstep=0 then wstep=89
@ INT_RETURN
' PWM calculation interrupt (Timer 0)
calcint:
' Recalculations
if flag=%1 THEN
' Reload timer calculation
dum=dum1*dum2
reload=Div32 freq
reload=(65535-reload)+8
' U/F calculation
if freq<=500 then
amp=(freq*131)+35
ELSE
AMP=65535
ENDIF
flag=%0
ENDIF
' Frequency reference control by potentiometer
potsense=((potsense<<6)**maxfreq)+5
if potsense<>freq then freq=potsense:flag=%1
' Frequency limits
if freq<minfreq then freq=minfreq
if freq>maxfreq then freq=maxfreq
@ INT_RETURN
' PWM carrier frequency configuration subroutine
pwmsub:
if pwmf=1 then PTPERH=$f:PTPERL=$ff:res=6
if pwmf=2 then PTPERH=$7:PTPERL=$ff:res=5
if pwmf=3 then PTPERH=$3:PTPERL=$ff:res=4
if pwmf=4 then PTPERH=$1:PTPERL=$ff:res=3
if pwmf=5 then PTPERH=$0:PTPERL=$ff:res=2
return
' IPM fault interrupt
faultint:
fault=4
goto faultsub
@ INT_RETURN
' Emergency stop interrupt
stopint:
fault=5
goto faultsub
@ INT_RETURN
' Inverter fault subroutine
faultsub:
' Emergency stop of the inverter
PWMCON0=%0
T1CON.0=%0
LOW PORTD.5
low PORTD.6
low PORTD.7
low PORTE.0
write 7,fault
' Disable interrupts
@ INT_DISABLE TMR0_INT
@ INT_DISABLE TMR1_INT
@ INT_DISABLE INT1_INT
@ INT_DISABLE INT2_INT
' LCD fault display
lcdout $fe,$2,"FAULT!",rep $20\10
lcdout $fe,$c0,"CODE: ",dec fault,rep $20\9
' Fault LED blink loop
faultlp:
HIGH PORTE.1
PAUSE 500
LOW PORTE.1
pause 500
goto faultlp
The sine table :
' Sine table (4 degrees/step, 90*4=360 degrees)
sine VAR byte[90]
sine[0]=128
sine[1]=137
sine[2]=146
sine[3]=155
sine[4]=163
sine[5]=172
sine[6]=180
sine[7]=188
sine[8]=196
sine[9]=203
sine[10]=210
sine[11]=217
sine[12]=223
sine[13]=229
sine[14]=234
sine[15]=239
sine[16]=243
sine[17]=247
sine[18]=250
sine[19]=252
sine[20]=254
sine[21]=255
sine[22]=255
sine[23]=255
sine[24]=255
sine[25]=254
sine[26]=252
sine[27]=250
sine[28]=247
sine[29]=243
sine[30]=239
sine[31]=234
sine[32]=229
sine[33]=223
sine[34]=217
sine[35]=210
sine[36]=203
sine[37]=196
sine[38]=188
sine[39]=180
sine[40]=172
sine[41]=163
sine[42]=155
sine[43]=146
sine[44]=137
sine[45]=128
sine[46]=119
sine[47]=110
sine[48]=101
sine[49]=93
sine[50]=84
sine[51]=76
sine[52]=68
sine[53]=60
sine[54]=53
sine[55]=46
sine[56]=39
sine[57]=33
sine[58]=27
sine[59]=22
sine[60]=17
sine[61]=13
sine[62]=9
sine[63]=6
sine[64]=4
sine[65]=2
sine[66]=1
sine[67]=0
sine[68]=0
sine[69]=1
sine[70]=2
sine[71]=4
sine[72]=6
sine[73]=9
sine[74]=13
sine[75]=17
sine[76]=22
sine[77]=27
sine[78]=33
sine[79]=39
sine[80]=46
sine[81]=53
sine[82]=60
sine[83]=68
sine[84]=76
sine[85]=84
sine[86]=93
sine[87]=101
sine[88]=110
sine[89]=119
And if you have some ideas and suggestions to improve the program... it will be good.
Thanks. :)