|
|
View previous topic :: View next topic |
Author |
Message |
matheuslps
Joined: 29 Sep 2010 Posts: 73 Location: Brazil
|
Get time between 2 square wave |
Posted: Tue Oct 26, 2010 1:03 pm |
|
|
I am developing a project that a need to measure the time between 2 sinusoid wave.
The Vin sine wave are lagged by an angle in comparison the other wave taked on the capacitor. I used a RC series network to cause this lag. So I applied this two signal in two comparators to obtain a square wave. Ok.
Now, I am trying to get the time difference between the rise of the 2 square wave.
I tried to use the 2 CCP module on the 16F877A but not worked.
A screenshot with the two wave a need to calculate the time difference between their rises (time between the rise of black one and the rise of the blue one) :
http://img594.imageshack.us/img594/9773/sadast.jpg
My code that not worked:
Code: | #include <16F877A.h>
#FUSES NOWDT //No Watch Dog Timer
#FUSES XT //Crystal osc <= 4mhz
#FUSES PUT //Power Up Timer
#FUSES NOPROTECT //Code not protected from reading
#FUSES NODEBUG //No Debug mode for ICD
#FUSES BROWNOUT //Reset when brownout detected
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD //No EE protection
#byte PIR1=0x0C
#use delay(clock=4000000)
#include <LCD.C>
int16 t1=0,t2=0,t=0;
float ap=0.0;
#int_ccp1
void isr()
{
t1=ccp_1;
}
#int_ccp2
void isr2()
{
t2=ccp_2;
t=t1-t2;
ccp_1=0;
}
void main()
{
lcd_init();
setup_ccp1 (CCP_CAPTURE_RE);
setup_ccp2 (CCP_CAPTURE_RE);
setup_timer_1 (T1_INTERNAL);
enable_interrupts (INT_CCP1|INT_CCP2); //Habilitar Interrupções
enable_interrupts (global);
while (TRUE)
{
//t=t2-t1;
ap=t*1.0;
printf (lcd_putc, "\nT = %6.1f", ap);
}
}
|
CCS 4.057
bye |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
|
matheuslps
Joined: 29 Sep 2010 Posts: 73 Location: Brazil
|
|
Posted: Sun Nov 14, 2010 7:01 pm |
|
|
I am back here to say that I tried this idea by Ttelmah from the topic suggested:
Quote: | CCP.
This is the best way to do what you want.
This is a hardware module in most PICs (you will need to choose one that has it), with a whole range of abilities to do with timing, and pulse generation. One ability, is to capture the reading on an internal counter (normally Timer1, but some of the PIC18's also allow Timer3 to be used), when an 'event' occurs. The events can be programmed to be the rising edge, or falling edge, on the CCP pins.
Accuracy will far exceed any software solution.
Look in the examples, at EX_CCPMP.C
In this, the two CCP modules are used. One to record when a signal rises, and the other when it falls. Each time a CCP records a value, there is an interrupt, and the code uses the second interrupt, on the falling edge, then subtracts the rising edge count, from the falling edge count, to give the pulse width. The same signal is fed to both CCP pins.
In your case, you simply connect your two signals to the two pins, and program the second CCP, to also use the rising edges (in the example, it is programmed to use the falling edge).
Best Wishes |
But this did not worked, I am getting a 0 (zero) result.
The 2 signal that I need to measure the time difference:
http://img580.imageshack.us/img580/6200/graphv.jpg
The circuit:
http://img152.imageshack.us/img152/2093/graph2l.jpg
My code:
Code: | #include <18f4550.h> //O PIC utilizado, obigatório!
//ser utilizado de 8 bits também.
#FUSES NOWDT //Sem Watch dog, evitando reset
#FUSES XT //Crystal de oscilação igual a 4mhz
#FUSES PUT //Tempo de início do PIC
#FUSES NOPROTECT //Codigo sem proteção de leitura, software livre!
#FUSES NODEBUG //No Debug mode for ICD
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD //No EE protection
#use delay(clock=4000000) //Meu clock
#include <LCD.C> //Rotina de LCD modo 4 vias. Obrigatório!
long rise,fall,pulse_width;
#int_ccp2
void isr()
{
rise = CCP_1;
fall = CCP_2;
pulse_width = fall - rise; // CCP_1 is the time the pulse went high
} // CCP_2 is the time the pulse went low
// pulse_width/(clock/4) is the time
// In order for this to work the ISR
// overhead must be less than the
// low time. For this program the
// overhead is 45 instructions. The
// low time must then be at least
// 9 us.
void main()
{
lcd_init();
//printf(lcd_putc "\n\rHigh time (sampled every second):\n\r");
setup_ccp1(CCP_CAPTURE_RE); // Configure CCP1 to capture rise
setup_ccp2(CCP_CAPTURE_RE); // Configure CCP2 to capture fall
setup_timer_1(T1_INTERNAL); // Start timer 1
enable_interrupts(INT_CCP2); // Setup interrupt on falling edge
enable_interrupts(GLOBAL);
while(TRUE) {
//delay_ms(1000);
printf(lcd_putc, "\n%lu us ", pulse_width );
}
} |
Compiler 4.057
Thanks |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Nov 14, 2010 9:11 pm |
|
|
I'm not sure about the scale of your timing diagram. What is the
estimated time difference between the two leading edges ? Are the units
in milliseconds or in microseconds ? |
|
|
matheuslps
Joined: 29 Sep 2010 Posts: 73 Location: Brazil
|
|
Posted: Sun Nov 14, 2010 11:30 pm |
|
|
Sorry, I forgot to comment this data.
Zooming on the graph, we have this:
http://img813.imageshack.us/img813/9796/szdfszf.png
Taking the average value of 2.5V of two signals... by approximation, we have a difference of 0,000488s (seconds) or 0.488ms. With a 4Mhz clock and T1 set to internal, is pretty easy for the PIC to catch it, hun?
Thanks... |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19516
|
|
Posted: Mon Nov 15, 2010 5:10 am |
|
|
Some comments:
You show MCLR connected to +6v. Now, this pin won't be _harmed_ by this, but it risks triggering the programming mode. The PIC is rated for 5.5v _max_ supply, with the logic inputs going a maximum of 0.3v above this. MCLR is allowed to go higher, since this connects to the programming circuit, and the voltage on this pin is used as the reference to generate Vpp, but it is not _rated_ to go to this voltage in normal operation. There can be very odd behaviours if the pin is taken to unexpected voltages like this...
Now, you show lots of nice little simulation graphs, but have you actually looked at the signals 'for real' on the PIC pins?. The real world often doesn't do exactly what you expect.....
The code should basically work, with a 'caveat'. You should test if CCP_2, is less than CCP_1. If it is, the timer has wrapped between the edges, and 65536 needs to be added to the result.
You really need to copy the pulse_width value to a local variable, with interrupts disabled, or you will see 'garbage' results as it updates half way through the LCD output....
4.057, is a bit 'borderline' for a compiler that works. Unfortunately, I'd rate the mid 70's as the first V4 compilers I found that actually did what they were meant to. You may have problems because of this....
Best Wishes |
|
|
matheuslps
Joined: 29 Sep 2010 Posts: 73 Location: Brazil
|
|
Posted: Mon Nov 15, 2010 2:25 pm |
|
|
Thanks Ttelmah for the help!
And yes I saw that mistake on MCLR, I forgot to edit that pin. But in real life, I use 5V and a 1K resistor into that pin.
So, I followed your suggest and....
Well I do not know why CCP2 module is not working _in simulation_. On my first program I put the first signal at CCP1 and the second signal at CCP2 and followed the EX_CCPMP.c that tells to capture the two modules when the event occurs on CCP2 and subtract them.
BUT, on the simulation it is not working, so I changed the order, now CCP1 is the second signal and CCP2 is the first signal and a used the CCP1 interrupt and I am not getting more a zero result.
However, the result I getting now is not what I expect. The result I am getting is a variation between 0 and 15000 us. I expect 0.488 ms. But not precisely.
Well, I am posting the new code, take a look and comment please.. I feel I am getting there. Just more details a can not see.
[off-topic]Why can not I declare a variable after interrupt's setups? I tried to declare a variable just after the enable_interrupts(GLOBAL); and I could not.[/off-topic]
Code: | #include <18f4550.h> //O PIC utilizado, obigatório!
//ser utilizado de 8 bits também.
#FUSES NOWDT //Sem Watch dog, evitando reset
#FUSES XT //Crystal de oscilação igual a 4mhz
#FUSES PUT //Tempo de início do PIC
#FUSES NOPROTECT //Codigo sem proteção de leitura, software livre!
#FUSES NODEBUG //No Debug mode for ICD
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD //No EE protection
#use delay(clock=4000000) //Meu clock
#include <LCD.C> //Rotina de LCD modo 4 vias. Obrigatório!
int16 entrada,capacitor,pulse_width;
#int_ccp1
void isr()
{
entrada = CCP_2;
capacitor = CCP_1;
}
void setup_pulse()
{
int16 temp;
disable_interrupts(global);
temp=pulse_width;
printf(lcd_putc, "\n%lu us ", temp );
enable_interrupts(GLOBAL);
}
void main()
{
lcd_init();
setup_ccp1(CCP_CAPTURE_RE); // Configure CCP1 to capture rise
setup_ccp2(CCP_CAPTURE_RE); // Configure CCP2 to capture fall
setup_timer_1(T1_INTERNAL); // Start timer 1
enable_interrupts(INT_CCP1);
enable_interrupts(GLOBAL);
while(TRUE)
{
if (capacitor < entrada)
{
capacitor+=65536;
pulse_width = capacitor - entrada;
setup_pulse();
}
}
} |
thanks. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9228 Location: Greensville,Ontario
|
|
Posted: Mon Nov 15, 2010 2:33 pm |
|
|
rule number 1: Simulation is NOT the real world
rule number 2: NEVER trust the simulator program, unless YOU wrote it.
I've never found a 'simulator' program in 35 years of cutting code that I would trust your life on or bet my house on. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19516
|
|
Posted: Mon Nov 15, 2010 2:48 pm |
|
|
On the varible declaration, this is standard C.
In the original C, variables can _only_ be declared at the start of a function defintion. On later improved version like ANSI C, you can declare a variable _at the start of a section_ (piece of code braketted with {}). CCS technically allows this, but it can sometimes be 'fragile' doing this, so it is safer to keep to the original C form. C 'generically' _does not_ allow definitions anywhere else.
Agree with the comments about simulation. MPLAB is the 'best' in this regard. Most others only work if you are 'lucky'....
Best Wishes |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Nov 15, 2010 3:15 pm |
|
|
I got tired of this so I made it work in hardware.
First I made a program to create the two test waveforms. This program
runs on the first PicDem2-Plus board:
Code: |
#include <16F877.H>
#fuses XT, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
#define WAVEFORM_0 PIN_B0
#define WAVEFORM_1 PIN_B1
//==========================================
void main()
{
output_low(WAVEFORM_0);
output_low(WAVEFORM_1);
delay_ms(100);
while(1)
{
output_high(WAVEFORM_0);
delay_us(448);
output_high(WAVEFORM_1);
delay_ms(40);
output_low(WAVEFORM_0);
delay_us(448);
output_low(WAVEFORM_1);
delay_ms(40);
}
} |
Then I took one of your original programs, and modified it to use RS-232
output instead of the LCD, and I put it on the 2nd PicDem2-Plus board:
Code: |
#include <16F877.h>
#FUSES NOWDT
#FUSES XT
#FUSES PUT
#FUSES NOPROTECT
#FUSES NODEBUG
#FUSES NOLVP
#FUSES NOCPD
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
long rise,fall,pulse_width;
#int_ccp2
void isr()
{
rise = CCP_1;
fall = CCP_2;
pulse_width = fall - rise;
}
void main()
{
setup_ccp1(CCP_CAPTURE_RE); // Configure CCP1 to capture rise
setup_ccp2(CCP_CAPTURE_RE); // Configure CCP2 to capture fall
setup_timer_1(T1_INTERNAL); // Start timer 1
enable_interrupts(INT_CCP2); // Setup interrupt on falling edge
enable_interrupts(GLOBAL);
while(TRUE) {
delay_ms(1000);
printf("%lu us \n\r", pulse_width );
}
} |
Then I connected the two boards together, with jumper wires.
Pin B0 on board 1 goes to pin C2 on Board 2.
Pin B1 on board 1 goes to pin C1 on Board 2.
Ground on board 1 goes to ground on Board 2.
Then I loaded TeraTerm and ran both boards and I got the following
output, which is in the expected range. All of these was done in less
than 10 minutes. It was compiled with vs. 4.057. I mean, days are
spent with the simulator, but two boards and an oscilloscope works a
lot better.
Quote: |
452 us
452 us
452 us
452 us
452 us
452 us
452 us
452 us
452 us
452 us
452 us |
|
|
|
matheuslps
Joined: 29 Sep 2010 Posts: 73 Location: Brazil
|
|
Posted: Mon Nov 29, 2010 4:10 am |
|
|
Thanks for your reply. The project is almost done. I have just more 1 question.
I just found the math library and want to know if I am using this right. I read that the sine and cosine functions are in radians.. so a made the conversion.
I am using a fake usb to connect the pic to the hyperterminal..... so a need to know if is necessary declare the RS232 protocol...
The code @ PCW 4.057
Code: |
#include <18F4550.h> //The PIC
#device adc=10 //ADC 10bits
#fuses HSPLL,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL3,CPUDIV1,VREGEN //Fuses
#use delay(clock=48000000) //Clock
#include <Math.h> //To make some calcs
#define USB_CON_SENSE_PIN PIN_B2 //Yes!
#include <usb_cdc.h>
void main()
{
long valor_1, valor_2, diferenca; //Variables
long tension_1=0, tension_2=0;
float envio, angulo_degree, angulo_radian, tensao_onda_1, tensao_onda_2, pot_ativa, pot_reativa;
int16 adc_1, adc_2=0;
usb_cdc_init();
usb_init();
setup_adc_ports(AN0_TO_AN1);
setup_adc(ADC_CLOCK_DIV_64);
setup_timer_1(T1_INTERNAL|T1_DIV_BY_4);
for(;;)
{
set_adc_channel(0);
delay_us(20);
adc_1=read_adc();
if (adc_1 > tension_1) //To find the biggest value
{
valor_1 = get_timer1();
tension_1 = adc_1;
}
set_adc_channel(1);
delay_us(20);
adc_2=read_adc();
if (adc_2 > tension_2) //To find the biggest value
{
valor_2 = get_timer1();
tension_2 = adc_2;
}
diferenca = (valor_2 - valor_1);
if (valor_2 < valor_1)
{
diferenca+=65536;
}
diferenca/=12; //Time in microseconds
envio = (diferenca/1000); //Time in miliseconds
usb_task();
if (usb_enumerated())
{
angulo_degree = (360*60*envio)/1000; //angle in degrees
angulo_radian = (angulo_degree*PI)/180; //angle in radians
tensao_onda_1 = (5*tension_1)/1023; //max value 1
tensao_onda_2 = (5*tension_2)/1023; //max value 2
pot_ativa = (((5*tension_1)/1023)*((5*tension_2)/1023)*(cos(angulo_radian)))/2; //Active power ?
pot_reativa = (((5*tension_1)/1023)*((5*tension_2)/1023)*(sin(angulo_radian)))/2; //reactive power ?
delay_ms(500);
printf(usb_cdc_putc,"\f T= %1.2f ms Tensao Entrada= %2.3f V Tensao Saida= %1.2f V Pot. Ativa= %1.2f W Pot. Reativa= %1.2f VAR" , envio,tensao_onda_1,tensao_onda_2,pot_ativa,pot_reativa); //show
}
}
} |
thanks |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Nov 29, 2010 12:45 pm |
|
|
Are you using a USB to serial cable like this:
http://www.siig.com/ViewProduct.aspx?pn=JU-CB1S12-S3
If so, the USB end of the cable needs to plug into a USB master, such as
the PC. The 18F4550 can only be a USB slave device. You can't plug
the USB end of the cable into the 18F4550 board.
You can plug the USB-to-serial cable into the PC, and the plug the serial
end of it into a PIC board (with a Max232-type chip on it). But of course
if you are using serial to talk to a PIC, you must use the #use rs232()
statement to define the serial port on the PIC. |
|
|
bkamen
Joined: 07 Jan 2004 Posts: 1615 Location: Central Illinois, USA
|
|
Posted: Mon Nov 29, 2010 12:52 pm |
|
|
temtronic wrote: | rule number 1: Simulation is NOT the real world
rule number 2: NEVER trust the simulator program, unless YOU wrote it.
|
Rule #3: Even if you wrote it - are you sure you can trust it?
Honestly, the simulator stuff should become a sticky at the top of the forum thread list with something like a list of "10 Commandments of Simulators."
-Ben _________________ Dazed and confused? I don't think so. Just "plain lost" will do. :D |
|
|
matheuslps
Joined: 29 Sep 2010 Posts: 73 Location: Brazil
|
|
Posted: Mon Dec 06, 2010 9:25 am |
|
|
hi, it is me again.
So, my project worked like a charm on a breadboard.
_BUT_ I needed come back here and tell that the problem that I was having on the simulator was not a simulator issue.
Look at the image below and pay attention on the two red retangles on the 18F4550:
http://img600.imageshack.us/img600/6268/semttulomd.png
The dunbass here, conected the second signal at the PIN B3, the second CCP2! That is because the code was not working. No interrupt was happening.....
The correct PIN is RC1!.
Now, the program works fine on the simulation too.
Thanks! |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|