Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[PIC] Power factor measurement using PIC18f4520

Status
Not open for further replies.
The 18F4520 is fine, no need to use a different PIC.

I did find a bug in Oshonsofts simulator through and it stops your program working properly. When Timer0 is configured in 16 bit mode it doesn't carry from bit 7 of TMR0L to bit 0 of TMR0H as it should. I have modified your program so it shows the state of the zero crossing inputs properly and also the phase. To get around the timer problem I just chaged to Timer 1 instead of Timer 0.

It seems to work in simulation but you will have to try it in real life for yourself. I suspect the LCD routines will make the reading inaccurate because of the delays they introduce but 'one step at a time'. If you get results, I will change it back to using interrupts so the signals get immediate attention.

Code:
Define LCD_LINES = 4
Define LCD_CHARS = 16
Define LCD_BITS = 8  'allowed values are 4 and 8 - the number of data interface lines
Define LCD_DREG = PORTC
Define LCD_DBIT = 0  '0 or 4 for 4-bit interface, ignored for 8-bit interface
Define LCD_RSREG = PORTD
Define LCD_RSBIT = 0
Define LCD_EREG = PORTD
Define LCD_EBIT = 2
Define LCD_RWREG = PORTD  'set to 0 if not used, 0 is default
Define LCD_RWBIT = 1  'set to 0 if not used, 0 is default
Define LCD_COMMANDUS = 2000  'delay after LCDCMDOUT, default value is 5000
Define LCD_DATAUS = 100  'delay after LCDOUT, default value is 100
Define LCD_INITMS = 100  'delay used by LCDINIT, default value is 100
'the last three Define directives set the values suitable for simulation; they should be omitted for a real device
Dim timer As Single
Dim phase As Single
Dim scale_factor As Single

Lcdinit 0  'initialize LCD module; cursor is blinking
TRISB = 0x03  'TRISB has bits 0 And 1 As inputs
T1CON = 0x24  'T1CON enabled, 2 x 8 Bit, internal clock, prescale 1: 4
INTCON = 0x10
INTCON2 = 0xe0
INTCON3 = 0x08
ADCON1 = 0x0f

scale_factor = 277


main:

TMR1L = 0
TMR1H = 0
timer = 0
loop:

	If PORTB.0 Then
		T1CON.TMR1ON = 1
		Lcdcmdout LcdLine1Home
		Lcdout "VZCD ON "
	Else
		Lcdcmdout LcdLine1Home
		Lcdout "VZCD OFF"
	Endif

	If PORTB.1 Then
		T1CON.TMR1ON = 0
		Lcdcmdout LcdLine2Home
		Lcdout "IZCD ON "
		timer = (TMR1H * 256) + TMR1L
		phase = timer / scale_factor
		Lcdcmdout LcdLine3Home
		Lcdout "Phase ="
		Lcdout #phase
	Else
		Lcdcmdout LcdLine2Home
		Lcdout "IZCD OFF"
	Endif

Goto loop

End
Brian.
 
Hello, and thank you Brian!!

Yes you had right! T0 debugging in PICBASIC has bugs.

