CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

HC-SR04 Ultrasonic Sensor with 16F877A
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
umutso



Joined: 23 Jan 2013
Posts: 39
Location: turkey

View user's profile Send private message MSN Messenger

HC-SR04 Ultrasonic Sensor with 16F877A
PostPosted: Wed Jan 23, 2013 2:32 pm     Reply with quote

Dear All,
I'm trying to implement a HC-SR04 ultrasonic sensor with 16F877A. The aim is to detect the distance and write the distance to rs232 serial port using a max232 with hardware uart on 16f877a.

The sensor has 4 pins. Two are VCC and GND and the others are trigger and echo pins. Trigger pin is taking to high with a minimum 10us pulse and echo pin gets the pulse back and counts until receiving the pulse. So I can formulate the distance. But since my trigger is going high and low with a 10/15us pulse, I can not get the distance via rs232 on the pc with a terminal emulator. I get garbage characters sometime and sometime I get nothing. Here is my code using ccs. I use C7 and C6 for serial uart with a 4Mhz external crystal while using the internal timer for counting issues. If you can help me on this I will be very pleased.
Code:

#include <16F877A.h>
 
#FUSES XT,NOWDT, NOPUT, PROTECT, NOBROWNOUT, NOLVP, NOCPD, NOWRT, NODEBUG
#use delay(clock=4000000)
#use rs232 ( baud=9600, xmit=pin_C6, rcv=pin_C7, parity=N, stop=1 )

int16 distance, time;          // Defining variables

// Defining the pins
#define trig pin_C0     
#define echo pin_C1     

void main()
{
 delay_ms(1000);                              // Boot-up delay

 setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);     // initiating timer

 while(true)
 {
 output_high(trig);                         // ping the sonar
 delay_us(20);                            // sending 20us pulse
 output_low(trig);

 while(!input(ECHO))                       // wait for high state of echo pin
 {}

 set_timer1(0);                           // setting timer zero

 while(input(ECHO))                       // Wait for high state of echo pin
 {}

 time=get_timer1();                       // Getting the time

 distance=time*0.028 + 1.093 ;            // Calculating the distance
                             
 printf("\fTime :%Lu \nDistance = %Lu",time,distance); // Putting the time on RS232 PC
                                       
 delay_ms(1000);
 }
}

_________________
Umut Sonkurt
Mike Walne



Joined: 19 Feb 2004
Posts: 1785
Location: Boston Spa UK

View user's profile Send private message

PostPosted: Wed Jan 23, 2013 2:41 pm     Reply with quote

What is the frequency of the ultrasonic output ?

Have you looked at any waveforms on a 'scope?

Mike
umutso



Joined: 23 Jan 2013
Posts: 39
Location: turkey

View user's profile Send private message MSN Messenger

Pulse type
PostPosted: Wed Jan 23, 2013 4:27 pm     Reply with quote

Hi mike

When triggered as high module sends 8 cycle burst of 40Hz sonic pulses. Cant check with scope that i have no scope.
_________________
Umut Sonkurt
umutso



Joined: 23 Jan 2013
Posts: 39
Location: turkey

View user's profile Send private message MSN Messenger

PostPosted: Wed Jan 23, 2013 4:33 pm     Reply with quote

Actually module does the work automatically when triggered. And I'm using a module that works with a similar circuit displays the distance on an lcd. So i think there is something wrong with my rs232, max232.

İ also tried direct connection with the pic to rs232 on hw uart and it works well on isis simulation. But practically i can not get it work :(
_________________
Umut Sonkurt
Mike Walne



Joined: 19 Feb 2004
Posts: 1785
Location: Boston Spa UK

View user's profile Send private message

Re: Pulse type
PostPosted: Wed Jan 23, 2013 4:45 pm     Reply with quote

umutso wrote:
Hi mike

When triggered as high module sends 8 cycle burst of 40Hz sonic pulses. Cant check with scope that i have no scope.
I'm assuming you really mean 40kHz and not 40Hz.

I don't want to sound harsh but:-

You need to use a 'scope so that you can SEE what you're dealing with.

Otherwise you're wasting your time and everyone elses.

Mike

EDIT Forget Proteus/ISIS. Search this forum to see what we all think of it.


Last edited by Mike Walne on Wed Jan 23, 2013 4:48 pm; edited 1 time in total
temtronic



Joined: 01 Jul 2010
Posts: 9221
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Wed Jan 23, 2013 4:46 pm     Reply with quote

Basic trouble shooting...
step 1...
Start with your PC, terminal program and confirm that you can send/receive data using a 'loopback' connection.
Simply connect pins 2 and 3 of the PC serial port.Anything you type on the PC keyboard will be echoed(displayed) on the PC screen.Be sure to type all the letters and numbers on the keyboard just to confirm it works.
Use 9600-n-1- no handshaking .

step2...
Connect your MAX232 to the PC serial port,observing TXD-RXD, RXD-TXD and jumper the TTL side of the MAX232 together.Again try typing on the PC keyboard...the screen should display everything you typed.

step3...
Connect the MAX232 to the PIC and program it with the 'echo' program that CCS has in the FAQ section of the help files(press F11 with an open project).This prgram will send a 'B' when you press 'A' on the PC keyboard, '2' for a '1', etc.

step1...confirms that the PC serial port and terminal program are running properly.
step2...confirms the MAX232 hardware is good.
step3..confirms the PIC is configured and running correctly.


2 important items..

1) always add 'errors' to the use RS232(.....) options when using the internal HARDWARE UART. It'll keep the UART from 'stalling' or 'locking' up


