SaltForTheThirsty
Ping)))Bridge()
This serves as an inbetween for a microcontroller and the Parallax Ping)) sonar. It triggers the sonar and stores the distance and sends it out the SPI upon request. It can return about 55 measurements a second at a distance of 10 feet, which is about the max distance of the Parallax Ping))). Code expects a 3.69 MHz clock.
Ping)))Bridge:
Download Files.
/*
* PingBridge.c
*
* Created: 12/8/2012 9:23:20 PM
* Author: Daniel Mack
*
* Function:
* to serve as an inbetween for a microcontroller and the Parallax Ping)) sonar.
* Triggers the sonar and stores the distance and sends it out the SPI
* in slave mode. Can return about 55 measurements a second at
* distance = 10 feet, which about the max of the Parallax Ping)))
*
* PORT B PIN 0 is connected to the Sig pin of the Ping)))
*
* code good at 3.69 MHz
*/
// includes
#include
#include
#include
// defines
// TIMEOUT should be set at (.0185*fclk)/8
#define TIMEOUT 8533 // timeout at about 10.3 feet at 3.69 MHz
#define low(x) ((x) & 0x00FF)
#define high(x) (((x)>>8)& 0x00FF)
// function prototypes
uint16_t time_stamp(uint8_t);
// global variables
volatile uint8_t edgeDetect = 0;
volatile uint8_t conversionComplete = 0;
volatile uint16_t distance = 0;
int main(){
// initialize hardware
// Ports
DDRB = (1<<PB0) | (1<<PB4); // MISO and PB0
// spi
SPCR = (1<<SPIE) | (1<<SPE); // interrupt, f/4
SPDR = 0;
// timer counter 1
OCR1A = TIMEOUT;
uint16_t risingEdge = 0;
uint16_t fallingEdge = 0;
while(1){
// trigger the sonar with a 5 micro second pulse
DDRB |= (1<<PB0);
cli();
// atmega88pa pins can be flipped by writing to them
// hence the two writes and not one write and one
// clear
PINB |= (_BV(PB0));
_delay_us(5);
PINB |= (_BV(PB0));
sei();
// PB0 now input to receive pulse from Ping)))
DDRB &=~(1<<PB0);
// Start Timer
// set timer up to capture incoming pulse
// rising edge, ctc, OCR1A as top, f/8
TCCR1B = (1<<ICES1) | (1<<WGM12) | (1<<CS11);
// clear pending interrupts
TIFR1 |= (1<<ICF1) | (1<<OCF1B) | (1<<OCF1A);
// input capture compA interrupt enabled
TIMSK1 = (1<<ICIE1) | (1<<OCIE1A);
// look for rising edge, timestamp it then look for falling edge, timestamp it.
// Do math to find distance. Distance is just a number of counts not normal units
// ie inches or cm.
while(conversionComplete == 0){
if(edgeDetect == 1)
risingEdge = time_stamp(0);
if(edgeDetect == 3){
cli();
fallingEdge = time_stamp(1);
distance = fallingEdge - risingEdge;
SPDR = low(distance);
conversionComplete = 1;
sei();
}
}
// delay 200 microseconds before next reading
// as instructed by Ping))) datasheet
// stop and reset timer
conversionComplete = 0;
TCCR1B = 0x00;
TCNT1 = 0x0000;
TIMSK1 = 0x00;
_delay_us(200);
}
}
// functions
// returns timer value at rising edge, sets timer to
// look for falling edge and returns timer value
// at falling edge
uint16_t time_stamp(uint8_t c){
switch(c){
case 0:
edgeDetect++;
TCCR1B &= ~_BV(ICES1);
break;
case 1:
edgeDetect = 0;
break;
}
return(ICR1);
}
// ISR
ISR(SPI_STC_vect){
SPDR = high(distance);
}
// sets resets after timeout
ISR(TIMER1_COMPA_vect){
conversionComplete = 1;
edgeDetect = 0;
SPDR = 0;
distance = 0;
}
ISR(TIMER1_CAPT_vect){
edgeDetect++;
}