PDA

View Full Version : ProblemwithPWMfrequency



sangaboy
- 27th February 2012, 18:21
Hi to every one
My aim is to generate 5kHZ SPWM so that when filtered will give sine waves(50hz). I havebeen reading different application manual and PIC16877 and Pic16f777 datashets for almost two days but I 'm still in darkness the problem comes for that frequency my duty cycle will have 10bit resolution. here are the question I have and the code I wrote, any one can help me.

(1) I simulate it using pic16f877 but I dont see any output


define OSC 4
Wsave var byte $70system
Wsave1 var byte $A0system
Wsave2 var byte $120system
Wsave3 var byte $1A0system


'pointer for phase one in sinearray
'pointer for phase two in sine array
ADCON0 = %00000000
ADCON1 = %00000000
LED1 VAR PORTB.1

TRISB = %11111101
TRISC = %11111001 'PMW output for CCP1 AND CCP2
TRISA = %11111111
PR2 = 199 'set for 5Khz HPWM
CCP1CON = %00001100 'set CCP1 for PWM OPERATION
CCP2CON = %00001100 'set CCP2 for PWM OPERATION
T2CON = %00000100 'TIMER2ON and prescale of 1:1
index var byte
temp var word
timerone var word
INCLUDE "DT_INTS-14.bas" ; Base Interrupt System emp
ASM

INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler TMR1_INT, _test, ASM, yes
endm
INT_CREATE ; Creates the interrupt processor
ENDASM

T1CON = 000001 ; Prescaler = 1;1, TMR1 ON
@ INT_ENABLE TMR1_INT ; Enable Timer 1 Interrupts

timerone = 64980 ;gives about 50 htz sine

test:
T1CON = 000000 'stop the timer
TMR1L = timerone.byte0 'reload the timer
TMR1H = timerone.byte1
T1CON = 000001 ' start the timer
gosub display
CCP1CON.4 = Temp.0 ' bit 0
CCP1CON.5 = Temp.1 ' bit 1
CCPR1L = Temp>>2 'Bit 2-7

display:
lookup2 index[115,102,90,79,70,62,57,53,52,53,57,62,70,79,90,102 ,115,128,141,154,166,177,186,194,199,203,204,203,1 99,194,186,177,166,154,141,128],temp
return

index=index+1
if index =36 then index =0
@ INT_RETURN


please any one one help me to solve this problem

thankx

HenrikOlsson
- 27th February 2012, 21:23
Hi,
Several things.
1) There is no "main loop" in the program so the execution falls thru into the interrtupt handler and then it hits the @INT RETURN macro which makes it return to what?

2) You have the display subroutine located in the middle of your code. When you're using subroutines you need to make sure that the program can't "reach" them without actually being called by a GOSUB. In your program the display subroutine gets exectued one time when called by the GOSUB (which is all OK) but then it gets executed again after you've loaded the CCP1 registers and since there's a RETURN at the end of the subroutine it jumps to somewhere it shouldn't.

3) You have the interrupt handler declared as ASM even though you're using PBP statements in the handler. I've said this to you in one of your other threads covering the same topic: Do NOT do that if you don't know what you're doing. If you don't understand WHY you can either read up on it here on the forum but if you don't care about the details simply follow the rules given: If the handler is in PBP then declare it as type PBP - not ASM.

/Henrik.

sangaboy
- 28th February 2012, 13:11
Hi every one

Thanks HenrikOlsson for your coments on this code. I worked on your coments and do some monifications, here is challenge I faced
(1) I declare my handler as PBP type when I compile the code gives the following error WARNING: Unable to open INCLUDE file REENTERPBP-14.BAS although I include that file in the compilation folder why is this error?

(2) I'm confusing why the program declared as ASM type having PBP statement and the Label does not have an underscore before it gives error while that declared as ASM type having PBP statement and the Label have an underscore before it gives gives NO error.But accorgni to Darrel PBP type label should have un underscore before it.

code


define OSC 4
Wsave var byte $70system
Wsave1 var byte $A0system
Wsave2 var byte $120system
Wsave3 var byte $1A0system


'pointer for phase one in sinearray
'pointer for phase two in sine array
ADCON0 = %00000000
ADCON1 = %00000000
LED1 VAR PORTB.1

TRISB = %11111101
TRISC = %11111001 'PMW output for CCP1 AND CCP2
TRISA = %11111111
PR2 = 199 'set for 5Khz HPWM
CCP1CON = %00001100 'set CCP1 for PWM OPERATION
CCP2CON = %00001100 'set CCP2 for PWM OPERATION
T2CON = %00000100 'TIMER2ON and prescale of 1:1
index var byte
temp var word
timerone var word
INCLUDE "DT_INTS-14.bas" ; Base Interrupt System emp
INCLUDE "ReEnterPBP-14.bas"
ASM

INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler TMR1_INT, _TEST, PBP, yes
endm
INT_CREATE ; Creates the interrupt processor
ENDASM

T1CON = 000001 ; Prescaler = 1;1, TMR1 ON
@ INT_ENABLE TMR1_INT ; Enable Timer 1 Interrupts

timerone = 64980 ;gives about 50 htz sine
Main:
PAUSE 5

GOTO Main
TEST:
T1CON = 000000 'stop the timer
TMR1L = timerone.byte0 'reload the timer
TMR1H = timerone.byte1
T1CON = 000001 ' start the timer
gosub display
CCP1CON.4 = Temp.0 ' bit 0
CCP1CON.5 = Temp.1 ' bit 1
CCPR1L = Temp>>2 'Bit 2-7
index=index+1
if index =36 then index =0

@ INT_RETURN

display:
lookup index,[115,102,90,79,70,62,57,53,52,53,57,62,70,79,90,102 ,115,128,141,154,166,177,186,194,199,203,204,203,1 99,194,186,177,166,154,141,128],temp

return 'return to the subroutine
return 'return to the original GOSUB



thankx

