pic.programmer
Advanced Member level 3
- Joined
- Aug 19, 2015
- Messages
- 773
- Helped
- 141
- Reputation
- 284
- Reaction score
- 140
- Trophy points
- 43
- Activity points
- 7,531
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.
#include "float2ascii.h"
unsigned long delta = 0;
char myFlags = 0, str[32];
double count = 0.0, time = 0.0, angle = 0.0, powerFactor = 0.0, powerFactorPrevious = 0.0;
unsigned int degree = 0, minutes = 0, seconds = 0;
const char character[] = {6,21,21,21,14,4,4,4};
sbit process at myFlags.B0;
#define _LCD_FIRST_ROW 0x80 //Move cursor to the 1st row
#define _LCD_SECOND_ROW 0xC0 //Move cursor to the 2nd row
#define _LCD_THIRD_ROW 0x94 //Move cursor to the 3rd row
#define _LCD_FOURTH_ROW 0xD4 //Move cursor to the 4th row
#define _LCD_CLEAR 0x01 //Clear display
#define _LCD_RETURN_HOME 0x02 //Return cursor to home position, returns a
//shifted display to its original position.
//Display data RAM is unaffected.
#define _LCD_CURSOR_OFF 0x0C //Turn off cursor
#define _LCD_UNDERLINE_ON 0x0E //Underline cursor on
#define _LCD_BLINK_CURSOR_ON 0x0F //Blink cursor on
#define _LCD_MOVE_CURSOR_LEFT 0x10 //Move cursor left without changing
//display data RAM
#define _LCD_MOVE_CURSOR_RIGHT 0x14 //Move cursor right without changing
//display data RAM
#define _LCD_TURN_ON 0x0C //Turn Lcd display on
#define _LCD_TURN_OFF 0x08 //Turn Lcd display off
#define _LCD_SHIFT_LEFT 0x18 //Shift display left without changing
//display data RAM
#define _LCD_SHIFT_RIGHT 0x1E //Shift display right without changing
//display data RAM
#define EN_DELAY 100
#define LCD_STROBE {LCD_EN = 1; Delay_us(EN_DELAY); LCD_EN = 0; Delay_us(EN_DELAY);};
// LCD module connections
sbit LCD_RS at LATD0_bit;
sbit LCD_EN at LATD1_bit;
sbit LCD_D4 at LATD2_bit;
sbit LCD_D5 at LATD3_bit;
sbit LCD_D6 at LATD4_bit;
sbit LCD_D7 at LATD5_bit;
sbit LCD_RS_Direction at TRISD0_bit;
sbit LCD_EN_Direction at TRISD1_bit;
sbit LCD_D4_Direction at TRISD2_bit;
sbit LCD_D5_Direction at TRISD3_bit;
sbit LCD_D6_Direction at TRISD4_bit;
sbit LCD_D7_Direction at TRISD5_bit;
// End LCD module connections
void LCD_Cmd(char out_char) {
LCD_RS = 0;
LCD_D4 = (out_char & 0x10)?1:0;
LCD_D5 = (out_char & 0x20)?1:0;
LCD_D6 = (out_char & 0x40)?1:0;
LCD_D7 = (out_char & 0x80)?1:0;
LCD_STROBE
LCD_D4 = (out_char & 0x01)?1:0;
LCD_D5 = (out_char & 0x02)?1:0;
LCD_D6 = (out_char & 0x04)?1:0;
LCD_D7 = (out_char & 0x08)?1:0;
LCD_STROBE
if(out_char == 0x01)Delay_ms(2);
}
void LCD_Chr(char row, char column, char out_char) {
switch(row){
case 1:
LCD_Cmd(0x80 + (column - 1));
break;
case 2:
LCD_Cmd(0xC0 + (column - 1));
break;
case 3:
LCD_Cmd(0x90 + (column - 1));
break;
case 4:
LCD_Cmd(0xD0 + (column - 1));
break;
}
LCD_RS = 1;
LCD_D4 = (out_char & 0x10)?1:0;
LCD_D5 = (out_char & 0x20)?1:0;
LCD_D6 = (out_char & 0x40)?1:0;
LCD_D7 = (out_char & 0x80)?1:0;
LCD_STROBE
LCD_D4 = (out_char & 0x01)?1:0;
LCD_D5 = (out_char & 0x02)?1:0;
LCD_D6 = (out_char & 0x04)?1:0;
LCD_D7 = (out_char & 0x08)?1:0;
LCD_EN = 1;
LCD_STROBE
}
void LCD_Chr_Cp(char out_char) {
LCD_RS = 1;
LCD_D4 = (out_char & 0x10)?1:0;
LCD_D5 = (out_char & 0x20)?1:0;
LCD_D6 = (out_char & 0x40)?1:0;
LCD_D7 = (out_char & 0x80)?1:0;
LCD_STROBE
LCD_D4 = (out_char & 0x01)?1:0;
LCD_D5 = (out_char & 0x02)?1:0;
LCD_D6 = (out_char & 0x04)?1:0;
LCD_D7 = (out_char & 0x08)?1:0;
LCD_EN = 1;
LCD_STROBE
}
void LCD_Init() {
Delay_ms(200);
LCD_RS_Direction = 0;
LCD_EN_Direction = 0;
LCD_D4_Direction = 0;
LCD_D5_Direction = 0;
LCD_D6_Direction = 0;
LCD_D7_Direction = 0;
LCD_RS = 0;
LCD_EN = 0;
LCD_D4 = 0;
LCD_D5 = 0;
LCD_D6 = 0;
LCD_D7 = 0;
Delay_ms(30);
LCD_D4 = 1;
LCD_D5 = 1;
LCD_D6 = 0;
LCD_D7 = 0;
LCD_STROBE
Delay_ms(30);
LCD_D4 = 1;
LCD_D5 = 1;
LCD_D6 = 0;
LCD_D7 = 0;
LCD_STROBE
Delay_ms(30);
LCD_D4 = 1;
LCD_D5 = 1;
LCD_D6 = 0;
LCD_D7 = 0;
LCD_STROBE
Delay_ms(30);
LCD_D4 = 0;
LCD_D5 = 1;
LCD_D6 = 0;
LCD_D7 = 0;
LCD_STROBE
Delay_ms(10);
LCD_Cmd(0x28);
LCD_Cmd(0x06);
}
void LCD_Out(char row, char col, char *text) {
while(*text)
LCD_Chr(row, col++, *text++);
}
void LCD_Out_Cp(char *text) {
while(*text)
LCD_Chr_Cp(*text++);
}
void CustomChar(char pos_row, char pos_char) {
char i;
Lcd_Cmd(64);
for (i = 0; i<=7; i++) Lcd_Chr_CP(character[i]);
//Lcd_Cmd(_LCD_RETURN_HOME);
Lcd_Chr(pos_row, pos_char, 0);
}
//Timer1
//Prescaler 1:1; TMR1 Preload = 64286; Actual Interrupt Time : 250 us
//Place/Copy this part in declaration section
void InitTimer1() {
T1CON = 0x01;
TMR1IF_bit = 0;
TMR1H = 0xFB;
TMR1L = 0x1E;
TMR1IE_bit = 1;
}
void Interrupt() {
if(INT0IF_bit) {
InitTimer1();
INT0IF_bit = 0;
INT1IE_bit = 1;
INT0IE_bit = 0;
}
if(INT1IF_bit) {
TMR1ON_bit = 0;
INT1IF_bit = 0;
INT1IE_bit = 0;
process = 1;
}
if(TMR1IF_bit) {
TMR1IF_bit = 0;
TMR1H = 0xFB;
TMR1L = 0x1E;
//Enter your code here
count = count + 1.0;
}
}
void main() {
ADCON1 = 0x0F;
TRISA = 0xC0;
TRISB = 0x03;
TRISC = 0x00;
TRISD = 0x00;
TRISE = 0x00;
PORTA = 0x00;
PORTB = 0x00;
PORTC = 0x00;
PORTD = 0x00;
PORTE = 0x00;
LATA = 0x00;
LATB = 0x00;
LATC = 0x00;
LATD = 0x00;
LATE = 0x00;
INTEDG0_bit = 1;
INTEDG1_bit = 1;
INT1IF_bit = 0;
INT1IE_bit = 0;
INT0IF_bit = 0;
INTCON |= 0xC0;
LCD_Init();
LCD_Cmd(_LCD_CURSOR_OFF);
LCD_Cmd(_LCD_CLEAR);
LCD_Out(1,1,"Cos ");
CustomChar(1,5);
LCD_Chr(1,7,'=');
INT0IE_bit = 1;
while(1) {
if(process) {
time = ((count * 0.00025) + 0.0000024 + (((1250.0 - (65536.0 - ((double)(TMR1H << 8) + (double)TMR1L))) * 0.0000002)));
angle = ((time * 1000000.0) / 0.02) * 360.0;
powerFactor = cos(angle * 0.0174532925); //
Float2Ascii(powerFactor, str, 5);
Ltrim(str);
Rtrim(str);
if(powerFactorPrevious != powerFactor){
LCD_Out(1,9,str);
powerFactorPrevious = powerFactor;
}
process = 0;
count = 0;
INT0IE_bit = 1;
}
}
}
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.
I have some working code in 'C' but just got called away for a few hours so it isn't finished yet. I should have the results for you tomorrow.
Brian.
#include "float2ascii.h"
char myFlags = 0, str[32];
double time = 0.0, angle = 0.0, powerFactor = 0.0, powerFactorPrevious = 0.0;
unsigned long int count = 0;
const char character[] = {6,21,21,21,14,4,4,4};
sbit process at myFlags.B0;
#define _LCD_FIRST_ROW 0x80 //Move cursor to the 1st row
#define _LCD_SECOND_ROW 0xC0 //Move cursor to the 2nd row
#define _LCD_THIRD_ROW 0x94 //Move cursor to the 3rd row
#define _LCD_FOURTH_ROW 0xD4 //Move cursor to the 4th row
#define _LCD_CLEAR 0x01 //Clear display
#define _LCD_RETURN_HOME 0x02 //Return cursor to home position, returns a
//shifted display to its original position.
//Display data RAM is unaffected.
#define _LCD_CURSOR_OFF 0x0C //Turn off cursor
#define _LCD_UNDERLINE_ON 0x0E //Underline cursor on
#define _LCD_BLINK_CURSOR_ON 0x0F //Blink cursor on
#define _LCD_MOVE_CURSOR_LEFT 0x10 //Move cursor left without changing
//display data RAM
#define _LCD_MOVE_CURSOR_RIGHT 0x14 //Move cursor right without changing
//display data RAM
#define _LCD_TURN_ON 0x0C //Turn Lcd display on
#define _LCD_TURN_OFF 0x08 //Turn Lcd display off
#define _LCD_SHIFT_LEFT 0x18 //Shift display left without changing
//display data RAM
#define _LCD_SHIFT_RIGHT 0x1E //Shift display right without changing
//display data RAM
#define EN_DELAY 100
#define LCD_STROBE {LCD_EN = 1; Delay_us(EN_DELAY); LCD_EN = 0; Delay_us(EN_DELAY);};
// LCD module connections
sbit LCD_RS at LATD0_bit;
sbit LCD_EN at LATD1_bit;
sbit LCD_D4 at LATD2_bit;
sbit LCD_D5 at LATD3_bit;
sbit LCD_D6 at LATD4_bit;
sbit LCD_D7 at LATD5_bit;
sbit LCD_RS_Direction at TRISD0_bit;
sbit LCD_EN_Direction at TRISD1_bit;
sbit LCD_D4_Direction at TRISD2_bit;
sbit LCD_D5_Direction at TRISD3_bit;
sbit LCD_D6_Direction at TRISD4_bit;
sbit LCD_D7_Direction at TRISD5_bit;
// End LCD module connections
void LCD_Cmd(char out_char) {
LCD_RS = 0;
LCD_D4 = (out_char & 0x10)?1:0;
LCD_D5 = (out_char & 0x20)?1:0;
LCD_D6 = (out_char & 0x40)?1:0;
LCD_D7 = (out_char & 0x80)?1:0;
LCD_STROBE
LCD_D4 = (out_char & 0x01)?1:0;
LCD_D5 = (out_char & 0x02)?1:0;
LCD_D6 = (out_char & 0x04)?1:0;
LCD_D7 = (out_char & 0x08)?1:0;
LCD_STROBE
if(out_char == 0x01)Delay_ms(2);
}
void LCD_Chr(char row, char column, char out_char) {
switch(row){
case 1:
LCD_Cmd(0x80 + (column - 1));
break;
case 2:
LCD_Cmd(0xC0 + (column - 1));
break;
case 3:
LCD_Cmd(0x90 + (column - 1));
break;
case 4:
LCD_Cmd(0xD0 + (column - 1));
break;
}
LCD_RS = 1;
LCD_D4 = (out_char & 0x10)?1:0;
LCD_D5 = (out_char & 0x20)?1:0;
LCD_D6 = (out_char & 0x40)?1:0;
LCD_D7 = (out_char & 0x80)?1:0;
LCD_STROBE
LCD_D4 = (out_char & 0x01)?1:0;
LCD_D5 = (out_char & 0x02)?1:0;
LCD_D6 = (out_char & 0x04)?1:0;
LCD_D7 = (out_char & 0x08)?1:0;
LCD_EN = 1;
LCD_STROBE
}
void LCD_Chr_Cp(char out_char) {
LCD_RS = 1;
LCD_D4 = (out_char & 0x10)?1:0;
LCD_D5 = (out_char & 0x20)?1:0;
LCD_D6 = (out_char & 0x40)?1:0;
LCD_D7 = (out_char & 0x80)?1:0;
LCD_STROBE
LCD_D4 = (out_char & 0x01)?1:0;
LCD_D5 = (out_char & 0x02)?1:0;
LCD_D6 = (out_char & 0x04)?1:0;
LCD_D7 = (out_char & 0x08)?1:0;
LCD_EN = 1;
LCD_STROBE
}
void LCD_Init() {
Delay_ms(200);
LCD_RS_Direction = 0;
LCD_EN_Direction = 0;
LCD_D4_Direction = 0;
LCD_D5_Direction = 0;
LCD_D6_Direction = 0;
LCD_D7_Direction = 0;
LCD_RS = 0;
LCD_EN = 0;
LCD_D4 = 0;
LCD_D5 = 0;
LCD_D6 = 0;
LCD_D7 = 0;
Delay_ms(30);
LCD_D4 = 1;
LCD_D5 = 1;
LCD_D6 = 0;
LCD_D7 = 0;
LCD_STROBE
Delay_ms(30);
LCD_D4 = 1;
LCD_D5 = 1;
LCD_D6 = 0;
LCD_D7 = 0;
LCD_STROBE
Delay_ms(30);
LCD_D4 = 1;
LCD_D5 = 1;
LCD_D6 = 0;
LCD_D7 = 0;
LCD_STROBE
Delay_ms(30);
LCD_D4 = 0;
LCD_D5 = 1;
LCD_D6 = 0;
LCD_D7 = 0;
LCD_STROBE
Delay_ms(10);
LCD_Cmd(0x28);
LCD_Cmd(0x06);
}
void LCD_Out(char row, char col, char *text) {
while(*text)
LCD_Chr(row, col++, *text++);
}
void LCD_Out_Cp(char *text) {
while(*text)
LCD_Chr_Cp(*text++);
}
void CustomChar(char pos_row, char pos_char) {
char i;
Lcd_Cmd(64);
for (i = 0; i<=7; i++) Lcd_Chr_CP(character[i]);
Lcd_Chr(pos_row, pos_char, 0);
}
//Timer1
//Prescaler 1:1; TMR1 Preload = 64286; Actual Interrupt Time : 250 us
//Place/Copy this part in declaration section
void InitTimer1() {
T1CON = 0x00;
TMR1IF_bit = 0;
TMR1H = 0xFB;
TMR1L = 0x1E;
TMR1IE_bit = 1;
TMR1ON_bit = 1;
}
void Interrupt() {
if(INT0IF_bit) {
InitTimer1();
INT0IF_bit = 0;
INT1IE_bit = 1;
INT0IE_bit = 0;
}
if(INT1IF_bit) {
TMR1ON_bit = 0;
INT1IF_bit = 0;
INT1IE_bit = 0;
process = 1;
}
if(TMR1IF_bit) {
TMR1H = 0xFB;
TMR1L = 0x1E;
//Enter your code here
count++;
TMR1IF_bit = 0;
}
}
void main() {
ADCON1 = 0x0F;
TRISA = 0xC0;
TRISB = 0x03;
TRISC = 0x00;
TRISD = 0x00;
TRISE = 0x00;
PORTA = 0x00;
PORTB = 0x00;
PORTC = 0x00;
PORTD = 0x00;
PORTE = 0x00;
LATA = 0x00;
LATB = 0x00;
LATC = 0x00;
LATD = 0x00;
LATE = 0x00;
INTEDG0_bit = 1;
INTEDG1_bit = 1;
INT1IF_bit = 0;
INT1IE_bit = 0;
INT0IF_bit = 0;
LCD_Init();
LCD_Cmd(_LCD_CURSOR_OFF);
LCD_Cmd(_LCD_CLEAR);
LCD_Out(1,1,"Cos ");
CustomChar(1,5);
LCD_Chr(1,7,'=');
INT0IE_bit = 1;
INTCON |= 0xC0;
while(1) {
if(process) {
time = ((double)(count * 0.00025) + 0.0000024 + ((1250.0 - (65536.0 - ((double)(TMR1H << 8) + (double)TMR1L))) * 0.0000002));
angle = (time / 0.02) * 360.0;
powerFactor = cos(angle * 0.0174532925);
Float2Ascii(powerFactor, str, 5);
Ltrim(str);
Rtrim(str);
if(powerFactorPrevious != powerFactor){
LCD_Out(1,9,str);
LongToStr(count, str);
Ltrim(str);
Rtrim(str);
LCD_Out(2,1,str);
powerFactorPrevious = powerFactor;
}
process = 0;
count = 0;
INT0IE_bit = 1;
}
}
}
//LCD_Out(1,4,str);
void Interrupt() {
if(INT0IF_bit) { // Voltage ZC has been detected
TMR1ON_bit = 1; // start Timer 1 counting
INT0IE_bit = 0; // disable further Voltage ZC detection
INT0IF_bit = 0; // clear the Voltage ZC Interrupt bit
INT1IE_bit = 1; // enable Current ZC detection interrupts
}
if(INT1IF_bit) { // Current ZC has been detected
TMR1ON_bit = 0; // stop Timer 1 counting
INT1IE_bit = 0; // disable further Current ZC detection
INT1IF_bit = 0; // clear the Current ZC Interrupt bit
timer_value = (double)(TMR1H << 8) + (double)TMR1L;
process = 1;
}
if(TMR1IF_bit) { // so what does this do???
TMR1H = 0x3C;
TMR1L = 0xB0;
TMR1IF_bit = 0;
//Enter your code here
count++;
}
}
if(process) { }
It should be within -5ms .... +5ms, for -90° (fully) capacitive to +90° (fully) inductive (with respect to voltage).The deltaT between the two signal's ZC's will be within 20 ms
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.
I suggested an XOR gate because it gives an output only when one or the other but not both inputs are high, when fed with the two square waves it's average output voltage will be proportional to the time they overlap and hence the phase difference between them. I agree it can all be done with direct measurement through the ADC but it removes the constraints of having to sample each waveform several times per cycle, essentially measuring the amount rather than the shape. Rectifying and filtering all the measurements isn't the cleverest way to do it but it is simple and gives accurate results.
Bear in mind that although the PIC18F4520 has 10 ADC inputs, they are internally connected to a multiplexer then on to one ADC module, it can not take simultaneous measurements although if the input impedance is kept low, it can rapidly sample the inputs in sequence.
The original topic was to use zero crossing as the method and Oshonsoft BASIC as the language, I fear a lot of time has been wasted by using develpment software that has very limited debugging capability.
Brian.
Sorry - been away trying to lay 2Km of water pipe in temperatures so low it has lost it's flexibility. It's like wrestling with a Python. I've got about 1.5Km down but many hours of struggling still to go! I envy you in warmer countries, there is still winter snow on the ground here.
Measuring the voltage and current is taking us back to my suggestions many posts back. If you are going to do that, PLEASE automate the phase measurement using a very simple analog method.
1. measure voltage with one ADC input
2. measure current with a second ADC input.
3. XOR (use a logic gate such as 74LS86 or equivalent) the two waveforms, feed it through a low pass filter and measure the resulting voltage through a third ADC input.
As long as you 'square up' the voltage and current waveforms using an op-amp or comparator before feeding them to the XOR gate, it's output will be a pulse with width equal to the phase difference in the signals. If you filter it to find the average, you get an analog voltage proportional to the phase shift.
It isn't using the zero crossing method at all but it will allow you to measure V, I, apparent power and phase displacement using simple math.
Brian.
#int_EXT
void ext_isr(void) {
disable_interrupts(INT_EXT_L2H);
set_timer1(0);
clear_interrupt(INT_EXT1);
enable_interrupts(INT_EXT1_L2H);
}
#int_EXT1
void ext1_isr(void) {
disable_interrupts(INT_EXT1_L2H);
timer_value = get_timer1();
process = 1;
clear_interrupt(INT_EXT);
enable_interrupts(INT_EXT_L2H);
}
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?