|
|
View previous topic :: View next topic |
Author |
Message |
hobby_85
Joined: 17 Aug 2009 Posts: 50
|
|
Posted: Tue Oct 13, 2009 9:33 pm |
|
|
Hey PCM, I ran the code but it has the following problems. I'm still trying to debug it, so any advice would be useful.
When I run it, I get 'PINC5 did not go HIGH, Error' repeatedly. And it comes out real fast, like 30 times every second. Thats with a 2 second delay at the end of my code as well.
From the osc I can tell that C5 has gone high, so no problems there. No problems with C1 either, that one goes high for sure and its being picked up as well.
Am I using the CCP function the right way in my code?
Thanks heaps. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Oct 14, 2009 1:04 am |
|
|
Currently, one of us suggests a few changes and you implement them. Then you re-post the code and ask us to look at it again, without you
doing anything at all. Why don't you try to fix the problems. You might learn something. |
|
|
hobby_85
Joined: 17 Aug 2009 Posts: 50
|
|
Posted: Wed Oct 14, 2009 6:04 am |
|
|
PCM programmer wrote: | Currently, one of us suggests a few changes and you implement them. Then you re-post the code and ask us to look at it again, without you
doing anything at all. Why don't you try to fix the problems. You might learn something. |
Sorry about that, I was at work and couldnt test it out till I got home. Just thought it might have been faster to make the corrections and put it back on here to see what people thought.
but your right, i should keep trying. apologies. |
|
|
hobby_85
Joined: 17 Aug 2009 Posts: 50
|
|
Posted: Wed Oct 14, 2009 11:34 pm |
|
|
Hey, just a quick question regarding timers.
If I use a 4Mhz system clock, and use the following,
Code: | setup_timer_0(RTCC_INTERNAL|RTCC_DIV_16); |
I am essentially telling the timer to count up every (4Mhz/4)*16 = 16 micro seconds right?
so the timer counts up every 16 us and overflows ever 255 counts, which is 0.00408seconds or 4.08 ms. Am i correct so far?
I have a piece of code where I count the number of counts between two pins going high. Its very small, milli second differences. It kind of works, but this timer overflow is making things hard for me. Is there a way I can tell the timer to just keep counting up and not stop at 255? or maybe could i use a 'for' loop to count the number of timer counts? is that possible? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Oct 14, 2009 11:57 pm |
|
|
Timer0 overflows every 256 counts. You can keep a static int8 variable inside the Timer0 isr, and extend it that way. Initialize the variable to 0
in the declaration. Or, you could use a global int8 variable.
Or you could use Timer1, which is a 16-bit counter. It has a smaller maximum prescaler of 8. So you count in 8 usec increments.
8 usec x 65536 counts = 524288 usec = approx 1/2 second.
(Assuming a 4 MHz oscillator). |
|
|
hobby_85
Joined: 17 Aug 2009 Posts: 50
|
|
Posted: Thu Oct 15, 2009 1:44 am |
|
|
Cool thanks. I ended up going for the second option cause it pretty much acts like a time-out loop in itself. However, I'm getting heaps of erratic 'values'. The values are meant to be the number of counts between the two pins going high.
64423
9505
64093
9558
64119
9582
64150
9826
Just out of interest, when I start the clock, I just go right? cause this could set the register value to 0 and just start counting. Or is there a special 'start counting now' command?
And then to stop, I just read the timer register in question? There's no need to 'reset' it or anything because the next time I need to count, I just use the set_Timer1(0) command again.
Am I on the right track here? Thanks heaps. |
|
|
bungee-
Joined: 27 Jun 2007 Posts: 206
|
|
Posted: Thu Oct 15, 2009 1:41 pm |
|
|
You are on the right path. Basically you need to setup timer once and then just set it to 0 on start and read the value on end. Maybe your timer overflows in a second measurement. Create simple timer ISR where you increase value of an variable, so you'll know if it overflowed or not.
So on "start timer" command you'll first set timer to 0 and also overflow variable to 0.
I suspect, that your events take longer than you expected.
How does your Timer1 setup statement look like? |
|
|
hobby_85
Joined: 17 Aug 2009 Posts: 50
|
|
Posted: Fri Oct 16, 2009 4:38 am |
|
|
bungee- wrote: | You are on the right path. Basically you need to setup timer once and then just set it to 0 on start and read the value on end. Maybe your timer overflows in a second measurement. Create simple timer ISR where you increase value of an variable, so you'll know if it overflowed or not.
So on "start timer" command you'll first set timer to 0 and also overflow variable to 0.
I suspect, that your events take longer than you expected.
How does your Timer1 setup statement look like? |
ah i understand. so every time it interrupts, it increases the variable and then when im printing the value, i just take note of the number of times it overflowed. thanks.
timer1 setup statement is
Code: | setup_timer_1(T1_INTERNAL|T1_DIV_BY_1); |
and then when i want to start the timer, i go
and then for my second pin, im using the CCP to capture it and create an interupt when it does. and then i just use
ill try adding the variable and see how things turn out. thanks for the advice. |
|
|
hobby_85
Joined: 17 Aug 2009 Posts: 50
|
|
Posted: Fri Oct 16, 2009 5:18 am |
|
|
Yes! I think it works! Well at least I think it does. For some reason, I'm getting values that are closer to what I need. I just hope I haven't hacked it.
This is what I got in the end, I've stripped all the unwanted code so its easier for you to see. I'm most worried about calling the interupts. Where do I enable them? Where do I disable them?
Code: |
#include <16F690.h>
#fuses INTRC, NOWDT, NOPROTECT, BROWNOUT, PUT, HS
#use delay(clock = 4000000)
#use rs232(baud=19200, xmit=PIN_B7, rcv=PIN_B5)
int16 ctr;
int tripped=0;
long value=0;
int counter=0;
#int_CCP1
void CCP1_isr(void)
{
disable_interrupts(INT_CCP1);
tripped=1;
}
#int_TIMER1
void TIMER1_isr(void)
{
counter = counter + 1; //variable to check if timer1 has overflowed
disable_interrupts(INT_TIMER1);
}
void main()
{
setup_adc_ports(NO_ANALOGS|VSS_VDD);
setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);
enable_interrupts(GLOBAL);
for(;;){
contact_slave3(); //After this, PINC1 should go high, followed closely by PINC5
for (ctr=0;ctr<64000;ctr++) { //Wait for PINC1 to go high until timeout
if(input(PIN_C1)) {
set_timer1(0); //set timer value to 0, start counting
enable_interrupts(INT_TIMER1); //feature to know if timer1 overflows
ctr=1; //PINC1 went high, set ctr=0, break
break;
}
}
if (ctr==1){ //at this point, C1 went high, start timer and wait for CCP/C5 to go high
setup_ccp1(CCP_CAPTURE_RE);
enable_interrupts(INT_CCP1);
if(tripped) {
value = CCP_1; //value at timer register when C5 went high
value = value + (counter * 65536); //take into account number of timer timer1 overflowed
printf("Value is: %Lu us",value); //print value
printf("Counter is: %d", counter); //print counter number
tripped=0; //reset
counter=0;
value=0;
}
else{
printf("\r\nC5 didnt go high\r\n");
}
}
else{ //PINC1 did not go high, error
printf("\r\nC1 didnt go high\r\n");
}
delay_ms(2000);
tripped = 0;
}
}
|
The first reading always seems to be a mess-up for me, but it seems to settle and sometimes gives a bad reading. Ideally I'm looking for readings around 5000 us or less. Preferably less.
Value is: 22204 us Counter is: 2
Value is: 7595 us Counter is: 1
Value is: 28443 us Counter is: 1
Value is: 50347 us Counter is: 1
Value is: 5769 us Counter is: 1
Value is: 7075 us Counter is: 1
Value is: 7088 us Counter is: 1
Value is: 7079 us Counter is: 1
Value is: 7069 us Counter is: 1
And you're right, I learnt it does takes longer than I expected. But somehow I thought microcontroller worked really really fast. |
|
|
bungee-
Joined: 27 Jun 2007 Posts: 206
|
|
Posted: Fri Oct 16, 2009 1:44 pm |
|
|
hobby_85 wrote: |
#include <16F690.h>
#fuses INTRC, NOWDT, NOPROTECT, BROWNOUT, PUT, HS
#use delay(clock = 4000000)
#use rs232(baud=19200, xmit=PIN_B7, rcv=PIN_B5)
int16 ctr;
int tripped=0;
long value=0;
int counter=0;
#int_CCP1
void CCP1_isr(void)
{
disable_interrupts(INT_CCP1);
tripped=1;
}
#int_TIMER1
void TIMER1_isr(void)
{
counter = counter + 1; //variable to check if timer1 has overflowed
disable_interrupts(INT_TIMER1); <--- You do not need this
}
void main()
{
setup_adc_ports(NO_ANALOGS|VSS_VDD);
setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);
enable_interrupts(GLOBAL);
for(;;){
contact_slave3(); //After this, PINC1 should go high, followed closely by PINC5
for (ctr=0;ctr<64000;ctr++) { //Wait for PINC1 to go high until timeout
if(input(PIN_C1)) {
set_timer1(0); //set timer value to 0, start counting
enable_interrupts(INT_TIMER1); //feature to know if timer1 overflows <--- put this in your setup part of program
Reset counter here
ctr=1; //PINC1 went high, set ctr=0, break
break;
}
}
if (ctr==1){ //at this point, C1 went high, start timer and wait for CCP/C5 to go high
setup_ccp1(CCP_CAPTURE_RE); <--- put this to your setup point of program
enable_interrupts(INT_CCP1);
if(tripped) {
value = CCP_1; //value at timer register when C5 went high <--- this should be in CCP ISR not here
value = value + (counter * 65536); //take into account number of timer timer1 overflowed <--- this should be in CCP ISR not here
printf("Value is: %Lu us",value); //print value
printf("Counter is: %d", counter); //print counter number
tripped=0; //reset
counter=0;
|
Put into ISR parts, that should be done there.
Also you need to put part of the program into some sort of loop, when you're waiting for second signal to arrive. |
|
|
hobby_85
Joined: 17 Aug 2009 Posts: 50
|
|
Posted: Fri Oct 16, 2009 8:30 pm |
|
|
Hey bungee, thanks for your help. Just one last question,
If I put the enable_interupts(ccp1) command in my program, does that start looking for the high in that pin from that point onwards only? Especially if the setup_ccp_re is at the start of the program? |
|
|
bungee-
Joined: 27 Jun 2007 Posts: 206
|
|
Posted: Sat Oct 17, 2009 12:43 pm |
|
|
Enable interrupt for CCP stay's where it is, but setup can be moved on to beginning. You do not need to setup what kind of interrupt will CCP have multiple times, once is enough. Leave enable where it is, so that it will be active just when you want it. |
|
|
Guest
|
|
Posted: Sun Oct 18, 2009 6:42 am |
|
|
hey bungee, thanks for the help so far. unfortunately, i seem to be having a software bug somewhere that i cant get rid of. i just dont know where it is.
basically im using the time difference in arrival of the two signals to determine how far apart the source is. the code works, but only to an extent.
if i hold the source 1.2 meters away, then i keep getting either 11.60 meters or 19.05 meters. and its constantly around those numbers. everytime.
likewise, for 2.4m, i get 12.8m or 20.2 meters. and when i hold it 3.6meters away, i get either 13.9m or 21.42m.
if i was getting only 1 solid answer for each distance, i could possibly find a relationship and hack the code by putting a constant in somewhere. but since i keep getting two different values for each distance, i dont know what to do.
ive tried re writing the code in a different way, but same problem. would you have any suggestions on how i could debug such a problem? |
|
|
Guest
|
|
Posted: Sun Oct 18, 2009 6:49 am |
|
|
I just thought I might add my code if you wanted to refer to it.
Code: |
#include <16F690.h>
#fuses INTRC, NOWDT, NOPROTECT, BROWNOUT, PUT, HS
#use delay(clock = 4000000)
#use rs232(baud=19200, xmit=PIN_B7, rcv=PIN_B5)
int16 ctr;
int tripped;
int tripped1;
long value;
int counter;
float distance;
int16 ctr1;
#int_CCP1
void CCP1_isr(void)
{
value = CCP_1;
value = value + (counter * 65536);
tripped=1;
disable_interrupts(INT_CCP1);
}
#int_TIMER1
void TIMER1_isr(void)
{
counter = counter + 1;
}
void main()
{
setup_adc_ports(NO_ANALOGS|VSS_VDD);
setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);
enable_interrupts(GLOBAL);
setup_ccp1(CCP_CAPTURE_RE);
for(;;){
contact_slave3(); //After this, PINC1 should go high, followed closely by PINC5
for (ctr=0;ctr<65535;ctr++) { //Wait for PINC1 to go high until timeout
if(input(PIN_C1)) {
set_timer1(0); //set timer value to 0, start counting
enable_interrupts(INT_TIMER1);
counter=0;
ctr=1; //PINC1 went high, set ctr=0, break
break;
}
}
if (ctr==1){ //at this point, C1 went high, start timer and wait for C5 to go high
enable_interrupts(INT_CCP1); //wait for rising edge of pinC5 until timeout
for (ctr1=0;ctr1<10000;ctr1++) {
if(tripped) {
delay_ms(200);
printf("TDOA is: %Lu us\r\n",value);
distance = (value) * (0.000008) * (348.4);
printf("Distance is:%f meters\r\n", distance);
tripped=0;
distance=0;
value=0;
tripped1 = 1;
break;
}
}
if (tripped1 == 0){
printf("\r\nNO US DETECTED\r\n");
tripped1=0;
}
}
else{ //PINC1 did not go high, error
printf("\r\nSlave Node 3 RF signature not found\r\n");
}
delay_ms(1000);
tripped = 0;
tripped1 = 0;
counter=0;
}
}
|
I know the code works, but not accurate at all. Its just that I need to know how to keep getting one consistent result rather than 2. It has to be a bug I think.
Any help/tip/advice would be greatly appreciated.
Thanks |
|
|
bungee-
Joined: 27 Jun 2007 Posts: 206
|
|
Posted: Mon Oct 19, 2009 1:35 am |
|
|
Try this:
You are doing this: Code: | value = value + (counter * 65536); | with 16bit you overflow every time you multiply. |
|
|
|
|
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
|