2) never EVER trust Proteus! Please read PIC101.

hth
jay
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Wed Jan 23, 2013 4:48 pm     Reply with quote

Here is the data sheet for the sensor:
http://elecfreaks.com/store/download/HC-SR04.pdf
The timing diagram is shown on page 2 of the data sheet.
Initially, all i/o pins are configured as inputs. So you need to
initialize the TRIG pin to a low level as shown in bold below.
Then it will be ready to go from a logic low to a logic high level,
when you make the TRIG pulse. Add the line shown in bold below,
in that exact position in the program:
Quote:
void main()
{
output_low(TRIG); // Initialize TRIG to inactive level
delay_ms(1000); // Boot-up delay




Quote:
I get garbage characters sometime and sometime I get nothing.

Fix your serial connection first. Make a simple "Hello World" program
with the PIC and get the RS232 working correctly. Then proceed with
the HC-SR04 program.
umutso



Joined: 23 Jan 2013
Posts: 39
Location: turkey

View user's profile Send private message MSN Messenger

PostPosted: Wed Jan 23, 2013 4:48 pm     Reply with quote

Hi mike

Yes it's 40 KHz just typing mistake from mobile.

You are right. Will do it first thing tomorrow and post the result.
Thank you for prompt replies.

Br
_________________
Umut Sonkurt
umutso



Joined: 23 Jan 2013
Posts: 39
Location: turkey

View user's profile Send private message MSN Messenger

PostPosted: Wed Jan 23, 2013 4:53 pm     Reply with quote

Actually when i put a printf like hello world string i can see it in my terminal. Things get defected after triggering the module. İ start to get asynchronous garbage characters. So serial port works fine. Just a separate hello world program is working fine.
_________________
Umut Sonkurt
umutso



Joined: 23 Jan 2013
Posts: 39
Location: turkey

View user's profile Send private message MSN Messenger

PostPosted: Wed Jan 23, 2013 4:55 pm     Reply with quote

İ will test max232. Did not do that. Thank you for the tip.
_________________
Umut Sonkurt
umutso



Joined: 23 Jan 2013
Posts: 39
Location: turkey

View user's profile Send private message MSN Messenger

PostPosted: Wed Jan 23, 2013 4:58 pm     Reply with quote

Did not think to get the trigger pin low first. Will apply this as well.
_________________
Umut Sonkurt
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Wed Jan 23, 2013 5:23 pm     Reply with quote

Make a test program that tests this line:
Code:
printf("\fTime :%Lu \nDistance = %Lu",time,distance); // Putting the time on RS232 PC
 

Comment out all code that talks to the sensor.
Load 'time' and 'distance' with nominal values. See if they print OK.
If it doesn't work then post your CCS compiler version.
umutso



Joined: 23 Jan 2013
Posts: 39
Location: turkey

View user's profile Send private message MSN Messenger

PostPosted: Thu Jan 24, 2013 3:25 am     Reply with quote

Dear All,

I checked with a simple program to send and receive data on MAX232 and it Works very well with 9600 baud both send & receive. The I simplified my program (below). When the program starts "Press a key to start..." comes ok, when I hit any key it again loops to "Press any key to start..." means the beginning. does this mean that the echo pin can not go high or something else?

help will be very appreciated.

Thanks in advance.

here is the code:

Code:
#include <16F877A.h>
 
 #FUSES XT,NOWDT, NOPUT, PROTECT, NOBROWNOUT, NOLVP, NOCPD, NOWRT, NODEBUG
 #use delay(clock=4000000)

#use rs232 ( baud=9600, xmit=pin_C6, rcv=pin_C7, parity=N, stop=1, errors )
   int time;         
 #define trig pin_C0     
 #define echo pin_C1     

  void main()
 {
 delay_ms(1000);
 setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);
 
       printf("\n\rPress a key to start...");
       getch();
       output_high(trig);
       delay_us(15);
       output_low(trig);
 
 
 while(!(input_state(echo)));
      set_timer1(0);
      while((input_state(echo)));
      time= get_timer1();
      printf("\n\rReceive Time=%ius",time);

 delay_ms(1000);                               

   printf("\n\rFinished...");
   getch();
    }

