![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
Core2
Joined: 27 Sep 2008 Posts: 22
|
Only works once. . . |
Posted: Wed Jan 20, 2010 11:34 am |
|
|
Hello everyone,
I need a little help as I don't understand why it only works correctly ONCE, when the program first starts. In general, it signals the sonar unit (SensComp 6500) to start the process, start Timer1, grab the Timer1 count when the echo line goes HIGH (connected to RB5 as an IOC pin), then calculate the distance and send it out serial port.
It works GREAT for the first iteration. The Timer1 count is~6600, which is correct for 35", and displays 35". But on every iteration after that, the count is~40.
A little incite as to what is going on. About 16uS after the INITialize line goes high, the transducer sends out (16) 50KHz pulses. Unfoutunately you can see these pulses on the ECHO line; they are about 1.4V in amplitude and last for about 340uS.
Initially, the first pulse, on the ECHO line was setting off the RB5 IOC and I was ALWAYS getting a count of ~40. Once I realized what was going on, I changed the Sonar function to:
1) Start the sonar procedure
2) Start Timer1
3) delay_us(350) - to get past the 16 pulses
4) Clear the INT_RB5 flag
5) enable RB5 IOC interrupt.
Thing are getting better!! The first reading is correct and accurate. After that the RB5 IOC is back to tripping on the first transducer spike. I thought that would be skipped as in the first reading. Here is where I'm confused as to what is going on?!?!?
Compiler version is 4.093.
Code: | // This program will fire off the SenseComp Sonar system, detect an echo, and
// calculate the distance. Timer1 is setup with 400nS 'ticks'(20MHz/4 = 5MHz.
// 1/5MHz = 200nS period. T1 is setup as a 'Divide by 2' counter, making it
// count in 400nS intervals.) T1 is a 16-bit counter and will roll over every
// 65356 'ticks'. This equates to 65536*400nS = 26.21mS. T1 will 'timeout'
// if the object is more than 29 feet away.
#include <16F882.h>
#device *=16
#fuses HS NOWDT PUT NOPROTECT NOCPD NOBROWNOUT NOIESO NOLVP NOWRT
#use delay (clock=20M)
#use rs232(baud=115200,xmit=PIN_C6, rcv=PIN_C7) //115K for Bluetooth
#use fast_io(B)
#include <stdio.h>
#define TRIGGER PIN_A2
int16 range, time;
boolean trip, echo_rcvd, noEcho;
#int_rb
void getRange(void)
{
disable_interrupts(GLOBAL);
if(trip)
{
range=get_timer1(); //Get the time
setup_timer_1(T1_DISABLED); //Stop the clock
trip = FALSE; //skip the H to L transition INT_RB5
echo_rcvd = TRUE; //Got one
clear_interrupt(INT_RB5); // Clear the Interrupt flag.
enable_interrupts (INT_RB5); // enable interrupt_on_change for pin B5 only
}
else
{
trip = TRUE;
echo_rcvd = FALSE;
setup_timer_1(T1_DISABLED); //Stop the clock
}
enable_interrupts(GLOBAL); //Enable all interrupts
}
#int_timer1
void lostEcho(void)
{
setup_timer_1(T1_DISABLED);
set_timer1(0); //Reset the timer to 0
echo_rcvd = TRUE;
noEcho = TRUE; //No echo returned
output_low(TRIGGER);
// printf("Timer1\n\r"); //Just a test to see if I'm timimg out
clear_interrupt(INT_TIMER1);
enable_interrupts(INT_TIMER1);
}
void getSonar (void)
{
set_timer1(0); //Set Timer1 to an initial value of 0
output_high(TRIGGER); //Initiate the Sonar sequence
setup_timer_1(T1_INTERNAL|T1_DIV_BY_2); //Start counting, 0.4uS tick time
delay_us(350); //Skip past the 16 sonar pulses
clear_interrupt(INT_RB5); //Clear the INT_RB5 flag
enable_interrupts (INT_RB5); // enable interrupt_on_change for pin B5 only
// time=get_timer1(); //get a sample of the Timer1
// printf("Timer1 count = %lu\n\r",time); //Just to see if Timer1 is running
while (!echo_rcvd) {} //Wait for echo
printf("IOC_Timer1 count = %lu\n\r",range); //See what the count is
if(!noEcho)
printf("Range = %lu inches\n\r",range/185); //Print range
else
printf("No echo returned\n\r");
output_low(TRIGGER);
}
void main(void)
{
// Variables
trip = TRUE;
echo_rcvd = FALSE;
noEcho = FALSE;
// setup interrupts
enable_interrupts(INT_TIMER1);//Enable TImer1 interrupt
enable_interrupts (GLOBAL);
printf("Starting. . . \n\r");
while (TRUE)
{
getSonar(); //Get sonar1 reading
echo_rcvd = FALSE;
delay_ms(5000);
}
}
|
Thanks for looking at it.
Duane |
|
![](templates/subSilver/images/spacer.gif) |
Core2
Joined: 27 Sep 2008 Posts: 22
|
|
Posted: Wed Jan 20, 2010 11:35 am |
|
|
And YES, I did get the IOC part working before moving on to connecting the sonar module.
Duane |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Jan 20, 2010 1:45 pm |
|
|
Quote: | #int_rb
void getRange(void)
{
disable_interrupts(GLOBAL);
if(trip)
{
range=get_timer1(); //Get the time
setup_timer_1(T1_DISABLED); //Stop the clock
trip = FALSE; //skip the H to L transition INT_RB5
echo_rcvd = TRUE; //Got one
clear_interrupt(INT_RB5); // Clear the Interrupt flag.
enable_interrupts (INT_RB5); // enable interrupt_on_change for pin B5 only
}
else
{
trip = TRUE;
echo_rcvd = FALSE;
setup_timer_1(T1_DISABLED); //Stop the clock
}
enable_interrupts(GLOBAL); //Enable all interrupts
} |
This routine about has a few things wrong with it.
1. Don't ever enable/disable global interrupts inside an interrupt service
routine. This can cause the program to crash, and it's unnecessary. It's
handled automatically by the PIC when it executes the interrupt, and
when it exits the interrupt. Delete those two lines.
2. The compiler automatically puts in a line of code to clear the INT_RB
interrupt flag. You don't need to do it yourself inside the routine.
You also don't need to enable it again, inside the interrupt routine,
since you alread enabled it in getSonar().
3. You must read port B when inside the #int_rb routine to clear
the "mismatch" condition that caused the interrupt. See the example
further down in this post. Also add that code to the getRange() routine
above. This "mismatch" condition is described in the PIC data sheet,
in the section on PortB interrupts.
4. In your getSonar() routine below, you should read port B, to clear
any initial "mismatch" condition, before you clear and enable interrupts
for RB5. The "mismatch" condition is what causes the interrupt flag
to become set. If your intention is to look for new RB5 interrupts
after enabling them, then it's important to clear any pre-existing
interrupts first. You can do this by adding the lines shown in bold:
Quote: | void getSonar (void)
{
char c;
set_timer1(0); //Set Timer1 to an initial value of 0
output_high(TRIGGER); //Initiate the Sonar sequence
setup_timer_1(T1_INTERNAL|T1_DIV_BY_2); //Start counting, 0.4uS tick time
delay_us(350); //Skip past the 16 sonar pulses
c = input_b();
clear_interrupt(INT_RB5); //Clear the INT_RB5 flag
enable_interrupts (INT_RB5); // enable interrupt_on_change for
|
Also, I notice you're using #fast_io mode for Port B, but you don't ever
set the TRIS. It comes up set as all inputs by default, upon power-on
reset of the PIC, so it will work anyway. But I'm mentioning it just to
make you aware that if you use #fast_io, you are responsible for
determining and setting the correct TRIS.
I didn't look at your program design. I only scanned it for CCS or PIC
related bugs. Also, I didn't look at your whole program. There might
be other problems. |
|
![](templates/subSilver/images/spacer.gif) |
Core2
Joined: 27 Sep 2008 Posts: 22
|
|
Posted: Wed Jan 20, 2010 5:14 pm |
|
|
PCM,
I'd like to think that you're getting some king of compensation for the NUMEROUS people you've helped over the years! You're definitely a GREAT asset to this forum!
I'll make the changes you've noted, and all will work well. It was point #3 that turned the light on for me. I know to do this, just brain-farted on coding it.
Thanks for the reply!
Have a great day,
Duane |
|
![](templates/subSilver/images/spacer.gif) |
Core2
Joined: 27 Sep 2008 Posts: 22
|
|
Posted: Wed Jan 20, 2010 10:53 pm |
|
|
Well, I thought for sure that reading port B (c = input_b() ) was the fix to my problem. Unfortunately, it didn't. Now I'm even more lost than before.
Its like a flag isn't getting cleared, OR set, that needs to be. . . I just don't see it!!!
The changes PCM noted were made.
Anybody have a clue?
Thanks,
Duane |
|
![](templates/subSilver/images/spacer.gif) |
Wayne_
Joined: 10 Oct 2007 Posts: 681
|
|
Posted: Thu Jan 21, 2010 3:27 am |
|
|
Code: |
void getSonar (void)
{
set_timer1(0); //Set Timer1 to an initial value of 0
output_high(TRIGGER); //Initiate the Sonar sequence
setup_timer_1(T1_INTERNAL|T1_DIV_BY_2); //Start counting, 0.4uS tick time
delay_us(350); //Skip past the 16 sonar pulses
clear_interrupt(INT_RB5); //Clear the INT_RB5 flag
enable_interrupts (INT_RB5); // enable interrupt_on_change for pin B5 only
// time=get_timer1(); //get a sample of the Timer1
// printf("Timer1 count = %lu\n\r",time); //Just to see if Timer1 is running
while (!echo_rcvd) {} //Wait for echo
printf("IOC_Timer1 count = %lu\n\r",range); //See what the count is
if(!noEcho)
printf("Range = %lu inches\n\r",range/185); //Print range
else
printf("No echo returned\n\r");
output_low(TRIGGER);
}
|
Your first run through you don't set timer_1 until after you have cleared it. What are the default settings for the timer ?
The second time round it will be set correctly, this is probably why you get the incorrect first reading!
I would put
setup_timer_1(T1_INTERNAL|T1_DIV_BY_2);
in main before enabling your interrupts and just enable/disable the timers interrupt as and when you need to. Remove all other setup_timer lines.
So you would then use
set_timer1(0);
enable_interrupts(timer1);
And disable_interrupts(TIMER1); in your interrupt routines.
There is also some redundant code in your program. |
|
![](templates/subSilver/images/spacer.gif) |
Core2
Joined: 27 Sep 2008 Posts: 22
|
|
Posted: Thu Jan 21, 2010 10:06 am |
|
|
Wayne_ wrote: | Your first run through you don't set timer_1 until after you have cleared it. What are the default settings for the timer ?
The second time round it will be set correctly, this is probably why you get the incorrect first reading!
|
Hey Wayne, thanks for your reply. I'll make the changes when I get home. Just to correct something, I get a correct reading the first time, and subsequent reading are wrong.
Its like the program is skipping the 350uS delay that was put in to skip over the 16 pulse transmission spikes.
Thanks,
Duane |
|
![](templates/subSilver/images/spacer.gif) |
rnielsen
Joined: 23 Sep 2003 Posts: 852 Location: Utah
|
|
Posted: Thu Jan 21, 2010 12:48 pm |
|
|
When you use the command set_timer1(0) it takes several cycles to accomplish this and will _always_ cause your timing sequence to be out. It is better to allow a timer to free run and use it as an interrupt to accomplish your timing. You'll need to calculate what the pre/post registers should be set to and then increment a variable, inside the ISR, that sets a flag.
Ronald |
|
![](templates/subSilver/images/spacer.gif) |
Wayne_
Joined: 10 Oct 2007 Posts: 681
|
|
Posted: Fri Jan 22, 2010 2:45 am |
|
|
Core2 wrote: | Wayne_ wrote: | Your first run through you don't set timer_1 until after you have cleared it. What are the default settings for the timer ?
The second time round it will be set correctly, this is probably why you get the incorrect first reading!
|
Hey Wayne, thanks for your reply. I'll make the changes when I get home. Just to correct something, I get a correct reading the first time, and subsequent reading are wrong.
Its like the program is skipping the 350uS delay that was put in to skip over the 16 pulse transmission spikes.
Thanks,
Duane |
I know you said that the first timing was correct but it is the first one which is different! As all the rest are the same I would consider that it is the first one which is wrong and there is something you are missing with regards to what you are expecting.
How do you know the Timer1 count shuold be ~6600 |
|
![](templates/subSilver/images/spacer.gif) |
Core2
Joined: 27 Sep 2008 Posts: 22
|
|
Posted: Fri Jan 22, 2010 1:15 pm |
|
|
Wayne,
I see what you are saying now. I got a hold of a friend who has WAY more experience with programming PICs than I do. He pointed out what I was doing wrong and set me straight. A lot of what he explained was what you guys were talking about.
Thanks for ALL your help!
Sound travels, on average, 1125ft/s or 13500 in/s. 1/13500 is~74uS. 35" x 74uS = ~2.6mS 2.6mS / 400ns [ T1 = Fosc/4, 20MHz/4 = 5MHz, 1/5MHz = 200nS, if T1 is setup as DIV_2, then a T1 'tick' = 400nS] = 6500 ticks.
Duane |
|
![](templates/subSilver/images/spacer.gif) |
|
|
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
|