Results worked, but we need to go back to ISR routine, since the LCD phase displays are tooooo fast (don't stop at a value unless IZCD is OFF).


From another part, there is another hardware problem:

The zero crossing detection for V is different than I, therefore the ON/OFF statuses of both ZCD are different:

IZCD is ON when it is truly on (load is connected and running)
ZVCD is ON when its circuit is switched off from 220VAC mains, and OFF when its circuit is plugged into 220VAC mains, that's because in this circuit an opto-coupler is used: When its circuit is off, a 5V from VDD is given to PORTB.0 and vice-versa (this is the hardware architecture and functioning).

Two things must be modified:
Changing from T0 to T1 timer in the ISR.
Change the if statement condition such that when portb.0 = 0 the VZCD is on (but this would cause future errors, since the system cannot distinguish wether the load is DISCONNECTED) or when a zero is crossed and detected.


Thank you

- - - Updated - - -

Hello,

There is also another remark:

Even when the IZCD is OFF it turns on by itself :lol: (artificial intelligence case :lol:) and then return it self off.

This might be done to something related about offset, due by LM358.
 

OK, this is the ISR version of the code and it seems to work in the simulator, at least when the ZC signals are manually tiggered.
Code:
Define LCD_LINES = 4
Define LCD_CHARS = 16
Define LCD_BITS = 8  'allowed values are 4 and 8 - the number of data interface lines
Define LCD_DREG = PORTC
Define LCD_DBIT = 0  '0 or 4 for 4-bit interface, ignored for 8-bit interface
Define LCD_RSREG = PORTD
Define LCD_RSBIT = 0
Define LCD_EREG = PORTD
Define LCD_EBIT = 2
Define LCD_RWREG = PORTD  'set to 0 if not used, 0 is default
Define LCD_RWBIT = 1  'set to 0 if not used, 0 is default
Define LCD_COMMANDUS = 2000  'delay after LCDCMDOUT, default value is 5000
Define LCD_DATAUS = 100  'delay after LCDOUT, default value is 100
Define LCD_INITMS = 100  'delay used by LCDINIT, default value is 100
'the last three Define directives set the values suitable for simulation; they should be omitted for a real device
Dim timer As Single
Dim phase As Single
Dim scale_factor As Single

Lcdinit 0  'initialize LCD module; cursor is blinking
TRISB = 0x03  'TRISB has bits 0 And 1 As inputs
T1CON = 0x24  'T1CON enabled, 2 x 8 Bit, internal clock, prescale 1: 4
INTCON = 0x10
INTCON2 = 0xe0
INTCON3 = 0x48
ADCON1 = 0x0f

scale_factor = 277


main:

TMR1L = 0
TMR1H = 0
timer = 0
Enable High

loop:
	Lcdcmdout LcdLine1Home
	Lcdout "Phase = "
	Lcdout #phase

Goto loop

End                                               

On High Interrupt
	If INTCON.INT0IF = 1 Then
		T1CON.TMR1ON = 1
		INTCON.INT0IF = 0
	Endif

	If INTCON3.INT1IF = 1 Then
		T1CON.TMR1ON = 0
		timer = (TMR1H * 256) + TMR1L
		phase = timer / scale_factor
		TMR1H = 0
		TMR1L = 0
		INTCON3.INT1IF = 0
	Endif
Resume
Please see if it solves the 'no AC' problem. PIC interrupts are edge driven which means they are only triggered when the voltage on the interrupt input CHANGES. The previous program used polling which means the inputs were read and acted upon each time the program went around the loop. If it doesn't fix the problem, there is another way but let me know if it works so far.

I removed the messages telling the levels of the inputs as they had to be in a particular state for the LCD to display the phase anyway.

Brian.
 
OK, this is the ISR version of the code and it seems to work in the simulator, at least when the ZC signals are manually tiggered.
Code:
Define LCD_LINES = 4
Define LCD_CHARS = 16
Define LCD_BITS = 8  'allowed values are 4 and 8 - the number of data interface lines
Define LCD_DREG = PORTC
Define LCD_DBIT = 0  '0 or 4 for 4-bit interface, ignored for 8-bit interface
Define LCD_RSREG = PORTD
Define LCD_RSBIT = 0
Define LCD_EREG = PORTD
Define LCD_EBIT = 2
Define LCD_RWREG = PORTD  'set to 0 if not used, 0 is default
Define LCD_RWBIT = 1  'set to 0 if not used, 0 is default
Define LCD_COMMANDUS = 2000  'delay after LCDCMDOUT, default value is 5000
Define LCD_DATAUS = 100  'delay after LCDOUT, default value is 100
Define LCD_INITMS = 100  'delay used by LCDINIT, default value is 100
'the last three Define directives set the values suitable for simulation; they should be omitted for a real device
Dim timer As Single
Dim phase As Single
Dim scale_factor As Single

Lcdinit 0  'initialize LCD module; cursor is blinking
TRISB = 0x03  'TRISB has bits 0 And 1 As inputs
T1CON = 0x24  'T1CON enabled, 2 x 8 Bit, internal clock, prescale 1: 4
INTCON = 0x10
INTCON2 = 0xe0
INTCON3 = 0x48
ADCON1 = 0x0f

scale_factor = 277


main:

TMR1L = 0
TMR1H = 0
timer = 0
Enable High

loop:
	Lcdcmdout LcdLine1Home
	Lcdout "Phase = "
	Lcdout #phase

Goto loop

End                                               

On High Interrupt
	If INTCON.INT0IF = 1 Then
		T1CON.TMR1ON = 1
		INTCON.INT0IF = 0
	Endif

	If INTCON3.INT1IF = 1 Then
		T1CON.TMR1ON = 0
		timer = (TMR1H * 256) + TMR1L
		phase = timer / scale_factor
		TMR1H = 0
		TMR1L = 0
		INTCON3.INT1IF = 0
	Endif
Resume
Please see if it solves the 'no AC' problem. PIC interrupts are edge driven which means they are only triggered when the voltage on the interrupt input CHANGES. The previous program used polling which means the inputs were read and acted upon each time the program went around the loop. If it doesn't fix the problem, there is another way but let me know if it works so far.

I removed the messages telling the levels of the inputs as they had to be in a particular state for the LCD to display the phase anyway.

Brian.

Much thanks to you Brian!

It worked, when the ZCD are mutually triggered, the "no AC" problem is solved.
When connected to the 60W fan, it shows:
Phase = 51.<this floating part of the number changes continusouly, with no stop>.<here another floating number appears and sometime it has letters, sometimes different characters>

But after all, the first integer value of 51, is very logical, since cos(51) = around 0.6 which is true for such load.

Is there must be a solution for the after comma floating point value numbers like: 51.1232 <continuously>, or when making a Cos(phase) this problem will be gone?

Thank you
 

Because it uses interupts, the phase calculation is made on every single cycle. The LCD is updated every time the 'loop:' is repeated.
I have no idea how Oshonsoft LCD routines work (it would take a long time to reverse-engineer Vlad's code) but I suspect they are unbuffered which means the characters displayed are taken 'live' from the result and may change during the time the LCD is being written to. That means the digits you see may each be from a different cycle measurement, bearing in mind that the LCD is relatively slow to update compared to the numbers being calculated.

The good news is the 'loop;' code runs independently of the interrupts so it makes no difference to accuracy if something slows it down. I added a new variable called 'measurement_ready' that prevents the LCD being updated until a measurment has been taken, it should stop wrong characters being displayed but it also dramatically slows down the simulation. That is an unfortunate problem with Oshonsofts simulator and there is nothing I can do about it. In real hardware it should still run at full speed.
Code:
Define LCD_LINES = 4
Define LCD_CHARS = 16
Define LCD_BITS = 8  'allowed values are 4 and 8 - the number of data interface lines
Define LCD_DREG = PORTC
Define LCD_DBIT = 0  '0 or 4 for 4-bit interface, ignored for 8-bit interface
Define LCD_RSREG = PORTD
Define LCD_RSBIT = 0
Define LCD_EREG = PORTD
Define LCD_EBIT = 2
Define LCD_RWREG = PORTD  'set to 0 if not used, 0 is default
Define LCD_RWBIT = 1  'set to 0 if not used, 0 is default
Define LCD_COMMANDUS = 2000  'delay after LCDCMDOUT, default value is 5000
Define LCD_DATAUS = 100  'delay after LCDOUT, default value is 100
Define LCD_INITMS = 100  'delay used by LCDINIT, default value is 100
'the last three Define directives set the values suitable for simulation; they should be omitted for a real device
Dim timer As Single
Dim phase As Single
Dim scale_factor As Single
Dim measurement_ready As Byte

Lcdinit 0  'initialize LCD module; cursor is blinking
TRISB = 0x03  'TRISB has bits 0 And 1 As inputs
T1CON = 0x24  'T1CON enabled, 2 x 8 Bit, internal clock, prescale 1: 4
INTCON = 0x10
INTCON2 = 0xe0
INTCON3 = 0x48
ADCON1 = 0x0f

scale_factor = 277


main:

TMR1L = 0
TMR1H = 0
timer = 0
Enable High

loop:
	If measurement_ready = 1 Then
		phase = timer / scale_factor
		Lcdcmdout LcdLine1Home
		Lcdout "Phase = "
		Lcdout #phase
		measurement_ready = 0
	Endif

Goto loop

End                                               

On High Interrupt
	If INTCON.INT0IF = 1 Then
		T1CON.TMR1ON = 1
		INTCON.INT0IF = 0
	Endif

	If INTCON3.INT1IF = 1 Then
		T1CON.TMR1ON = 0
		timer = (TMR1H * 256) + TMR1L
		measurement_ready = 1
		TMR1H = 0
		TMR1L = 0
		INTCON3.INT1IF = 0
	Endif
Resume

Brian.
 
Hi,

I´d add a simple filter for the phase values.
Like:
phase_filtered = phase_filtered + (phase_new - phase-filtered) >> 6
(Tha value in the brackets shifted 5 bits right)

This gives a tau of about 1 second. And needs very low processing power.

****
Then every 25th interrupt set a flag for the main loop to display the new phase_filtered value.

Again low processing power. And an new update of the display every half a second gives stable values and good readability.

Klaus
 
Hello and thanks!

@betwixt:

The wrong characters stopped from appearing, hence the startup became more slow.
The floating numbers (after comma, since phase is defined as Single) are still showing, but that is not a problem, and as you said, nothing can be done about it.

The problem is when showing Cos(Phase):

Sure that the value of phase are true and logical (around 51.135), but when you add another statement under phase = timer / scale_factor like
Code:
If measurement_ready = 1 Then
		phase = timer / scale_factor
		pf = Cos(phase)
		Lcdcmdout LcdLine1Home
		Lcdout "Phase = "
		Lcdout #phase
		Lcdcmdout LcdLine2Home
		Lcdout "Pow Fac = "
		Lcdout #pf
		measurement_ready = 0

The results of cosine phase are not true, since phase is changing almost instantaneously and the command of Cos(phase) and its sending to display takes much of a delay, therefore it doesn't show a real value.

We need to stick the value of phase for one time, then make a Cos(phase) only for the last value of phase, without continuation.

But in the case of change of load, we need to know the new power factor for it, therefore we cannot decline the need of the loop that you've created.

Is adding a delay behind phase = timer / scale_factor and another delay after pf = Cos(phase) would solve this issue? The priority is to display pf.


Thank you
 

I don't think a delay is the solution.

Please try this, it is the same code I posted before with some lines commented out and the LCD showing a different variable. The remainder of the code is as before, I am only posting the changed section to save space:
Code:
loop:
    If measurement_ready = 1 Then
'phase = timer / scale_factor
        Lcdcmdout LcdLine1Home
        Lcdout "count = "
        Lcdout #timer
        measurement_ready = 0
        T1CON.TMR1ON = 1
    Endif

Goto loop

End                                               

On High Interrupt
'If INTCON.INT0IF = 1 Then
'T1CON.TMR1ON = 1
'INTCON.INT0IF = 0
'Endif

    If INTCON3.INT1IF = 1 Then
        T1CON.TMR1ON = 0
        timer = (TMR1H * 256) + TMR1L
        measurement_ready = 1
        TMR1H = 0
        TMR1L = 0
        INTCON3.INT1IF = 0
    Endif
Resume

What I am trying to find out is how big the number in the TMR1 becomes in the time between voltage zero crossings. The prescaler bits may need changing to ensure the number is as big as possible without the timer overflowing. The Oshonsoft simulator has no way of creating timed operations and it is impossible to manually change the interrupt pins state in a precise fixed time. It has to be done with real hardware. Ideally, the number will be around 45000 - 55000 which is large enough for the result to be accurate but never risk overflowing at 65536.

Brian.
 
Hi,

to avoid overflow one could decrease timer_tick frequency with the presacler..

The resolution should still be good enough. (Although i don´t know the capabilities of the PIC´s hardware)

Klaus
 
That's exactly what I'm trying to get Khaled to do. The problem is Oshonsoft's software is about as fast as a snail with arthritis and it doesn't have any method of providing timed events as stimulus. The program is supposed to start a counter when a voltage zero crossing occurs and stop it when the current zero crossing occurs. The phase difference can then be calculated by scaling the count to a sensible number then taking it's cosine. The trouble is the only way to simulate the two zero crossings is by clicking on the pin diagram in the simulator window and that makes it very 'hit or miss' with the timing.

I've temporarily changed the software so the counter works more like a frequency counter (really a period counter) so the number of counts can be found only between voltage zero crossings. For best accuracy the number should be as high as possible but without risk of overflowing back to zero. The prescaler bits can be adjusted to find a safe value but unfortunately I do not have any 18F4520 devices here to test hardware myself and I cannot tell what interrupt latency the Oshonsoft compiler introduces in its code. We are having to go back and forth in a debug loop between Wales and Lebanon!

It would be far better to use a good 'C' compiler but Khaled is constrained by his tutor to using Oshonsoft BASIC. The documentation doesn't even say whether the cosine parameters are degrees or radians!

Brian.
 
Hi,

Another solution:
Feed both signals to an XOR and low pass filter it's output and convert it with the ADC.

Klaus
 
That's certainly a viable solution and if the ADC was used to measure the current and voltage as well it would make sense to perform the whole operation in the analog domain but the original post in this long thread was asking to use zero crossings for the measurement so it has to be done by digital methods. Given that restriction, the timer method is probably easiest.

Brian.
 
That's certainly a viable solution and if the ADC was used to measure the current and voltage as well it would make sense to perform the whole operation in the analog domain but the original post in this long thread was asking to use zero crossings for the measurement so it has to be done by digital methods. Given that restriction, the timer method is probably easiest.

Brian.

Hello Brian and thank you!

I tested your last code, to seek the value of the timer, as it is: what is commented is still commented, the result were like:

1. either there is no LCD output at all
2. either the LCD displays only "count = " with no value
3. the LCD displays: "count = 0.000"

The VZCD routine is disabled (commented) maybe the timer is not having the fire signal to start?


Thank you
 

Sorry, my mistake. Please add one line so the interrupt routine looks like this:
Code:
On High Interrupt
'If INTCON.INT0IF = 1 Then
'T1CON.TMR1ON = 1
'INTCON.INT0IF = 0
'Endif

	If INTCON3.INT1IF = 1 Then
		T1CON.TMR1ON = 0
		timer = (TMR1H * 256) + TMR1L
		measurement_ready = 1
		TMR1H = 0
		TMR1L = 0
		INTCON3.INT1IF = 0
		T1CON.TMR1ON = 1
	Endif
Resume

I forgot to add the line to restart the timer when the first interrupt finished.
I tried to check the timing in the simulator but on my PC it took almost 5 minutes to simulate 20mS of real time 8-O In 'C' I can do it in real time.

Brian.
 
Sorry, my mistake. Please add one line so the interrupt routine looks like this:
Code:
On High Interrupt
'If INTCON.INT0IF = 1 Then
'T1CON.TMR1ON = 1
'INTCON.INT0IF = 0
'Endif

	If INTCON3.INT1IF = 1 Then
		T1CON.TMR1ON = 0
		timer = (TMR1H * 256) + TMR1L
		measurement_ready = 1
		TMR1H = 0
		TMR1L = 0
		INTCON3.INT1IF = 0
		T1CON.TMR1ON = 1
	Endif
Resume

I forgot to add the line to restart the timer when the first interrupt finished.
I tried to check the timing in the simulator but on my PC it took almost 5 minutes to simulate 20mS of real time 8-O In 'C' I can do it in real time.

Brian.

Hello and much thanks to you Brian!

I tried your modified code, that resets the timer: the results were same as without adding the final line code, as follows:

1) count = 0.000
2) count
3) count =
4) co
5) no LCD display at all.