HenrikOlsson
- 28th February 2012, 13:59
1) As far as I can see the file is called ReEnterPBP.bas. For some reason you're trying to include ReEnterPBP-14.bas.

2) The compiler (PBP) adds an underscore in front of all variables and labels so the label Test becomes _Test in the compiled program. This is so that any variables and labels you create does not interfere with whatever system variables PBP creates internally. The interrupt declaration, ie this part...

ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler TMR1_INT, _TEST, PBP, yes
endm
INT_CREATE ; Creates the interrupt processor
ENDASM

...is, as you can see by ASM/ENDASM directives assembly code which is passed directly to the assembler. So the label needs (_test) needs to have the underscore infront of it here because once the assembler is invoked your Test: label is called _Test. I hope that makes sense.

sangaboy
- 28th February 2012, 15:21
thankx for the explaination about underscore I understood it very well why under score. But your statement below is not clear to me
"As far as I can see the file is called ReEnterPBP.bas. For some reason you're trying to include ReEnterPBP-14.bas".
thankx

HenrikOlsson
- 28th February 2012, 15:30
Hi,
If you go to Darrel's website (http://darreltaylor.com/DT_INTS-14/downloads.htm) and download the .zip file for DT_INTS-14 (http://darreltaylor.com/DT_INTS-14/DT_INTS-14_V110.zip) you get two (2) files. One is called DT_INTS-14.bas and the other is called ReEnterPBP.bas. In your program you are correctly icluding DT_INTS-14.bas but you are, incorrectly trying to include a file called ReEnterPBP-14.bas - your code:

INCLUDE "DT_INTS-14.bas" ; Base Interrupt System emp
INCLUDE "ReEnterPBP-14.bas" '<-----Here, you have the wrong filename.
See, the file your're TRYING to include is ReEnterPBP-14.bas but the file is called ReEnterPBP.bas (if you haven't renamed it in which case I don't what the problem is).

/Henrik.

sangaboy
- 28th February 2012, 16:23
Thankx it compile fine but the output is stationary. I 'm confusing why is it.I attach simulation of the output as seen from ISIS



define OSC 4
Wsave var byte $70system
Wsave1 var byte $A0system
Wsave2 var byte $120system
Wsave3 var byte $1A0system
ADCON0 = %00000000
ADCON1 = %00000000
LED1 VAR PORTB.1

TRISB = %11111101
TRISC = %11111001 'PMW output for CCP1 AND CCP2
TRISA = %11111111
PR2 = 199 'set for 5Khz HPWM
CCP1CON = %00001100 'set CCP1 for PWM OPERATION
CCP2CON = %00001100 'set CCP2 for PWM OPERATION
T2CON = %00000100 'TIMER2ON and prescale of 1:1
index var byte
temp var word
timerone var word
INCLUDE "DT_INTS-14.bas"
INCLUDE "ReEnterPBP.bas"
ASM

INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler TMR1_INT, _TEST, PBP, yes
endm
INT_CREATE ; Creates the interrupt processor
ENDASM

T1CON = 000001 ; Prescaler = 1;1, TMR1 ON
@ INT_ENABLE TMR1_INT ; Enable Timer 1 Interrupts

timerone = 64980 ;gives about 50 htz sine
Main:
PAUSE 5

GOTO Main
TEST:
T1CON = 000000 'stop the timer
TMR1L = timerone.byte0 'reload the timer
TMR1H = timerone.byte1
T1CON = 000001 ' start the timer
gosub display
CCP1CON.4 = Temp.0 ' bit 0
CCP1CON.5 = Temp.1 ' bit 1
CCPR1L = Temp>>2 'Bit 2-7
index=index+1
if index =36 then index =0

@ INT_RETURN[CODE]

display:
lookup index,[115,102,90,79,70,62,57,53,52,53,57,62,70,79,90,102 ,115,128,141,154,166,177,186,194,199,203,204,203,1 99,194,186,177,166,154,141,128],temp

return 'return to the subroutine
return 'return to the original GOSUB

HenrikOlsson
- 28th February 2012, 17:06
Hi,
Not that I think it's a problem but why TWO returns in the subroutine? The execution will never get to the second one.

Are you sure that the output really IS "stationary", it's not just that you have the horisontal sweep set to fast?
Wrap the ISR in a LED1 = 1 and LED1 = 0 and sample PortB.1 too with your "scope", that way you'll see IF and and what frequency the interrupt ACTUALLY runs as well as how long it takes to execute.
With 4MHz crystal, PR2 set to 199 and prescaler set to 1:1 you should be getting 5kHz PWM but your "scope" (if I read it correctly) shows a period of 400us which means a PWM frequency is 2.5kHz, why is that?

sangaboy
- 29th February 2012, 15:29
Thankx HenrikOlsson for the comments I worked on on them

For what I know the gosub coment within subroutine takes two return. The first return will bring you back to the subroutine(TEST) and the second return will bring you to the original gosub comand if I'm not wrong.

I havebeen worked on the code for almost whole day I'm still getting the same output and I try know my interrupt frequency by Toggling PortB.1 the problem comes I cant see the square wave comes from that pin. here is code and output from ISIS.



define OSC 4
Wsave var byte $70system
Wsave1 var byte $A0system
Wsave2 var byte $120system
Wsave3 var byte $1A0system
ADCON0 = %00000000
ADCON1 = %00000000
LED1 VAR PORTB.1

TRISB = %11111101
TRISC = %11111001 'PMW output for CCP1 AND CCP2
TRISA = %11111111
PR2 = 199 'set for 5Khz HPWM
CCP1CON = %00001100 'set CCP1 for PWM OPERATION
CCP2CON = %00001100 'set CCP2 for PWM OPERATION
T2CON = %00000100 'TIMER2ON and prescale of 1:1
index var byte
temp var word
timerone var word
INCLUDE "DT_INTS-14.bas" ; Base Interrupt System
INCLUDE "ReEnterPBP.bas"
ASM

INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler TMR1_INT, _TEST, PBP, yes
endm
INT_CREATE ; Creates the interrupt processor
ENDASM

