|
|
View previous topic :: View next topic |
Author |
Message |
doguhanpala
Joined: 05 Oct 2016 Posts: 120
|
How to use both pins in ccp2 ? |
Posted: Wed Jul 17, 2019 1:38 am |
|
|
Hello everyone,
In my project I have 2 dc motors and an ultrasonic sensor. They both work fine separately. I use 18f4550. The problem is, the motors use ccp1 (RC2) and ccp2 (RC1). My ultrasonic sensor also uses ccp2(RB3). I am trying to converge the 2 codes. The problem is they both use same code lines for different pins.
Code: |
setup_ccp1(CCP_PWM); //Enable 2
setup_ccp2(CCP_PWM); //Enable 1
setup_timer_2(T2_DIV_BY_4, 99, 1); //30kHz, 0-399
|
In pwm setup, i use ccp_pwm, but in ultrasonic code i use ccp_capture_fe. They are on different pins. I also change the status of CCP2 interrupt on ultrasonic code. How do i make the compiler to separate the 2 pins (RB3 and RC1)? Is it possible?
This is the ultrasonic code.
Code: |
#if !defined(__PCH__)
#error USB CDC Library requires PIC18
#endif
#include <18F4550.h>
#DEVICE ADC=10
#fuses HSPLL,NOWDT,MCLR,PROTECT,NOLVP,NODEBUG,NOBROWNOUT,USBDIV,PLL5,CPUDIV1,VREGEN,CCP2B3
#use delay(clock=48000000)
//#include <usb_bootloader.h>
#include "usb_cdc.h"
#define rp_getc usb_cdc_getc
#define rp_putc usb_cdc_putc
#define BLUE_LED PIN_D5 //Blue LED
#define RED_LED PIN_D6 //Red LED
#define TRIGGER PIN_B2 //any suitable pin
#define ECHO PIN_B3 //CCP2 input
int value;
int32 distance;
int16 calculate_Distance();
void main()
{
usb_cdc_init();
usb_init();
output_low(TRIGGER);
setup_ccp1(CCP_OFF);
setup_ccp2(CCP_CAPTURE_FE);
setup_comparator(NC_NC_NC_NC);
setup_timer_1(T1_INTERNAL | T1_DIV_BY_8); //calc above
while(true)
{
usb_task();
printf(rp_putc, "%ld\n\r",calculate_Distance());
}
}
int16 calculate_Distance()
{
value = rp_getc();
delay_ms(20);
if(value == 'a')
{
output_high(BLUE_LED);
output_high(TRIGGER);
delay_us(20);
output_low(TRIGGER);
set_timer1(0); //clear timer
CCP_2=0; //clear CCP;
clear_interrupt(INT_CCP2);
clear_interrupt(INT_TIMER1);
while (!interrupt_active(INT_CCP2) && !interrupt_active(INT_TIMER1)); {} // //Here an edge was seen
if (interrupt_active(INT_CCP2))
{
distance=(int32)CCP_2*4/55; //this gives integer distance in mm - 4m=55555 counts
distance=distance/10; //conversion distance from mm to cm
if (distance>10 && distance<400)
{
output_low(BLUE_LED);
output_high(RED_LED);
}
else
{
output_low(RED_LED);
output_high(BLUE_LED);
}
// delay_ms(100); //pause before next reading
printf(rp_putc, "%ld\n\r",distance);
return distance;
}
else
{
//Here timer timed out
printf(rp_putc,"O"); //overtime
delay_ms(100);
return 0;
}
}
} |
Thank you so much! |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19496
|
|
Posted: Wed Jul 17, 2019 3:47 am |
|
|
Yes and no....
All you need to do is setup the CCP to be a capture at the start of the distance
routine, and set it back to be a PWM at the end of the routine.
However, it will not generate a PWM, while it is being used for capture.
Understand it is not a question of 'using both pins'. The CCP setup for PWM
does not perform capture. It does not 'have' a capture input in this mode.
Also uses a different timer in capture mode than PWM mode.
Only one peripheral, and 'one job or the other'. It can't do both at the same
time. So your PWM output, will have to stop while you read the distance.
Whether this matters or not is down to how the PWM is actually used.
Alternatively, consider not using the CCP for the distance measurement.
You could simply reset a timer, and then when the pulse arrives, read this.
Since you are already setting timer1 to zero for your timeout, use this.
Just wait for the change on the CCP input pin, and read timer1 when this
happens. |
|
|
doguhanpala
Joined: 05 Oct 2016 Posts: 120
|
|
Posted: Wed Jul 17, 2019 7:14 am |
|
|
Ttelmah wrote: | Yes and no....
All you need to do is setup the CCP to be a capture at the start of the distance
routine, and set it back to be a PWM at the end of the routine.
However, it will not generate a PWM, while it is being used for capture.
Understand it is not a question of 'using both pins'. The CCP setup for PWM
does not perform capture. It does not 'have' a capture input in this mode.
Also uses a different timer in capture mode than PWM mode.
Only one peripheral, and 'one job or the other'. It can't do both at the same
time. So your PWM output, will have to stop while you read the distance.
Whether this matters or not is down to how the PWM is actually used.
Alternatively, consider not using the CCP for the distance measurement.
You could simply reset a timer, and then when the pulse arrives, read this.
Since you are already setting timer1 to zero for your timeout, use this.
Just wait for the change on the CCP input pin, and read timer1 when this
happens. |
Thank you for your answer Ttelmah!
I've kinda hoped that there is a way to separate those pins and manipulate them both as i wanted. So i will try to use timer and another pin. Since i took the code from a post here, there are some code lines i don't know.
Code: | distance=(int32)CCP_2*4/55 |
In here the ccp_2 behaves like a function? Does it return the time it has been high/low?
There are timer flags but no timers itself. I am confused. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19496
|
|
Posted: Wed Jul 17, 2019 7:37 am |
|
|
CCP_2 is a register. It contains the value that was latched from the timer
at the moment the pin triggered, It is defined in the .h file for the processor.
In capture mode (you can program whether it is to capture the rising
or falling edge), when the required edge is seen, the value in Timer1 (or
optionally Timer3), is stored into this register.
Your code would have simply have to do the same. You can use the existing
pin. So something like:
Code: |
//at the start of the routine
int16 TIMER_val;
//then
while (!input(PIN_C2) && !interrupt_active(INT_TIMER1)); {} //
if (!interrupt_active(INT_TIMER1))
{
//Only go here if we haven't timed out
TIMER_val=get_timer1(); //read the timer value
//Then use this instead of the CCP_2 value
|
For detecting a rising edge on the pin. |
|
|
doguhanpala
Joined: 05 Oct 2016 Posts: 120
|
|
Posted: Thu Jul 18, 2019 6:46 am |
|
|
Ttelmah wrote: | CCP_2 is a register. It contains the value that was latched from the timer
at the moment the pin triggered, It is defined in the .h file for the processor.
In capture mode (you can program whether it is to capture the rising
or falling edge), when the required edge is seen, the value in Timer1 (or
optionally Timer3), is stored into this register.
Your code would have simply have to do the same. You can use the existing
pin. So something like:
Code: |
//at the start of the routine
int16 TIMER_val;
//then
while (!input(PIN_C2) && !interrupt_active(INT_TIMER1)); {} //
if (!interrupt_active(INT_TIMER1))
{
//Only go here if we haven't timed out
TIMER_val=get_timer1(); //read the timer value
//Then use this instead of the CCP_2 value
|
For detecting a rising edge on the pin. |
Thank you so much Ttelmah!
As i undertand, instead of using ccp2 register, we manually call the timer value from get_timer1(). I have edited the code to this.
Code: | clear_interrupt(INT_TIMER1);
while (!input_state(ECHO) && !interrupt_active(INT_TIMER1)); {} // //Here an edge was seen. ECHO is PIN B3
if (!interrupt_active(INT_TIMER1))
{
TIMER_val=get_timer1();
distance=(int32)TIMER_val*4/55; //this gives integer distance in mm - 4m=55555 counts
distance=distance/10; //conversion distance from mm to cm
printf(rp_putc, "%ld\n\r",TIMER_val);
|
I always read the timer value about same(665-661) even the distance is changed. Any ideas? I have checked the sensor, it still works with old codes.
I have deleted the CCP2B3 fuse and the lines below since i use input_state.
Code: | setup_ccp2(CCP_CAPTURE_FE);
setup_comparator(NC_NC_NC_NC); |
|
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9221 Location: Greensville,Ontario
|
|
Posted: Thu Jul 18, 2019 7:22 am |
|
|
maybe this....
I think it should be unsigned int16. The timer1 register(s) holds a 16bit value that logically would be an unsigned value.
I could be totally wrong (almost 40*C here today) but I'd change the code/compile/test....
Jay |
|
|
doguhanpala
Joined: 05 Oct 2016 Posts: 120
|
|
Posted: Thu Jul 18, 2019 7:30 am |
|
|
temtronic wrote: | maybe this....
int16 TIMER_val;
I think it should be unsigned int16. The timer1 register(s) holds a 16bit value that logically would be an unsigned value.
I could be totally wrong( almost 40*C here today) but I'd change the code/compile/test....
Jay |
Thank you Jay,
I've tried it but unfortunately, it did not work :/
There is something i miss which effects the timer i think. I tried editing value types, resetting TIMER_val to 0 in different locations. I have tried editing the size of variables but no luck. It is always between 666 and 661.
Code: | #if !defined(__PCH__)
#error USB CDC Library requires PIC18
#endif
#include <18F4550.h>
#DEVICE ADC=10
#fuses HSPLL,NOWDT,MCLR,PROTECT,NOLVP,NODEBUG,NOBROWNOUT,USBDIV,PLL5,CPUDIV1,VREGEN
#use delay(clock=48000000)
//#include <usb_bootloader.h>
#include "usb_cdc.h"
#define rp_getc usb_cdc_getc
#define rp_putc usb_cdc_putc
#define BLUE_LED PIN_D5 //Blue LED
#define RED_LED PIN_D6 //Red LED
#define TRIGGER PIN_B2 //any suitable pin
#define ECHO PIN_B3 //CCP2 input
int value;
int32 distance;
int16 calculate_Distance();
int16 TIMER_val;
void main()
{
usb_cdc_init();
usb_init();
output_low(TRIGGER);
setup_ccp1(CCP_OFF);
//setup_ccp2(CCP_CAPTURE_FE);
//setup_comparator(NC_NC_NC_NC);
setup_timer_1(T1_INTERNAL | T1_DIV_BY_8); //calc above
while(true)
{
usb_task();
printf(rp_putc, "%ld\n\r",calculate_Distance());
}
}
int16 calculate_Distance()
{
value = rp_getc();
delay_ms(20);
if(value == 'a')
{
output_high(BLUE_LED);
output_high(TRIGGER);
delay_us(20);
output_low(TRIGGER);
TIMER_val=0;
set_timer1(0); //clear timer
clear_interrupt(INT_TIMER1);
while (!input_state(ECHO) && !interrupt_active(INT_TIMER1)); {} // //Here an edge was seen
if (!interrupt_active(INT_TIMER1))
{
TIMER_val=get_timer1();
distance=(int32)TIMER_val*4/55; //this gives integer distance in mm - 4m=55555 counts
distance=distance/10; //conversion distance from mm to cm
printf(rp_putc, "%ld\n\r",TIMER_val);
if (distance>10 && distance<400)
{
output_low(BLUE_LED);
output_high(RED_LED);
}
else
{
output_low(RED_LED);
output_high(BLUE_LED);
}
// delay_ms(100); //pause before next reading
return distance;
}
else
{
//Here timer timed out
printf(rp_putc,"O"); //overtime
delay_ms(100);
return 0;
}
}
} |
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19496
|
|
Posted: Thu Jul 18, 2019 8:01 am |
|
|
661, is 1/2269 second. 440uSec.
Tell us more about the sensor?.
PIN_B3, when used as a digital input, is a standard 'TTL' input. Will accept
anything above 2.4v as a '1'. When used to trigger the CCP, it is a Schmidt
input, and will require the signal to go up to 4v, to be seen as a '1'.
However I realise your existing code is looking for the falling edge, not the rising edge.
Now you would actually have to ignore the edge until you see it fall. So
Code: |
int1 old, new;
old=new=input_state(ECHO);
while (!((old==1) && (new==0)) && !interrupt_active(INT_TIMER1))
{
old=new;
new=input_state(ECHO);
}
|
In place of your existing test line.
It'll then sit in the loop until it sees a point where the signal was high and
has gone low.
I suspect your sensor is actually setting it's pulse high about 2mSec after
the signal, so the existing code picks this up... |
|
|
doguhanpala
Joined: 05 Oct 2016 Posts: 120
|
|
Posted: Thu Jul 18, 2019 8:41 am |
|
|
Quote: | I suspect your sensor is actually setting it's pulse high about 2mSec after
the signal, so the existing code picks this up... |
You are right.
The last code you suggested worked succesfully. Measurements are correct. Thank you so much Ttelmah!
Note: the sensor is hc-sr084. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19496
|
|
Posted: Thu Jul 18, 2019 9:51 am |
|
|
Good.
Glad it worked. |
|
|
|
|
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
|