- Joined
- Jul 4, 2009
- Messages
- 16,532
- Helped
- 5,157
- Reputation
- 10,347
- Reaction score
- 5,215
- Trophy points
- 1,393
- Location
- Aberdyfi, West Wales, UK
- Activity points
- 139,786
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
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
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.
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.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
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.
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
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
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
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.
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
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.
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
loop:
Lcdcmdout LcdClear
Lcdcmdout LcdLine1Home
Lcdout "Phase = "
Lcdout #phase
pf = Cos(phase)
Lcdcmdout LcdLine2Home
Lcdout "Pow fac = "
Lcdout #pf
WaitMs 1000
Goto loop
1) count = 0.000
2) count
3) count =
4) co
5) no LCD display at all.
Measurement_ready is 1 every half cycle or full cycle. This may be too fast.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
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
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.
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?