/* * main.c * * Description: * This is a driver for the SRF04 ultrasonic module for the CCS * PICC compiler. * * For information of the SRF04 module, go to: * http://www.robot-electronics.co.uk/htm/srf04.htm * * Author: Martin Dubuc (martin.dubuc@rogers.com) * http://members.rogers.com/martin.dubuc/Robotics/Tips.html * * Creation date: February 26, 2003 */ /* * 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 PIC16F877 *=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 PIC18F452 *=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 according to the 20_MHZ_CLOCK definition. If 20_MHZ_CLOCK is defined, set clock speed to 20 MHz, otherwise, set it 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 */ #define DELAY_BETWEEN_ECHO_PULSE 10 /* Delay between end of echo and trigger pulse */ /* 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 /* State definitions */ #define START_TX 0 #define WAIT_FOR_RX_HIGH 1 #define WAIT_FOR_RX_LOW 2 #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 with prescale of 1 */ /* t us / 1000000 us/s * (347 m/s) * (100 cm/m) / 2 */ /* = # increments / 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 INFINITE (0xffff) /* Type definitions */ typedef int uint8_t; typedef long uint16_t; /* Variable definitions */ uint16_t echo_delay; uint8_t state; boolean distance_ready = FALSE; /* Global variable definitions */ uint16_t 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_globals(void); void init_timers(void); void init(void); void rtcc_isr(void); void rb_isr(void); /* 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 */ /* Initialize all global variables. This is not strictly required * because we initialize all global variables to default values, but * would be important if we ever re-initialized the values after the * microcontroller starts running. */ void init_globals(void) { distance_ready = FALSE; state = START_TX; } /* init_globals */ /* Driver initialization. Initialize pins, global variables, * interrupts and timers. */ void init(void) { init_pins(); init_globals(); init_timers(); // Enable Timer0 and RB4-RB7 interrupts enable_interrupts(INT_RB); enable_interrupts(GLOBAL); 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 ( ; ; ) { if (state == START_TX) { /* First, toggle the ULTRASONIC_TX pin to generate echo signal. */ /* Pull ultrasonic TX pin high */ output_high(ULTRASONIC_TX); /* Get the other side 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. Will detect the pulse in the RB interrupt service routine (ISR). We use ISR to allow us to continue processing while transmitting/receiving ultrasounds. */ set_timer1(0); state = WAIT_FOR_RX_HIGH; } if (get_timer1() > MAX_DELAY_ECHO_PULSE) distance_ready = TRUE; /* In state 1, wait for low to high transition on ULTRASONIC_RX pin. We will detect this transition in the RB interrupt service routine. */ /* In state 2, wait for high to low transition on ULTRASONIC_RX pin. We will detect this transition in the RB interrupt service routine. */ if (distance_ready) { #ifdef 20_MHZ_CLOCK if (get_timer1() >= 44000) { #else if (get_timer1() >= 35000) { #endif printf("distance = INFINITE\r\n"); distance = INFINITE; } else { distance = GET_DISTANCE(echo_delay); printf("distance = %lu\r\n", distance); } distance_ready = FALSE; // Prepare for next reading state = START_TX; /* Make sure there is an appropriate delay between end of echo and trigger pulse. */ delay_ms(DELAY_BETWEEN_ECHO_PULSE); delay_ms(500); } delay_us(20); } } /* main */ #int_rb void rb_isr(void) { if ((state == WAIT_FOR_RX_HIGH) && input(ULTRASONIC_RX)) { /* Detected a low to high transition */ state = WAIT_FOR_RX_LOW; set_timer1(0); } if ((state == WAIT_FOR_RX_LOW) && !input(ULTRASONIC_RX)) { /* Detected a high to low transition */ echo_delay = get_timer1(); distance_ready = TRUE; } } /* rb_isr */