T1CON = 000001 ; Prescaler = 1;1, TMR1 ON
@ INT_ENABLE TMR1_INT ; Enable Timer 1 Interrupts

timerone = 64980 ;gives about 50 htz sine
Main:
PAUSE 5

GOTO Main

TEST:
T1CON = 000000 'stop the timer
TMR1L = timerone.byte0 'reload the timer
TMR1H = timerone.byte1
T1CON = 000001 ' start the timer
gosub display
CCP1CON.4 = Temp.0 ' bit 0
CCP1CON.5 = Temp.1 ' bit 1
CCPR1L = Temp>>2 'Bit 2-7
TOGGLE LED1
index=index+1
if index =36 then index =0


@ INT_RETURN

display:
lookup index,[115,102,90,79,70,62,57,53,52,53,57,62,70,79,90,102 ,115,128,141,154,166,177,186,194,199,203,204,203,1 99,194,186,177,166,154,141,128],temp

return 'return to the subroutine
return 'return to the original GOSUB



I don't understand why the output is 2.5Kh instead of 5khz

help me on that problems
thankx

HenrikOlsson
- 29th February 2012, 18:25
Hi,
No you need one RETURN at the end of the subroutine. That RETURN makes the code return to line after the GOSUB, the @INT_RETURN makes it return from the interrupt handler.

Are you sure you have the scope connected to the correct output?


The first thing you need to do i make sure that the PIC and that simulator of yours is running properly and that you're using it properly. Remove all the interrupt and PWM stuff and then make a simple program that just toggles that LED1 output. Connect your "scope" and make sure you can see the output toggle on the scope.

When and only when you have that working put the interrupt stuff back in but move the TOGGLE command to the interrupt handler - EXACTLY as shown here. (http://darreltaylor.com/DT_INTS-14/blinky.html) Don't try to add all your PWM stuff.

When and only when you can see that LED1 output toggling on the scope try adjusting the interrupt frequency and see if that works the way you want.

EDIT: Now make sure that you can setup and control the dutycycle of the PWM module in the main loop (still no interrupts). Just toggle the dutycycle between two values and make sure you can see that on the scope.

Now, when you have THAT working you are ready to start adding the PWM stuff.

Don't try to skip a step until you have the previous one working and understand why and how.

sangaboy
- 2nd March 2012, 15:32
Hi HenrikOlsson

(1) Thankx. I worked on the steps you told me and I manage to control my interrupt frequency which is (50*36=1800) for this frequency the time1 will be loaded with 64980 this value gives me (1667hz) which is the lowest frequency but the value 65080 gives me the frequency 1818. I think as you told me early the PBP tpyes take longer time compared to ASM types ,thankx for it and I deside to use the value which gives (1818hz).

(2)But sorry you are stastment below is not clear to me.
EDIT: Now make sure that you can setup and control the dutycycle of the PWM module in the main loop (still no interrupts). Just toggle the dutycycle between two values and make sure you can see that on the scope.

Thankx

HenrikOlsson
- 2nd March 2012, 16:47
2) I mean something simple like this:


Main:
Temp = 40
GOSUB UpdateDuty
Pause 500
Temp = 400
GOSUB UpdateDuty
Pause 500
GOTO Main

UpdateDuty:
CCP1CON.4 = Temp.0 ' bit 0
CCP1CON.5 = Temp.1 ' bit 1
CCPR1L = Temp>>2 'Bit 2-7
RETURN

This should switch the dutycycle between '40' and '400' att 500ms intervals which should be clearly visible on the "scope". Make sure you can do that before you try to move the PWM stuff to the ISR. Since you now know that is interrupt is firing properly and you can control the frequency all you need is to to move it back into the ISR.

You are making progress but the key is to take it slow and try to understand each step. When something doesn't work, solve one problem at a time and take it slow.

/Henrik.

sangaboy
- 3rd March 2012, 17:22
Thankx HenrikOlsson for the comments, and explaination to me

I have been worked on this code for the whole day but still I didi not get any output. The problem I faced is I don't get any output to the CCP1(TRISC<2>).I tryt to put led1 on main to measure the time I get it clear which is 1sec for each toggle which is true( 500+500)ms also I put led1 on UpdateDuty subroutine also I get clear a delay of 500ms to each toggle which is also true because UpdateDuty it is called aftter every 500ms. But I 'm confusing where is problem? And why is CCP1 does not output to (TRISC<2>)?.Here is the code.



PIC 16F877
define OSC 4

TRISC = %11111011
CCP1CON = %00001100
T2CON = %00000100
PR2 = 199 for 5khz
TRISB = %11111101
TRISA = %11111111
LED1 VAR PORTB.1
temp var word
Main:
Temp = 40
GOSUB UpdateDuty
Pause 500
Temp = 400
GOSUB UpdateDuty
Pause 500
TOGGLE LED1
GOTO Main
UpdateDuty:
CCP1CON.4 = Temp.0 ' bit 0
CCP1CON.5 = Temp.1 ' bit 1
CCPR1L = Temp>>2 'Bit 2-7
RETURN
end


Help me to solve this problem thankx.

HenrikOlsson
- 4th March 2012, 12:43
Hi,
I've tried the above code here and it works just fine. I don't have a 16F877 so I tried it on a 18F25K20, the dutycylce of PWM-signal changes just as expected - no problem.

I looked at the datasheet for the 16F877 and the CCP1 pin isn't multiplexed with any other functions so it should work. Have you tried this with real hardware or are you still messing around with the simulator? My guess is that you're measuring on the wrong pin or that you have that simulator of yours set up wrong or that the PWM module isn't simulated properly.

sangaboy
- 6th March 2012, 17:50
Thankx HenrikOlsson

True the problem was due to the simulator was not working properly .Now the code is working fine and I get the correct PWM frequency(5khz) after change the ISIS vasion Thankx for it. But I have the following problem of relating the dutycycle from the theory and that from picdatashetformural.

