/* * srf04.c * * Description: * This is a driver for the SRF04 ultrasonic module for the CCS * PICC compiler. This version is a blocking version of the driver. A delay * of up to 46 ms may be incurred while waiting for the feedback from * the sensor to calculate the distance. * * For information of the SRF04 module, go to: * http://www.robot-electronics.co.uk/htm/srf04.htm * * Author: Martin Dubuc * http://mdubuc.freeshell.org/Robotics/Tips.html * * Creation date: March 13, 2005 */ /* * Calculation of the distance with the ultrasonic module relies * on the microcontroller timing services. The distance is * calculated according to the amount of time an ultrasound takes * to echo on obstacles. The shorter it takes for the echo to come back, * the closer the obstacle. */ #ifdef __PCM__ #include <16f877.h> /* Microcontroller configuration bits */ #fuses HS,NOPROTECT,NOWDT,BROWNOUT,PUT,NOLVP #ORG 0x1F00,0x1FFF {} /* Reserve memory for bootloader for the 8k 16F876/7 */ #device *=16 /* Allow RAM to expand beyond 256 bytes */ #else // PIC18F #include <18f452.h> #fuses NOOSCSEN,HS,BORV20,NOBROWNOUT,PUT,WDT128,NOWDT,CCP2C1,NODEBUG,NOLVP,STVREN,NOPROTECT,NOWRT,NOWRTD,NOWRTB #device *=16 /* Allow RAM to expand beyond 256 bytes */ /* Remap reset and interrupt vector for the PIC18F bootloader */ #BUILD(reset=0x200) #BUILD(interrupt=0x208) /* Reserve memory for the PIC18F bootloader */ #ORG 0,0x1FF dummy() { #ASM NOP #ENDASM } #endif // _PCM /* The 20_MHZ_CLOCK define is used to indicate whether we are using a 4 MHz or 20 MHz clock */ #define 20_MHZ_CLOCK /* Set the clock speed; based on the 20_MHZ_CLOCK define. If 20_MHZ_CLOCK is defined, set the clock to 20 MHz, otherwise, set the clock to 4 MHz. */ #ifdef 20_MHZ_CLOCK #use delay(clock=20000000) #else #use delay(clock=4000000) #endif /* Directive for RS-232 interface */ #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7) /* Ultrasonic module definitions */ /* Delay definitions */ #define INPUT_TRIGGER_DELAY 10 /* In microseconds */ /* Delay between end of echo pulse and trigger pulse is 10 ms */ #define DELAY_BETWEEN_ECHO_PULSE 10 /* Maximum elapsed time for an echo pulse is approx. 36 ms */ #ifdef 20_MHZ_CLOCK #define MAX_DELAY_ECHO_PULSE 44000 /* Number of timer increments for 35 ms using prescale of 4 */ #else #define MAX_DELAY_ECHO_PULSE 35000 /* Number of timer increments for 35 ms using prescale of 1 */ #endif #ifdef 20_MHZ_CLOCK /* Every Timer1 increment takes 0.8 us with prescale of 4 */ /* t us / 1000000 us/s * (347 m/s) * (100 cm/m) / 2 */ /* = # increments * 0.8 / 5000 * 347 or roughly t / 72 */ #define GET_DISTANCE(t) (t / 72) #else /* 4 MHz clock */ /* Every increment takes 1 us */ /* t us / 1000000 us/s * (347 m/s) * (100 cm/m) / 2 */ /* = t / 5000 * 347 or roughly t / 58 */ #define GET_DISTANCE(t) (t / 58) #endif /* Hardware pin definition */ #define ULTRASONIC_TX PIN_B3 #define ULTRASONIC_RX PIN_B4 #define DISTANCE_INFINITE (0xffff) /* Type definitions */ typedef int uint8_t; typedef long uint16_t; /* Variable definitions */ uint16_t echo_delay; /* Global variable definitions */ uint16_t distance = DISTANCE_INFINITE; /* This is the distance of the closest object ahead of the ultrasonic module (in cm). If set to INFINITE, there are no objects in sight. */ /* Function prototypes */ /* Public interface */ void main(void); void init_pins(void); void init_timers(void); void init(void); void monitor_distance_sensor(); /* Driver implementation */ /* Init hardware pins: Set up the TRIS and set the pins to their * default values. */ void init_pins(void) { /* Set up the various pins in/out */ set_tris_b(0b00010000); /* B3 is output. B4 is input. Rest is unused */ /* Set initial condition for ultrasonic transmitter */ output_low(ULTRASONIC_TX); } /* init_pins */ /* Driver initialization. Initialize pins, global variables and timers. */ void init(void) { init_pins(); init_timers(); printf("SRF04 Ultrasonic Module Driver\r\n"); } /* init */ /* Initialize the Timer0 timer. */ void init_timers(void) { /* Set up Timer1 */ /* Following settings will allow for 1 cm precision */ #ifdef 20_MHZ_CLOCK setup_timer_1(T1_INTERNAL | T1_DIV_BY_4); #else // 4 MHz setup_timer_1(T1_INTERNAL | T1_DIV_BY_1); #endif } /* init_timers */ /* This is the main control loop. */ void main(void) { init(); for ( ; ; ) { monitor_distance_sensor(); printf("echo delay %lu\r\n", echo_delay); printf("distance %lu\r\n", distance); } } /* main */ void monitor_distance_sensor(void) { /* First, toggle the ULTRASONIC_TX pin to generate echo signal. */ /* Pull ultrasonic TX pin high */ output_high(ULTRASONIC_TX); /* Get the sensor the chance to see this */ delay_us(INPUT_TRIGGER_DELAY); output_low(ULTRASONIC_TX); /* Wait for pulse on ULTRASONIC_RX pin. Distance is measured by using time it takes for ultrasound to echo, which is calculated according to length of echo pulse on ULTRASONIC_RX pin. */ /* Wait for low to high transition on ULTRASONIC_RX pin. */ for ( ; !input(ULTRASONIC_RX); ) ; /* Detected a low to high transition */ /* Reset timer. */ set_timer1(0); /* Wait for high to low transition on ULTRASONIC_RX pin. */ for ( ; input(ULTRASONIC_RX); ) ; /* Detected a high to low transition */ echo_delay = get_timer1(); #ifdef 20_MHZ_CLOCK if (echo_delay >= 44000) { #else if (echo_delay >= 35000) { #endif distance = DISTANCE_INFINITE; } else { distance = GET_DISTANCE(echo_delay); } /* Make sure there is an appropriate delay between end of echo and trigger pulse. If the delay between calls to monitor_distance_sensor is greater than 10 ms, then this delay can be removed. */ delay_ms(DELAY_BETWEEN_ECHO_PULSE); } /* monitor_distance_sensor */