Please note that using this code, the phase angle is totally correct, and represents well the displacement power factor:
Code:
Define LCD_LINES = 4
Define LCD_CHARS = 16
Define LCD_BITS = 8  'allowed values are 4 and 8 - the number of data interface lines
Define LCD_DREG = PORTC
Define LCD_DBIT = 0  '0 or 4 for 4-bit interface, ignored for 8-bit interface
Define LCD_RSREG = PORTD
Define LCD_RSBIT = 0
Define LCD_EREG = PORTD
Define LCD_EBIT = 2
Define LCD_RWREG = PORTD  'set to 0 if not used, 0 is default
Define LCD_RWBIT = 1  'set to 0 if not used, 0 is default
Define LCD_COMMANDUS = 2000  'delay after LCDCMDOUT, default value is 5000
Define LCD_DATAUS = 100  'delay after LCDOUT, default value is 100
Define LCD_INITMS = 100  'delay used by LCDINIT, default value is 100
'the last three Define directives set the values suitable for simulation; they should be omitted for a real device
Dim timer As Single
Dim phase As Single
Dim scale_factor As Single

Lcdinit 0  'initialize LCD module; cursor is blinking
TRISB = 0x03  'TRISB has bits 0 And 1 As inputs
T1CON = 0x24  'T1CON enabled, 2 x 8 Bit, internal clock, prescale 1: 4
INTCON = 0x10
INTCON2 = 0xe0
INTCON3 = 0x48
ADCON1 = 0x0f