From theory (dutycycle=(Time-ON/period) for my case
case1: AS seen from the scope when I used the above fomural gives 1/2=0.5=50%

case2: As seen from the scope when I used the above fomural gives 0.1/2=0.05=5%

how these values(case1 and case2) can be related with 40 and 400 values

from pic16f877 datasheet PWM_dutycycle= CCPR1L:CCP1CON<5:4>*TOSC*(TMR2 prscale value)

I 'm confusing how can I relate the value from theory formular and that from datasheet to know that I get the correct results.

Help me to solve this problems because always these two case confusing me.


Thankx

HenrikOlsson
- 6th March 2012, 18:10
Hi,
I really hope you've learned something here....How much time have you (and I) wasted on that simulator by now? If you had put a PIC on a breadboard from the get go you'd be done by now.

As you know by now the PWM period ends when TMR2=PR2. So if you set the CCPR1L value to whatever you have PR2 set to you'll get 100% dutycycle (this assumes 1:1 prescaler). So, if PR2 is 200 then setting CCPR1L to 200 will give you 100% dutycycle, setting it to 50 will give you 25% dutycycle and so on. The two lowest significant bits (CCP1CON<5:4>) adds 2 bits (or 4 times if you will ) worth of resolution. So if you prefer you could say that a DutyVal of PR2*4=100%.

For example, DutyVal=800. Take the 2 low bits and stuff them CCP1CON5:4 and take the 8 high bits in stuff them in CCPR1L. If you take a close look at the 8 bits alone you'll see that it's the value 200.

/Henrik.

sangaboy
- 7th March 2012, 18:02
Thankx HenrikOlsson
I really appreciate your effort on this forum.

(1) sorry I understand you explaination very well on how dutycycle relate with value of PR2. one problem is that you statements below is not clear to me and why PR2*4=100%:
the two lowest significant bits (CCP1CON<5:4>) adds 2 bits (or 4 times if you will ) worth of resolution. So if you prefer you could say that a DutyVal of PR2*4=100%.
For example, DutyVal=800. Take the 2 low bits and stuff them CCP1CON5:4 and take the 8 high bits in stuff them in CCPR1L. If you take a close look at the 8 bits alone you'll see that it's the value 200.
a

(2)From what I know for 8bit resolution
CCP1CON.4 = duty.0
CCP1CON.5 = duty.1
CCPR1L = DUTY >> 2
that is means that 2bit (CCPICON<5:4>) and 6bit obtain after shifting right(divide by 4) duty value are combine to form 8bit resolution

What I want to know is that, if I used 10 bit resolution is that code here correct?

CCP1CON.4 = duty.0
CCP1CON.5 = duty.1
CCPR1L = DUTY
that is 2bit(CCPICON<5:4>) are combine with 8bit (CCPR1L)from duty value to form 10bit resolution.
thankx

HenrikOlsson
- 7th March 2012, 20:33
Hi,
I'm not sure how to explain this in any other way....
If you have a WORD sized variable with a 10bit value stored in it you take the two lower bits and put them in CCP1CON5:4. Then you shift the value to the right twice and then load the value to CCPR1L.

0000001100110010

Above, the value 818 is shown in binary. The first thing that you do is take the two lower bits (the ones in green) and load them to CCP1CON.4 and CCP1CON.5. Then you shift the value to the right twice which makes the two green bits "dissappear" and two "zeros" shifted in at the high end. The value now looks like this:

0000000011001100

Now you load the value (204) to CCPR1L. The code is just as it always been

DutyVal = 818
CCP1CON.4 = DutyVal.0 'Lowest significant bit
CCP1CON.5 = DutyVal.1
CCPR1L = DutyVal >> 2 ' Shift value to the right twice and move it to CCPR1L

You may remember that an instruction cycle is 4 clock cycles. Ie, when running with a 20MHz crystal the "execution speed" is 5Mhz. This is because there's 4 clock cycles to each instruction cycle. Normally TMR2, which is used for the PWM generation, is clocked at the instruction cycle rate but in PWM mode it gets concatenated with the 2 bit internal Q clock used to "derive" the f/4 clock. So in PWM mode you could think of TMR2 is a 10bit timer operating at 20Mhz (in this case). The 8 most significant bits of the timer is the TMR2 register and the two low significant bits are the internal 2 bit Q clock.

The value of this 10 bit TMR2 gets compared to the 10 bit value consisting of 8 bits in CCPR1L and 2 bits in CCP1CON.

It's all in the datasheet:
6331

Do you see the TMR2 register (8 bits) and the two bits of the Q clock? This forms the 10bit timer. Above that you have a comparator which compares the 10bit timer value with the 10 bit dutycycle value built up from CCPR1L and the two bits in CCP1CON. When there's a match the output goes low. CCPR1H buffers CCPR1L at the start of each cycle so that you can safely update CCPR1L at any time without disturbing the output.

May I suggest you also take a look at the PIC Midrange manual (http://ww1.microchip.com/downloads/en/devicedoc/33023a.pdf) and I'm sure there are multiple application notes on Microchips website describing the PWM generation in far more detail and far more accurately than I can.

/Henrik.

sangaboy
- 13th March 2012, 17:57
Hi HenrikOlsson
I have manage to combine the code,compile it successfully and get the correct PWM frequency(5khz) thanks for all.
(a) As you told me early the DutyVal of PR2*4=100% that means that my value of PR2=199 the DutyVal can vary within (0-796).One problem I have is in my lookup table the there is value greater than 796.What happen to this values greater than 796?

(b) Also I have read PIC Midrange manual(http://ww1.microchip.com/downloads/en/devicedoc/33023a.pdf) page 211 and 212 it says
(1) " If the PWM duty cycle value is longer than the PWM period, the CCPx pin will not be cleared. This allows a duty cycle of 100%".
(2) " Any value greater than 255 will result in a 100% duty cycle".
is this two reason cause some part of my wave form not to have a PWM frequency of 5khz? having a long off time
here is code and two phase PWM output



STEPCOUNT var byte
STEPCOUNT1 var byte

LED1 VAR PORTB.1

STEPCOUNT = 0 'pointer for phase one in sinearray
STEPCOUNT1 = 12 'pointer for phase two in sine array
ADCON0 = %00000000
ADCON1 = %00000000

TRISB = %11111101
TRISC = %11111001 'PMW output for CCP1 AND CCP2
TRISA = %11111111
TMR2 = 0
PR2 = 199 'generate 5khz 'set for 18Khz HPWM
CCP1CON = %00001100 'set CCP1 for PWM OPERATION
CCP2CON = %00001100 'set CCP2 for PWM OPERATION
T2CON = %00000100 'TIMER2ON and prescale of 1:1

sineval var byte[36]
sineval[0] = 512
sineval[1] = 583
sineval[2] = 652
sineval[3] = 717
sineval[4] = 775
sineval[5] = 825
sineval[6] = 866
sineval[7] = 896
sineval[8] = 915
sineval[9] = 921
sineval[10] =915
sineval[11] =896
sineval[12] =866
sineval[13] =825
sineval[14] =775
sineval[15] =716
sineval[16] =652
sineval[17] =583
sineval[18] =512
sineval[19] = 441
sineval[20] = 372
sineval[21] = 308
sineval[22] = 249
sineval[23] = 199
sineval[24] = 158
sineval[25] = 128
sineval[26] = 109
sineval[27] = 103
sineval[28] = 109
sineval[29] = 128
sineval[30] = 158
sineval[31] = 199
sineval[32] = 249
sineval[33] = 308
sineval[34] = 441
sineval[35] = 512

timerone var word
Temp var byte
Temp1 var byte
INCLUDE "DT_INTS-14.bas" ; Base Interrupt System emp
INCLUDE "ReEnterPBP.bas"

ASM

INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler TMR1_INT, _sine, PBP, yes
endm
INT_CREATE ; Creates the interrupt processor
ENDASM

T1CON = 000001 ; Prescaler = 1;1, TMR1 ON
@ INT_ENABLE TMR1_INT ; Enable Timer 1 Interrupts

timerone = 65080' gives1818hz interruptfrequency or about 50 htz sine
Main:
PAUSE 5

GOTO Main

'---[TMR1_INT - interrupt handler]------------------------------------------

sine:
T1CON = 000000 'stop the timer

TMR1L = timerone.byte0 'reload the timer
TMR1H = timerone.byte1
T1CON = 000001 ' start the timer


TeMP = sineval[STEPCOUNT]
CCP1CON.4 = Temp.0 ' bit 0
CCP1CON.5 = Temp.1 ' bit 1
CCPR1L = Temp >>2 'Bit 2-7

TeMP1 = sineval[STEPCOUNT1]
CCP2CON.4 = Temp1.0 ' bit 0
CCP2CON.5 = Temp1.1 ' bit 1
CCPR2L = Temp1 >>2 'Bit 2-7
TOGGLE LED1
stepcount = stepcount +1
stepcount1 = stepcount1 +1

if stepcount =36 then stepcount =0
if stepcount1 =36 then stepcount1 =12


@ INT_RETURN


Help to help me to solve this problems
thanks

HenrikOlsson
- 13th March 2012, 18:17
Hi,

One problem I have is in my lookup table the there is value greater than 796.What happen to this values greater than 796?
You answered your own question in (1) from the Midrange manual:

(1) " If the PWM duty cycle value is longer than the PWM period, the CCPx pin will not be cleared. This allows a duty cycle of 100%".
Any dutycycle value above 796 will result in 100% dutycycle. In other words your SIN-output will be distorted/clipped.


is this two reason cause some part of my wave form not to have a PWM frequency of 5khz? having a long off time
Don't think so, I'd expect it to stay at 100% but I may be wrong. However this isn't correct:


if stepcount =36 then stepcount =0
if stepcount1 =36 then stepcount1 =12

You can't restart at the 12th byte, that will make the second output miss 1/3 of the cycle. You start at the 12th byte to get the correct phase angle offset but you must restart at 0 once it reaches 36.

/Henrik.

sangaboy
- 14th March 2012, 14:53
Thanks HenrikOlsson for your information.But this look like is not clear to me. From what I now when stepcount1 =36 for 2nd phase then stepcount1=12 so as it start to the 12thbyte again because initially is declared as stepcount1=12.What confusing me is that initially in my declaration of variable stepcount1=12 why after one cylecle stepcount1 should declared as stepcount1=0.How can I archieve phase difference of 120 if stepcount=0 after one cylecle.

HenrikOlsson
- 14th March 2012, 17:58
Hi,
You have 36 values in you SIN table. To get a correct output you need each phase to cycle thru these 36 values. You get the phase difference by starting each phase 120° apart in the lookup table but from that point they will keep that phase difference if you reset the index pointer to 0 when they reach 36:
6342

If you don't reset it to 0 but instead keep restarting the second phase at the 12th value (like you're currently doing) the output will look something like this:

6343

Why? Because the second phase never "gets" the first 12 values of the lookup table so the output gets A) distorted and B) of another frequency since it doesn't contain the same number of "samples" as the the first phase.

