- Joined
- Jul 4, 2009
- Messages
- 16,478
- Helped
- 5,157
- Reputation
- 10,347
- Reaction score
- 5,202
- Trophy points
- 1,393
- Location
- Aberdyfi, West Wales, UK
- Activity points
- 139,434
There are two considerations:
1. Timer0 is configured in 16-bit mode so it's numeric range is 0 to 65535 (decimal). To get most accurate results you want it to count to the biggest number possible between voltage zero crossings but not risk it overflowing (back to zero) if the AC frequency is slightly too low. The prescaler bits in T0CON decide how much the clock is divided before reaching the counter, for example if set to 1:256 it means the count increases once in every 256 clock pulses. The optimum division is the one that makes the count near to but not exceeding 65535 during the time between zero crossings. I'm going to suggest you use 1:4 so the count is 5,000,000 times per second so if set to zero at voltage zero crossing, it would reach 50,000 in the 10mS between zero crossing points (at 50Hz AC, it would be 42,666 with 60Hz AC). So with a 20MHz clock, the value in T0CON should be 0x81.
2. the actual phase angle is proportional to, but not equal to the timer count between voltage and current zero crossings. To convert the value to an angle you need to divide the timer value by a number that converts the timer count into an angle between zero and 360 degrees. You know that zero count must be 0 degrees so there is no constant offset, you also know that the time between voltage zero crossings (10ms at 50Hz) gives a count of 50,000 and that equates to 180 degrees (remember there are two voltage zero crossings per cycle) so the factor to divide by is 50,000/180 = 277.7
I hope I got the calculations right, it's almost half a century since I left school and I was no good at math even then :sad:
You might need to reverse the wires to the CT secondary if you get results working backwards, the voltage ZCD gives a pulse every zero crossing but the curent ZCD produces a square wave at AC frequency, if the wrong edge of the square wave is used the results will be 180 degrees out but swapping the wires will fix that.
I've changed the program to use interrupts, you have to use PORTB.0 and PORTB.1 as the inputs as the pins on PORTC can't be used as interrupt inputs. Again, no promises it will work as I have no hardware (or time!) to test it.
note that if interrupts are used, you can add more instructions in the "loop:" code without losing accuracy.
Brian.
1. Timer0 is configured in 16-bit mode so it's numeric range is 0 to 65535 (decimal). To get most accurate results you want it to count to the biggest number possible between voltage zero crossings but not risk it overflowing (back to zero) if the AC frequency is slightly too low. The prescaler bits in T0CON decide how much the clock is divided before reaching the counter, for example if set to 1:256 it means the count increases once in every 256 clock pulses. The optimum division is the one that makes the count near to but not exceeding 65535 during the time between zero crossings. I'm going to suggest you use 1:4 so the count is 5,000,000 times per second so if set to zero at voltage zero crossing, it would reach 50,000 in the 10mS between zero crossing points (at 50Hz AC, it would be 42,666 with 60Hz AC). So with a 20MHz clock, the value in T0CON should be 0x81.
2. the actual phase angle is proportional to, but not equal to the timer count between voltage and current zero crossings. To convert the value to an angle you need to divide the timer value by a number that converts the timer count into an angle between zero and 360 degrees. You know that zero count must be 0 degrees so there is no constant offset, you also know that the time between voltage zero crossings (10ms at 50Hz) gives a count of 50,000 and that equates to 180 degrees (remember there are two voltage zero crossings per cycle) so the factor to divide by is 50,000/180 = 277.7
I hope I got the calculations right, it's almost half a century since I left school and I was no good at math even then :sad:
You might need to reverse the wires to the CT secondary if you get results working backwards, the voltage ZCD gives a pulse every zero crossing but the curent ZCD produces a square wave at AC frequency, if the wrong edge of the square wave is used the results will be 180 degrees out but swapping the wires will fix that.
I've changed the program to use interrupts, you have to use PORTB.0 and PORTB.1 as the inputs as the pins on PORTC can't be used as interrupt inputs. Again, no promises it will work as I have no hardware (or time!) to test it.
Code:
Define CLOCK_FREQUENCY = 20
Dim t0count As Word
Dim phase_angle As Word
Dim scaling_factor As Word
scaling_factor = 277 'conversion factor from count to phase
'initialize the pic registers
Gosub setup_pic
'initialize the display
Lcdinit
INTCON.GIE = 1 'enable interrupts
'main program loop
loop:
phase_angle = t0count / scaling_factor
Lcdout "Phase= ", #phase_angle
WaitMs 1000
Goto loop
End
setup_pic:
TRISB = 0x03 'TRISB has bits 0 And 1 As inputs
T0CON = 0x81 'T0CON enabled, 16 Bit, internal clock, prescale 1:4
INTCON = 0x50 'only INT0 and peripheral interrupts enabled
INTCON2 = 0x80 'PORTB pull-ups disabled
INTCON3 = 0x04 'INT1 enabled
Return
On Low Interrupt
Save System
If INTCON.1 = 1 Then
t0count = 0
INTCON.1 = 0 'reset the interrupt flag
Endif
Goto end_of_isr
If INTCON3.0 = 1 Then
T0CON.7 = 0 'stop the counter
t0count = TMR0H * 256
t0count = t0count + TMR0L
T0CON.7 = 1 'start the Count again
INTCON3.0 = 0 'reset the interrupt flag
Endif
end_of_isr:
Resume
Brian.