_________________
Umut Sonkurt
temtronic



Joined: 01 Jul 2010
Posts: 9221
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Thu Jan 24, 2013 7:26 am     Reply with quote

2 comments...

1)I don't see how this program loops back to the 'press any key' again.
It should just execute once then 'drop off' and sleep after it says' finished...' and gets the 2nd key pressed. CCS puts a sleep command after main().

Normally program will look like this
Code:

main() {

'put init stuff here'

while(true) {

                do real stuff....

                } //end of while loop

} //end of main
hidden sleep instruction

2) I also don't see why the printf 'finished...' doesn't appear on your PC screen !

Please use the 'code' tag to put the entire program into this thread, as there has to be 'something' funny going on.

Maybe I'm not seeing it right but it's what I see.


hth
jay
Douglas Kennedy



Joined: 07 Sep 2003
Posts: 755
Location: Florida

View user's profile Send private message AIM Address

PostPosted: Thu Jan 24, 2013 7:58 am     Reply with quote

Observations on your code...I really don't like to look at code since I know you will learn more if you discover your own errors.

All PIC programs need an infinite loop in main to stop them from falling asleep. EX while(true); as last line in main.

Here is my code it may give you some ideas.
If not at least you will have learned to avoid this approach.
The code starts with an attempt to describe the ultrasonic timing interface so the pic code can be seen to be married to the needs of the interface.
It doesn't describe the electrical interface the data sheet for the SR-04
is sufficient. If you haven't read it then you really really need to before writing another line of code.
If you are using Proteus to avoid having to read the data sheet and build a test board then have a Proteus board help you. The way you describe your issue could mean you are using Proteus since most don't see a real circuit looping the way you describe it. The code below should not be used with Proteus.

The code has a setup routine it also uses an isr routine to measure the delay and has a notation routine call to translate echo delay time into distance in inches.

Now this is code that will not by cutting and pasting be a solution for you
since I have cut it out of a larger program.
The isr provides a raw count representing time.
HC_SR04_RangeRaw() obtains this raw value in 2us units.
HC_SR04_RangeInches changes the raw value notation to inches.

Code:
///// ultra sonic ranger
///     ________            ______________________
///     | Trig |            |      echo           |
///_____| 10us |____________| 150us to 25 ms      |____________
//                            38ms is infinity ( no return)
//               ^^^^^^^^
//               |||||||| <-8 pulses at 40khz
////                     
////                        <- pulse width      ->
////  pulse width of us/148 is distance in inches

/////         pulse width measurement using CCP
//1) Read the CCP, into ccp_val[flag].
//2) Test flag - if set, this is the second edge, goto 4
//3) Change the interrupt edge, and set the flag - exit
//4) Now the time is ccp_val[1]-ccp_val[0]. If this is -ve add 65536.
//5) clear flag, and exit.
#define HC_SR04_TRIGGER_PIN PIN_A1
#define HC_SR04_ECHO_PIN PIN_C2

#define FE 0
#define RE 1
unsigned int16 rise_cnt,fall_cnt,pulse_width_cnt;
int8 ccp_mode;
#int_CCP1
void  CCP1_isr(void)
{
     if (ccp_mode==RE){
         rise_cnt = CCP_1;
         ccp_mode=FE;
         setup_ccp1(CCP_CAPTURE_FE);
       
     }
     else {
         fall_cnt = CCP_1;
         if (fall_cnt>=rise_cnt) pulse_width_cnt = fall_cnt - rise_cnt;
         else pulse_width_cnt = 65536+fall_cnt - rise_cnt;
         
          ccp_mode=RE;
         setup_ccp1(CCP_CAPTURE_RE);
     }
}         


 
unsigned int16  HC_SR04_RangeRaw()
{
unsigned int16 value;
value=0;
pulse_width_cnt=0;
output_low(HC_SR04_TRIGGER_PIN);
delay_us(10);
set_timer1(0);
ccp_mode=RE;
setup_ccp1(CCP_CAPTURE_RE);

//// trigger measurement
output_high(HC_SR04_TRIGGER_PIN);
delay_us(10);
output_low(HC_SR04_TRIGGER_PIN);


delay_ms(40);     //// allow CCP interrupt to see both edges of max pulse=38ms

//// pulse_width_cnt is in 2us units
value=pulse_width_cnt;
return value;
}
void HC_SR04_setup()
{
setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);//start 2us per inc timer
enable_interrupts(INT_CCP1);
enable_interrupts(GLOBAL);

}
int16 HC_SR04_RangeInches(unsigned int16 gRng_Raw)
{unsigned int16 inches;
inches=gRng_Raw/74L;
return inches;
}
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
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