Thinking even further and adding the third phase, starting at the 24th value keep restarting at 24 the output would look something like:
6344

I hope you see that the above is not correct and that you understand WHY it's not correct.



Using your lookup table, starting the pointers at 0, 12 and 24 and restarting them all at 0 when they reach 36 the output looks like:
6345
Which I think is more inline with what you're after, isn't it?

Now, the waveform is distorted because you have the value 512 as the first AND as the last the value in the table which means that you'll get a dutycycle of 512 for two "samples" in a row. That is where th flat spot in the wave form is comming from.

/Henrik.

sangaboy
- 15th March 2012, 21:28
Hi HenrikOlsson

Now Inderstand why stepcount1 should restart to zero.
(1) But I have been working on the code and and modify my look up table as you told me about the first value and the last value, but the problem of flat spot still remaing I didn't understand why is this?
(2)If I want to make acertain value of dutycylecle maximum (specific range of variation) let say(0- 80)% or (0-75%) should I do in the look up table or modify the formular?
formular : ((sin(degree*pi/180)+1) /2)*1023 for 10 bit resolution.


help me to solve this problems

Thanks

HenrikOlsson
- 16th March 2012, 06:12
Hi,
1) Can't help without seeing the values.
2) Not sure I understand what the problem is.... If you want a certain maximum dutycycle then simply rescale the values before storing them in the lookuptable (change the formula to produce a table with lower values). If you want to rescale at runtime then you need to perform the math in the PIC. Retrieve the "original" value, rescale, and output.