scale_factor = 277


main:

TMR1L = 0
TMR1H = 0
timer = 0
Enable High

loop:
	Lcdcmdout LcdLine1Home
	Lcdout "Phase = "
	Lcdout #phase

Goto loop

End                                               

On High Interrupt
	If INTCON.INT0IF = 1 Then
		T1CON.TMR1ON = 1
		INTCON.INT0IF = 0
	Endif

	If INTCON3.INT1IF = 1 Then
		T1CON.TMR1ON = 0
		timer = (TMR1H * 256) + TMR1L
		phase = timer / scale_factor
		TMR1H = 0
		TMR1L = 0
		INTCON3.INT1IF = 0
	Endif
Resume


its problem was with the floating point like:


When you made a digital delay in the code by adding measurement_ready single variable, the floating problem point was gone.

Also, I added a delay of 1000 and cleared the LCD at each begin of loop like:
Code:
loop:
	Lcdcmdout LcdClear
	Lcdcmdout LcdLine1Home
	Lcdout "Phase = "
	Lcdout #phase
		pf = Cos(phase)
	Lcdcmdout LcdLine2Home
	Lcdout "Pow fac = "
	Lcdout #pf
	WaitMs 1000

Goto loop

And also the floating point disturbance was also vanished.

BUT:

I tried another test, by connecting a 200W incandescent (purely resistive) lamp instead of the 60W fan, the phase result that were satisfactory when connected to the fan, turned unsatisfactory:

The phase became equal to 47,123 and so on around 48, which is not logical nor true at all, and cos(48) = around 0.67 for a resistive load!

I tried to test the real power factor of the 200W resistive lamp, by testing its supply voltage that is of 216V and its current drawing that is 0.87V.

I did this: 0.87*216/200 = 0.9396
Cos^-1(0.9396) = 20.01

Instead of showing on LCD Phase = 20,01 it kept showing values around 48, yes it decreased from 51 but still way far from the real answer.

I must simultaneously connect/disconnect different types of load to see the system response of power factor calculation on the LCD.

I thought that the only problem was from LCD routine and delays. But when saw the response to the purely resistive load, there is something not functioning right.

The current system (hardware/code) behavior to the change of load is logical, since it has decreased the phase value from inductive to resistive load, but their values are not accurate.

Thank you!!!!
 

Hi,

1) count = 0.000
2) count
3) count =
4) co
5) no LCD display at all.

This tells me that there is not enough time to display the value.

If INTCON3.INT1IF = 1 Then
T1CON.TMR1ON = 0
timer = (TMR1H * 256) + TMR1L
measurement_ready = 1
TMR1H = 0
TMR1L = 0
INTCON3.INT1IF = 0
T1CON.TMR1ON = 1
Endif
Measurement_ready is 1 every half cycle or full cycle. This may be too fast.
--> try to put a counter 0 to 19 into the ISR and set measurement_ready only every 20th ISR run.
Then there is enough time for the main loop to display the value.
Don't use the delay in the main loop.

