Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Parallax Ping Sensor

Status
Not open for further replies.
this sucks. If its so simple how come no one can give a straight answer.

The algorithm I gave you earlier is very close to what I do with a similar sensor. It sounds to me like your MCU just wasn't interrupting. You only posted partial code so I didn't see how I could help.

Did you enable interrupts? Did you write your interrupt routines? What is intFlag? Was it declared as volatile?
 
The simplest way to do it is;

1. Make trigger pulse
2. Poll to test if signal when high
2. Reset TMR1
3. Poll to test if signal goes lo
4. Stop TMR1
5. subtract constant Tin-min from TMR1
6. TMR1 now contains the distance

the 2 poll delays will cancel each other out on average. Generally you want to average a few readings anyway.
 
Take a look:
Main2.c
Code:
// include files
#include <p18cxxx.h>
#include "main2.h"

// config settings
#pragma config WDT = OFF, LVP = OFF, OSC = INTIO67, XINST = OFF

// global vars
PingData Ping;
unsigned char intFlag;

// interrupts
#pragma code high_vector=0x08
void interrupt_at_high_vector(void)
{
_asm GOTO High_ISR _endasm
}

#pragma code low_vector=0x18
void interrupt_at_low_vector(void)
{
_asm GOTO Low_ISR _endasm
}

// code
#pragma code

#pragma interruptlow Low_ISR
void Low_ISR()
{
}

#pragma interrupt High_ISR
void High_ISR()
{
	INTCONbits.INT0IF =0;
	if(intFlag == 0){
		Ping.start = TMR0L;
		Ping.start = TMR0H;
		Ping.start <<= 8;
		Ping.start |= TMR0L;
		intFlag = 1;
	} else {
		Ping.end = TMR0L;
		Ping.end = TMR0H;
		Ping.end <<= 8;
		Ping.end |= TMR0L;	
		intFlag = 0;
	}

}

void main()
{
	OSCCON = 0x72;      			//8MHz clock 500ns cycles
	while(!OSCCONbits.IOFS);		//wait for osc stable

	intFlag = 0;
	initPIC();
	while(1)
	{
		GetPing();
	}
}

// function definitions
void PlayTone(void){
	unsigned char x;
	for(x=0;x<20;x++){
		BuzzOut = 1;
		Delay10KTCYx(5);
		BuzzOut = 0;
		Delay10KTCYx(5);
	}
		BuzzOut = 0;
}
void initPIC(void){
	TRISA = 0x00;
	TRISB = 0x00;
	TRISC = 0x00;

//----------------------
// PING INIT			
//----------------------
	PingDir = 0;		//PING pin is output
	PingOut = 0;		//Start with PING pin LOW
//----------------------
// Buzz INIT			
//----------------------
	BuzzDir = 0;
	BuzzOut = 0;
//----------------------
// Timer0, INT0 INIT			
//----------------------
	T0CON   = 0b10001000;	//16 Bit Timer
	INTCON  = 0b11000000; 	//bit 1 = INT0IF
	INTCON2 = 0b10000001; 	//bit 6 = rising edge(1)
	RCON    = 0b10000000;  	//IPEN = 1
}

void GetPing(void){

	INTCON2bits.INTEDG0 = 1;

	Ping.start = 0;	
	Ping.end = 0;
	Ping.start = 0;

	PingDir = 0;

	PingOut = 0;
	Delay16uS();
	PingOut = 1;
	Delay16uS();
	PingOut = 0;

	INTCONbits.INT0IF =0;
	INTCONbits.INT0IE = 1;

	PingDir = 1;
	PingIn = 0;


	while(intFlag == 0);
	INTCONbits.INT0IE = 0;
	INTCON2bits.INTEDG0 = 0;
	INTCONbits.INT0IF =0;
	INTCONbits.INT0IE = 1;
	while(intFlag == 1);

}