/Henrik.

sangaboy
- 16th March 2012, 07:41
Hi HenrikOlsson
1) Can't help without seeing the values.
Here is the values


Wsave var byte $70system
Wsave1 var byte $A0system
Wsave2 var byte $120system
Wsave3 var byte $1A0system

STEPCOUNT var byte
STEPCOUNT1 var byte

LED1 VAR PORTB.1

STEPCOUNT = 0 'pointer for phase one in sinearray
STEPCOUNT1 = 12 'pointer for phase two in sine array
ADCON0 = %00000000
ADCON1 = %00000000

TRISB = %11111101
TRISC = %11111001 'PMW output for CCP1 AND CCP2
TRISA = %11111111
TMR2 = 0
PR2 = 199 'generate 5khz 'set for 18Khz HPWM
CCP1CON = %00001100 'set CCP1 for PWM OPERATION
CCP2CON = %00001100 'set CCP2 for PWM OPERATION
T2CON = %00000100 'TIMER2ON and prescale of 1:1

sineval var byte[36]
sineval[0] = 512
sineval[1] = 583
sineval[2] = 652
sineval[3] = 717
sineval[4] = 775
sineval[5] = 825
sineval[6] = 866
sineval[7] = 896
sineval[8] = 915
sineval[9] = 921
sineval[10] =915
sineval[11] =896
sineval[12] =866
sineval[13] =825
sineval[14] =775
sineval[15] =716
sineval[16] =652
sineval[17] =583
sineval[18] =512
sineval[19] = 441
sineval[20] = 372
sineval[21] = 308
sineval[22] = 249
sineval[23] = 199
sineval[24] = 158
sineval[25] = 128
sineval[26] = 109
sineval[27] = 103
sineval[28] = 109
sineval[29] = 128
sineval[30] = 158
sineval[31] = 199
sineval[32] = 249
sineval[33] = 308
sineval[34] = 372
sineval[35] = 441

timerone var word
Temp var byte
Temp1 var byte
INCLUDE "DT_INTS-14.bas" ; Base Interrupt System emp
'INCLUDE "ReEnterPBP.bas"

ASM

INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler TMR1_INT, _sine, ASM, yes
endm
INT_CREATE ; Creates the interrupt processor
ENDASM

T1CON = 000001 ; Prescaler = 1;1, TMR1 ON
@ INT_ENABLE TMR1_INT ; Enable Timer 1 Interrupts

timerone = 65080' gives1818hz nterruptfrequency or about 50 htz sine
Main:
PAUSE 5

GOTO Main

'---[TMR1_INT - interrupt handler]------------------------------------------

sine:
T1CON = 000000 'stop the timer

TMR1L = timerone.byte0 'reload the timer
TMR1H = timerone.byte1
T1CON = 000001 ' start the timer


TeMP = sineval[STEPCOUNT]
CCP1CON.4 = Temp.0 ' bit 0
CCP1CON.5 = Temp.1 ' bit 1
CCPR1L = Temp >>2 'Bit 2-7

TeMP1 = sineval[STEPCOUNT1]
CCP2CON.4 = Temp1.0 ' bit 0
CCP2CON.5 = Temp1.1 ' bit 1
CCPR2L = Temp1 >>2 'Bit 2-7
TOGGLE LED1
stepcount = stepcount +1
stepcount1 = stepcount1 +1

if stepcount =36 then stepcount =0
if stepcount1 =36 then stepcount1 =0


@ INT_RETURN

HenrikOlsson
- 16th March 2012, 07:54
Hi,
Here's three cycles with the values from you last post.
6348

What is that you think is wrong with it? I don't see it...

Demon
- 23rd March 2012, 01:46
He checks for 36, shouldn't it be 35?

Robert

ScaleRobotics
- 23rd March 2012, 02:11
He checks for 36, shouldn't it be 35?


No, after completing step 35, it increments, then it does a = 36 check. If it = 36, it goes back to step 0.

Demon
- 23rd March 2012, 12:36
Right, I forgot to check when the step was incremented, argh, and that's basic debugging procedure too (must be going senile).

Demon
- 23rd March 2012, 13:15
Could the length of PAUSE be an issue?

http://www.picbasic.co.uk/forum/showthread.php?t=1853

Would placing PAUSE 1 within a loop make a difference?

What about using microseconds instead of milliseconds?

There's a minimum delay in microseconds in the PBP manual, but I don't see oscillator setting in that last code.

Robert

sangaboy
- 26th March 2012, 11:10
No change even if the pause 1, what I want to ask is the values in the look table greater than 255 may affect the sinwave and cause the signal to be distorted?. Can any one simulates the code and see the effect. Why the output look like this because I have try to eliminate the problem of flat spot for almost 4days but the problem still exit even although I try to edit my look table as HenrikOlsson told me about the value 512 ).



define OSC 4
Wsave var byte $70system
Wsave1 var byte $A0system
Wsave2 var byte $120system
Wsave3 var byte $1A0system

STEPCOUNT var byte
STEPCOUNT1 var byte

LED1 VAR PORTB.1

STEPCOUNT = 0 'pointer for phase one in sinearray
STEPCOUNT1 = 12 'pointer for phase two in sine array
ADCON0 = %00000000
ADCON1 = %00000000