The problem with resistive load may be that both zero cross signals come at about the same time...not defined what zero cross signal comes first. What hapens, when the current signal comes before the voltage signal?

Klaus
 
This is where I start shouting curses at Oshonsoft! The simulator is far too slow to check these things will work in real life. There is also no way to add a breakpoint at a particular place in the source code, you have to find the equivalent assembly line and put it there and worst of all, if you single step the BASIC instructions, there is no way to make it resume full speed again, you have to reset it to the start. To be fair to them, when it does work, the code it produces is very compact but they should concentrate on core functionality rather than making it look pretty.

Anyway, rant over! The fact that you see different figures is encouraging, it means the timer is actually counting different numbers when the phase changes. I wuld not expect a true phase value at this stage becuase the result is only a time measurement, it has to be scaled to represent 0 - 180 degrees then the cosine taken to show the real phase.

The LCD problem is due to the interrupts being processed faster than the LCD routines can show the results. What is happening is the LCD commands do not have time to finish before the next data is being written to them. When you see a partial line of characters, it is because the 'home' command was used before the previous line was fully displayed.

The important point here is that the actual measurement must be accurate, how it displays it is of secondary importance. One way to do it would be to place the LCD routine inside the interrupt so it has to finish displaying before it can take the next measurment but that would be considered very bad practise because it would not only block further timer interrupts but any other interrupt you tried to use as well.