//------------------------------------------------------
// Used MPLAB Stopwatch. Exact 16uS from call to return.
//------------------------------------------------------
void Delay16uS(void){
	Delay10TCY();
	Nop();Nop();
}
//------------------------------------------------------
// Used MPLAB Stopwatch. Exact 400uS from call to return.
//------------------------------------------------------
void Delay400uS(void){
	Delay100TCYx(3);
	Delay10TCYx(9);
	Nop();Nop();Nop();Nop();Nop();Nop();
}
main2.h
Code:
//main2.h
#ifndef __MAIN2_H
#define __MAIN2_H
#include <delays.h>

void main(void);
void initPIC(void);
void GetPing(void);
void Delay16uS(void);
void Delay400uS(void);
void PlayTone(void);

void Low_ISR(void);
void High_ISR(void);

#define PingDir  TRISBbits.TRISB0
#define PingOut  LATBbits.LATB0
#define PingIn   PORTBbits.RB0

#define BuzzDir  TRISCbits.TRISC2
#define BuzzOut  LATCbits.LATC2

typedef union {
	struct {
		unsigned int start;
	};
	struct {
		unsigned int end;
	};
	struct {
		unsigned int len;
	};
}  PingData;  
#endif
 
The simplest way to do it is;

1. Make trigger pulse
2. Poll to test if signal when high
2. Reset TMR1
3. Poll to test if signal goes lo
4. Stop TMR1
5. subtract constant Tin-min from TMR1
6. TMR1 now contains the distance

the 2 poll delays will cancel each other out on average. Generally you want to average a few readings anyway.

Would try now but am tired. gonna try in about 10 min
 
From PIC datasheet (18F2525)

TMR0H is not the actual high byte of Timer0 in 16-bit
mode; it is actually a buffered version of the real high
byte of Timer0 which is not directly readable nor
writable (refer to Figure 11-2). TMR0H is updated with
the contents of the high byte of Timer0 during a read of
TMR0L. This provides the ability to read all 16 bits of
Timer0 without having to verify that the read of the high
and low byte were valid, due to a rollover between
successive reads of the high and low byte.

Does this mean i have to read the TMR0L then the TMR0H ? like:

Code:
	Time = TMR0L;
	Time = TMR0H;
	Time <<= 8;
	Time |= TMR0L;
 
Ok this is giving me a stable number:
Code:
void GetPing(void){
	unsigned int MyPing = 0;
	char Done = 0;
	
	PingDir = 0;

	PingOut = 0;
	Delay16uS();
	PingOut = 1;
	Delay10TCY();
	PingOut = 0;

	PingDir = 1;
	PingIn = 0;
	while(!PingIn);
	T0CONbits.TMR0ON = 1;
	
	while(PingIn);

	T0CONbits.TMR0ON = 0;

	Time = TMR0L;
	Time = 0;
	Time = TMR0H;
	Time <<= 8;
	Time |= TMR0L;

	TMR0L = TMR0H = 0;
}
 
Looks good but i'd use a 16bit var for time and change the end to this for better accuracy as you can subtract Tin_min before you reduce resolution;

Code:
	Time = TMR0L;
	Time += (TMR0H << 8);
	Time -= Tin_min (important)
(then reduce Time resolution if needed)
 
Last edited:
i got this which checks 3 times and averages them...
Code:
void GetPing(void){
	unsigned char x;
	unsigned int MyPing;
	char Done;

for(x=0;x<3;x++){
	Done = 0;
	MyPing = 0;
	
	PingDir = 0;

	PingOut = 0;
	Delay16uS();
	PingOut = 1;
	Delay10TCY();
	PingOut = 0;

	PingDir = 1;
	PingIn = 0;
	while(!PingIn);
	T0CONbits.TMR0ON = 1;
	
	while(PingIn);

	T0CONbits.TMR0ON = 0;

	avg[x] = TMR0L;
	avg[x] += (TMR0H << 8);

	TMR0L = TMR0H = 0;

}
	Time = 0;
	Time = (avg[0] + avg[1] + avg[2]) / x;
}

Now to the tougher part. Converting into inches
 
Last edited:
heh i dont even need actual distance. I want to calculate the distance between 2 objects (cars) and just alarm when too close and the closer you get the more it alarms.