TRISB = %11111101
TRISC = %11111001 'PMW output for CCP1 AND CCP2
TRISA = %11111111
TMR2 = 0
PR2 = 199 'generate 5khz 'set for 18Khz HPWM
CCP1CON = %00001100 'set CCP1 for PWM OPERATION
CCP2CON = %00001100 'set CCP2 for PWM OPERATION
T2CON = %00000100 'TIMER2ON and prescale of 1:1

sineval var byte[36]
sineval[0] = 512
sineval[1] = 583
sineval[2] = 652
sineval[3] = 717
sineval[4] = 775
sineval[5] = 825
sineval[6] = 866
sineval[7] = 896
sineval[8] = 915
sineval[9] = 921
sineval[10] =915
sineval[11] =896
sineval[12] =866
sineval[13] =825
sineval[14] =775
sineval[15] =716
sineval[16] =652
sineval[17] =583
sineval[18] =512
sineval[19] = 441
sineval[20] = 372
sineval[21] = 308
sineval[22] = 249
sineval[23] = 199
sineval[24] = 158
sineval[25] = 128
sineval[26] = 109
sineval[27] = 103
sineval[28] = 109
sineval[29] = 128
sineval[30] = 158
sineval[31] = 199
sineval[32] = 249
sineval[33] = 308
sineval[34] = 372
sineval[35] = 441

timerone var word
Temp var byte
Temp1 var byte
INCLUDE "DT_INTS-14.bas" ; Base Interrupt System emp
'INCLUDE "ReEnterPBP.bas"

ASM

INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler TMR1_INT, _sine, ASM, yes
endm
INT_CREATE ; Creates the interrupt processor
ENDASM

T1CON = 000001 ; Prescaler = 1;1, TMR1 ON
@ INT_ENABLE TMR1_INT ; Enable Timer 1 Interrupts

timerone = 65080' gives1818hz nterruptfrequency or about 50 htz sine
Main:
PAUSE 1

GOTO Main

'---[TMR1_INT - interrupt handler]------------------------------------------

sine:
T1CON = 000000 'stop the timer

TMR1L = timerone.byte0 'reload the timer
TMR1H = timerone.byte1
T1CON = 000001 ' start the timer


TeMP = sineval[STEPCOUNT]
CCP1CON.4 = Temp.0 ' bit 0
CCP1CON.5 = Temp.1 ' bit 1
CCPR1L = Temp >>2 'Bit 2-7

TeMP1 = sineval[STEPCOUNT1]
CCP2CON.4 = Temp1.0 ' bit 0
CCP2CON.5 = Temp1.1 ' bit 1
CCPR2L = Temp1 >>2 'Bit 2-7
TOGGLE LED1
stepcount = stepcount +1
stepcount1 = stepcount1 +1

if stepcount =36 then stepcount =0
if stepcount1 =36 then stepcount1 =0


@ INT_RETURN

Acetronics2
- 26th March 2012, 14:39
Hi,

Do not trust in Proteus/Isis ...

I sometimes have some VERY funny results when it perfectly works in real life ... :angel:

" lots of examples available " ... especially when schemes are mixing analogic and digital !!!

Alain

Darrel Taylor
- 26th March 2012, 15:12
sineval var byte[36]
sineval[0] = 512
sineval[1] = 583
...

The array should be of WORDs if you want it to hold values greater than 255.

PROTEUS Rules!!

HenrikOlsson
- 26th March 2012, 15:23
What Darrel said.

AND

In a post made March 13th:

You answered your own question in (1) from the Midrange manual:

(1) " If the PWM duty cycle value is longer than the PWM period, the CCPx pin will not be cleared. This allows a duty cycle of 100%".


Any dutycycle value above 796 will result in 100% dutycycle. In other words your SIN-output will be distorted/clipped.