The alternative is not to re-enable the timer interrupt until after the LCD routines have finished. This has the drawback that there is a (tiny) period between enabling the interrupt and the next instruction being processed where an interrupt could sneak in. Without intimate knowledge of the compiler output it's difficult to avoid it.
Try this change, it should fix the LCD problem but do not expect to see the phase as the result yet, a fairly steady number is what I would like to see:
Code:
loop:
'phase = timer / scale_factor
		Lcdcmdout LcdLine1Home
		Lcdout "count = "
		Lcdout #timer
		INTCON3.INT1IF = 0
		T1CON.TMR1ON = 1
	Endif

Goto loop

End                                               

On High Interrupt
'If INTCON.INT0IF = 1 Then
'T1CON.TMR1ON = 1
'INTCON.INT0IF = 0
'Endif

	If INTCON3.INT1IF = 1 Then
		T1CON.TMR1ON = 0
		timer = (TMR1H * 256) + TMR1L
		TMR1H = 0
		TMR1L = 0
	Endif
Resume

Brian.
 
This is where I start shouting curses at Oshonsoft! The simulator is far too slow to check these things will work in real life. There is also no way to add a breakpoint at a particular place in the source code, you have to find the equivalent assembly line and put it there and worst of all, if you single step the BASIC instructions, there is no way to make it resume full speed again, you have to reset it to the start. To be fair to them, when it does work, the code it produces is very compact but they should concentrate on core functionality rather than making it look pretty.

Anyway, rant over! The fact that you see different figures is encouraging, it means the timer is actually counting different numbers when the phase changes. I wuld not expect a true phase value at this stage becuase the result is only a time measurement, it has to be scaled to represent 0 - 180 degrees then the cosine taken to show the real phase.