The further away the less until a safer distance and no alarm.

I think i can do it from here .. Ill post my final code when its done... thanks guys
 
Yay its beautiful... ima make a video:
Code:
#include <p18f2525.h>
#include "main.h"
#include <delays.h>

#pragma config WDT = OFF, LVP = OFF, OSC = INTIO67, XINST = OFF

unsigned int Time;
unsigned int avg[3];

void main(void){
	unsigned float temp = 0;
	unsigned char speed,length;
	OSCCON = 0x72;      			//8MHz clock 500ns cycles
	while(!OSCCONbits.IOFS);		//wait for osc stable

	initPIC();

	while(1){
		GetPing();
		speed = 0;
		SetLED(0xFF);
		if(Time < 50){
			speed = 3;
			length = 5;
			SetLED(2);
			goto PlayIt;
		}
		if(Time < 80){
			speed = 6;
			length = 5;
			SetLED(1);
			goto PlayIt;
		}
		if(Time < 125){
			speed = 9;
			length = 5;
			SetLED(0);
			goto PlayIt;
		}
PlayIt:
		if(speed>0)
			PlayTone(speed,length);

	}

}
void SetLED(char led){
	LED0 = LED1 = LED2 = 0;

	if(led == 0) LED0 = 1;	
	if(led == 1) LED1 = 1;
	if(led == 2) LED2 = 1;
}
void PlayTone(unsigned char time,unsigned char dur){
	unsigned char x;
	for(x=0;x<dur;x++){
		BuzzOut = 1;
		Delay10KTCYx(time*2);
		BuzzOut = 0;
		Delay10KTCYx(time/2);
	}
		BuzzOut = 0;
}
void initPIC(void){
	TRISA = 0x00;
	TRISB = 0x00;
	TRISC = 0x00;

//----------------------
// PING INIT			
//----------------------
	PingDir = 0;		//PING pin is output
	PingOut = 0;		//Start with PING pin LOW
//----------------------
// Buzz INIT			
//----------------------
	BuzzDir = 0;
	BuzzOut = 0;

	T0CON   = 0b00001000;

}

void GetPing(void){
	unsigned char x;
	unsigned int MyPing = 0;
	char Done = 0;
	
for(x=0;x<3;x++){
	PingDir = 0;

	PingOut = 0;
	Delay16uS();
	PingOut = 1;
	Delay10TCY();
	PingOut = 0;

	PingDir = 1;
	PingIn = 0;
	while(!PingIn);

	while(PingIn){
		MyPing++;
	}

	avg[x] = MyPing / 10;
	Delay10KTCYx(15);
}
	Time = (avg[0]+avg[1]+avg[2]) / 3;

}

//------------------------------------------------------
// Used MPLAB Stopwatch. Exact 16uS from call to return.
//------------------------------------------------------
void Delay16uS(void){
	Delay10TCY();
	Nop();Nop();
}
//------------------------------------------------------
// Used MPLAB Stopwatch. Exact 400uS from call to return.
//------------------------------------------------------
void Delay400uS(void){
	Delay100TCYx(3);
	Delay10TCYx(9);
	Nop();Nop();Nop();Nop();Nop();Nop();
}

Forgot the main.h
Code:
//main.h
#ifndef __MAIN_H
#define __MAIN_H

void main(void);
void initPIC(void);
void GetPing(void);
void Delay16uS(void);
void Delay400uS(void);
void PlayTone(unsigned char time,unsigned char dur);
void SetLED(char led);

#define PingDir  TRISCbits.TRISC3
#define PingOut  LATCbits.LATC3
#define PingIn   PORTCbits.RC3

#define BuzzDir  TRISCbits.TRISC2
#define BuzzOut  LATCbits.LATC2

#define LED0  LATBbits.LATB0
#define LED1  LATBbits.LATB1
#define LED2  LATBbits.LATB2

#endif
 
Last edited:
Status
Not open for further replies.

New Articles From Microcontroller Tips

Back
Top