You have several values larger than 796 (4*199 (which is what you have PR2 set to, remember we've been thru this)) in your lookuptable so you are "overdriving" the dutycycle register and "clipping" will occur.

/Henrik.

sangaboy
- 27th March 2012, 17:58
Hi to all
I tried to modify the code according to Darrel Taylor and HenrikOlsson comments but the problem still exits, let me put in real hardware and see what happen.
And here is modified code but the output is still like that posted in the previous post.


define OSC 4
Wsave var byte $70system
Wsave1 var byte $A0system
Wsave2 var byte $120system
Wsave3 var byte $1A0system

STEPCOUNT var byte
STEPCOUNT1 var byte

LED1 VAR PORTB.1

STEPCOUNT = 0 'pointer for phase one in sinearray
STEPCOUNT1 = 12 'pointer for phase two in sine array
ADCON0 = %00000000
ADCON1 = %00000000

TRISB = %11111101
TRISC = %11111001 'PMW output for CCP1 AND CCP2
TRISA = %11111111
TMR2 = 0
PR2 = 199 'generate 5khz 'set for 18Khz HPWM
CCP1CON = %00001100 'set CCP1 for PWM OPERATION
CCP2CON = %00001100 'set CCP2 for PWM OPERATION
T2CON = %00000100 'TIMER2ON and prescale of 1:1

sineval var word[36]
sineval[0] = 512
sineval[1] = 556
sineval[2] = 599
sineval[3] = 640
sineval[4] = 676
sineval[5] = 707
sineval[6] = 733
sineval[7] = 752
sineval[8] = 763
sineval[9] = 767
sineval[10] =763
sineval[11] =752
sineval[12] =733
sineval[13] =707
sineval[14] =676
sineval[15] =640
sineval[16] =599
sineval[17] =556
sineval[18] =512
sineval[19] =468
sineval[20] =425
sineval[21] =385
sineval[22] =348
sineval[23] =317
sineval[24] =291
sineval[25] =272
sineval[26] =261
sineval[27] =257
sineval[28] =261
sineval[29] =272
sineval[30] = 291
sineval[31] = 317
sineval[32] = 348
sineval[33] = 385
sineval[34] = 425
sineval[35] = 468

timerone var word
Temp var byte
Temp1 var byte
INCLUDE "DT_INTS-14.bas" ; Base Interrupt System emp
'INCLUDE "ReEnterPBP.bas"

ASM

INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler TMR1_INT, _sine, PBP, yes
endm
INT_CREATE ; Creates the interrupt processor
ENDASM

T1CON = 000001 ; Prescaler = 1;1, TMR1 ON
@ INT_ENABLE TMR1_INT ; Enable Timer 1 Interrupts

timerone = 65080' gives1818hz nterruptfrequency or about 50 htz sine
Main:
PAUSE 5

GOTO Main

'---[TMR1_INT - interrupt handler]------------------------------------------

sine:
T1CON = 000000 'stop the timer

TMR1L = timerone.byte0 'reload the timer
TMR1H = timerone.byte1
T1CON = 000001 ' start the timer


TeMP = sineval[STEPCOUNT]
CCP1CON.4 = Temp.0 ' bit 0
CCP1CON.5 = Temp.1 ' bit 1
CCPR1L = Temp >>2 'Bit 2-7

TeMP1 = sineval[STEPCOUNT1]
CCP2CON.4 = Temp1.0 ' bit 0
CCP2CON.5 = Temp1.1 ' bit 1
CCPR2L = Temp1 >>2 'Bit 2-7
TOGGLE LED1
stepcount = stepcount +1
stepcount1 = stepcount1 +1

if stepcount =36 then stepcount =0
if stepcount1 =36 then stepcount1 =0


@ INT_RETURN


Thanks.

sangaboy
- 30th March 2012, 13:59
Hi to all
I try to download my program from my computer(wind7)using PIC16f877 development board and ET-CAB10PIN V2 interfacing cable but WHEN I try to run winpic800 software.
the following problems arise.
(1)failed to import Smport.sys
(2)when I check the hardware it say hardware not responding

any one can help me how to solve this problems
thanks

Demon
- 30th March 2012, 17:21
http://lmgtfy.com/?q=winpic800+failed+to+import

Robert

sangaboy
- 12th April 2012, 12:09
Hi every one
(1) Previous I thought that the problem of flat spot on my SPWM signal was due to the simulator(ISIS) but I was wrong because I implement it on the actual hardware using PIC16F877V1-V2 DEVELOPMENT BOARD board and DLIS40L oscilloscope but the problem still remain now I'm totally confused what cause that problem of flat spot to my wave form. I try to scale my look up table so that my dutycycle lie on the range of (0 to 4*199) but nothing was change to my signal
when viewed.
(2)ARE the ten bit look table is not working on 8bit chip like 16F877 0R 16F777 ? I think those values greater than 255 is one cause that problems



define OSC 4
Wsave var byte $70system
Wsave1 var byte $A0system
Wsave2 var byte $120system
Wsave3 var byte $1A0system

STEPCOUNT var byte
STEPCOUNT1 var byte

LED1 VAR PORTB.1

STEPCOUNT = 0 'pointer for phase one in sinearray
STEPCOUNT1 = 12 'pointer for phase two in sine array
ADCON0 = %00000000
ADCON1 = %00000000

TRISB = %11111101
TRISC = %11111001 'PMW output for CCP1 AND CCP2
TRISA = %11111111
TMR2 = 0
PR2 = 199 'generate 5khz 'set for 18Khz HPWM
CCP1CON = %00001100 'set CCP1 for PWM OPERATION
CCP2CON = %00001100 'set CCP2 for PWM OPERATION
T2CON = %00000100 'TIMER2ON and prescale of 1:1

sineval var word[36]
sineval[0] = 512
sineval[1] = 556
sineval[2] = 599
sineval[3] = 640
sineval[4] = 676
sineval[5] = 707
sineval[6] = 733
sineval[7] = 752
sineval[8] = 763
sineval[9] = 767
sineval[10] =763
sineval[11] =752
sineval[12] =733
sineval[13] =707
sineval[14] =676
sineval[15] =640
sineval[16] =599
sineval[17] =556
sineval[18] =512
sineval[19] =468
sineval[20] =425
sineval[21] =385
sineval[22] =348
sineval[23] =317
sineval[24] =291
sineval[25] =272
sineval[26] =261
sineval[27] =257
sineval[28] =261
sineval[29] =272
sineval[30] = 291
sineval[31] = 317
sineval[32] = 348
sineval[33] = 385
sineval[34] = 425
sineval[35] = 468

timerone var word
Temp var byte
Temp1 var byte
INCLUDE "DT_INTS-14.bas" ; Base Interrupt System emp
INCLUDE "ReEnterPBP.bas"

ASM

INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler TMR1_INT, _sine, PBP, yes
endm
INT_CREATE ; Creates the interrupt processor
ENDASM

T1CON = 000001 ; Prescaler = 1;1, TMR1 ON
@ INT_ENABLE TMR1_INT ; Enable Timer 1 Interrupts

timerone = 65080' gives1818hz nterruptfrequency or about 50 htz sine
Main:
PAUSE 5

GOTO Main

'---[TMR1_INT - interrupt handler]------------------------------------------

sine:
T1CON = 000000

TMR1L = timerone.byte0
TMR1H = timerone.byte1
T1CON = 000001


TeMP = sineval[STEPCOUNT]
CCP1CON.4 = Temp.0 ' bit 0
CCP1CON.5 = Temp.1 ' bit 1
CCPR1L = Temp >>2 'Bit 2-7

TeMP1 = sineval[STEPCOUNT1]
CCP2CON.4 = Temp1.0 ' bit 0
CCP2CON.5 = Temp1.1 ' bit 1
CCPR2L = Temp1 >>2 'Bit 2-7
TOGGLE LED1
stepcount = stepcount +1
stepcount1 = stepcount1 +1

if stepcount =36 then stepcount =0
if stepcount1 =36 then stepcount1 =0


@ INT_RETURN



(3) I'm not clear on the WINPIC800V358 software parameter on the attachment.



Any one can help me to solve these problems
Thankx