The LCD problem is due to the interrupts being processed faster than the LCD routines can show the results. What is happening is the LCD commands do not have time to finish before the next data is being written to them. When you see a partial line of characters, it is because the 'home' command was used before the previous line was fully displayed.

The important point here is that the actual measurement must be accurate, how it displays it is of secondary importance. One way to do it would be to place the LCD routine inside the interrupt so it has to finish displaying before it can take the next measurment but that would be considered very bad practise because it would not only block further timer interrupts but any other interrupt you tried to use as well.

The alternative is not to re-enable the timer interrupt until after the LCD routines have finished. This has the drawback that there is a (tiny) period between enabling the interrupt and the next instruction being processed where an interrupt could sneak in. Without intimate knowledge of the compiler output it's difficult to avoid it.
Try this change, it should fix the LCD problem but do not expect to see the phase as the result yet, a fairly steady number is what I would like to see:
Code:
loop:
'phase = timer / scale_factor
		Lcdcmdout LcdLine1Home
		Lcdout "count = "
		Lcdout #timer
		INTCON3.INT1IF = 0
		T1CON.TMR1ON = 1
	Endif

Goto loop

End                                               

On High Interrupt
'If INTCON.INT0IF = 1 Then
'T1CON.TMR1ON = 1
'INTCON.INT0IF = 0
'Endif

	If INTCON3.INT1IF = 1 Then
		T1CON.TMR1ON = 0
		timer = (TMR1H * 256) + TMR1L
		TMR1H = 0
		TMR1L = 0
	Endif
Resume

Brian.

Hello, thank you Brian!!

I will sign a petition to have a permission using other than OshonSoft compiler to code the project with.

Talking C, what compiler do you advise to work with? any tutorials?

This task took, and will be taken a huge amount of time, and there are other task to accomplish. If OshonSoft is the problem, I will do best to have permission to code in C.

Unfortunately it's been a while I didn't use C in a big source code, beside compiler choice would you recommend any tutorials?


Thanks.
 

Mods I came to know through email that the OP has switched the Compiler for OshonSoft Simulator to mikroC PRO PIC and that is why I am making this post.

I have made a power factor measurement project using mikroC PRO PIC. I am only testing it in Proteus and I am getting wrong result. I am attaching the project here. Please test it and tell me what is wrong.

In Proteus I have set a 7 ms delay between the two signals. In code I have used a 250 us timer interrupt. For 1 ms it is 4 x 250 us and so for 7 ms I have to get 28x 250 us. That is the variable count should hold 28 but all the time it shows 11 or 12. Only once when the project is started it shows 27 or 28 and then changes to 11 or 12. Is it a Proteus bug ?
 

Attachments

  • Power Factor Measurement.rar
    44.6 KB · Views: 68
I have had to use many different compilers for various customers but the best one I've found is from a little known UK company. It does almost all PIC12, PIC16 and PIC18 devices and the company will add new ones if requested. You can use it as a normal 'C' compiler or use it's rapid development mode where you click on the peripherals and link them to the pins and it automatically includes the code to drive that peripheral. The best part is it simulates at super fast speed and you can inject values directly into registers or send signals to pins from a table of timed events. So for example to simulate the ZC interrupts you can use a text file containing:
1000m PORTB.0 = 1
1001m PORTB.1 = 1

Which tells it to wait for one second to ensure the LCD has initialized then make PORTB.0 high, then one millisecond later make PORTB.1 high. That should simulate a 1mS delay between zero crossings. Obviously, you can edit the file to use different timings or add more lines so it uses different delays at a later time.

It also has a waveform editor for checking ADC operation and it can simulate serial data for checking communication links. It also has a facility for handling two or more PICs simultaneously, you can link their pins together and write/debug a different program on each one and see how they interact with each other. It is very useful when debugging complex designs.

Try downloading the demo version at **broken link removed** The full version is not expensive.

Next best is MPLABX which is Microchips own IDE and install the XC8 compiler as a tool within it. It is free and very good but with all compilers installed is >4GB in size!

Brian.
 

Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top