This is an old revision of the document!


Ultrasonic distance measure

SRF04 example

Trigger (blue wire) is connected to PB2 Echo (yellow wire) is connected to PB3

Red and Black wires are +5 V supply

//
// SFR04 ultrasonic distance measuring
//
// Mikk Leini
//
// 2009
//
 
// Include avrlibc
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
 
// Include common library
#include "pinops.h"
 
// Configuration
#define INTEGRATION_STEP 5
 
// Math operations
#define MIN(a, b)   ((a) < (b) ? (a) : (b))
#define MAX(a, b)   ((a) > (b) ? (a) : (b))
#define INTEGRATE(value, new_value, n)  value = (value * (n - 1) + new_value) / n;
 
// Configure pins
#define SEGMENT_DISPLAY_LATCH      PORTPIN(G, 2)
#define SEGMENT_DISPLAY_DATA_OUT   PORTPIN(C, 6)
#define SEGMENT_DISPLAY_CLOCK      PORTPIN(C, 7)
#define LEDR                       PORTPIN(C, 5)
#define US_TRIGGER                 PORTPIN(B, 2) // blue
#define US_ECHO                    PORTPIN(B, 3) // yellow
 
// Ultrasonic data structure
struct
{
	unsigned char state;
	unsigned long front;
	unsigned short result;
} ultrasonic;
 
// 16 bit timestamp
volatile unsigned long timestamp = 0;
 
//
// 7 segment display initialization
//
void segment_diplay_init(void)
{
	// Set latch, data out and clock pins as output
	setup_output_pin(SEGMENT_DISPLAY_LATCH);
	setup_output_pin(SEGMENT_DISPLAY_DATA_OUT);
	setup_output_pin(SEGMENT_DISPLAY_CLOCK);	
}
 
//
// Digit writing to 7 segment display
//
void segment_display_write(unsigned char digit)
{
	unsigned char map;
 
	// Decimal to segment map
	switch (digit)
	{
		case 0 : map = 0b00111111; break; // Every bit corresponds to one segment
		case 1 : map = 0b00000110; break; // "1"
		case 2 : map = 0b01011011; break; // "2"
		case 3 : map = 0b01001111; break; // "3" and so on
		case 4 : map = 0b01100110; break; 
		case 5 : map = 0b01101101; break; 
		case 6 : map = 0b01111100; break; 
		case 7 : map = 0b00000111; break;
		case 8 : map = 0b01111111; break; 
		case 9 : map = 0b01100111; break;  
		default: map = 0b01111001;        // E like Error
	}	
 
	// Latch low
	clear_pin(SEGMENT_DISPLAY_LATCH);
 
	// Send every bit in the byte. MSB (most significant bit) first.
	for (signed char i = 7; i >= 0; i--)
	{
		// If bit is set, sets the data out pin, otherwise not		
		set_pin_to(SEGMENT_DISPLAY_DATA_OUT, IS_BIT_SET(map, i));
 
		// Clock high for certain period
		set_pin(SEGMENT_DISPLAY_CLOCK)
		_delay_us(1);
 
		// Clock low for certain period		
		clear_pin(SEGMENT_DISPLAY_CLOCK)
		_delay_us(1);
	}
 
	// Latch high 	
	set_pin(SEGMENT_DISPLAY_LATCH);
}
 
 
//
// 0.1ms clock Timer1
//
void clock_init(void)
{ 		
	// Fast PWM, Top = ICR, Prescaler = 1
	TCCR1A = BIT(WGM11);
	TCCR1B = BIT(WGM13) | BIT(WGM12) | BIT(CS10);
 
	// Top = 1475
	// Clock = 14.745600 Mhz / 1475 = ~10 kHz
	// Period = 1 / Clock = 0.1 ms
	ICR1 = 1475;
 
	// Enable overflow interrupt
	TIMSK = BIT(TOIE1);
}
 
//
// Delay
// Time in 0.1 of milliseconds
//
void delay(unsigned int time)
{
	unsigned long end_time, temporary = 0;
 
	// Interrupt safe timestamp waiting
	cli();
	end_time = timestamp + time;
	sei();
 
	while (temporary < end_time)
	{
		cli();
		temporary = timestamp;
		sei();
		asm volatile ("nop");
	}
}
 
//
// Timer1 overflow interrupt
//
ISR(TIMER1_OVF_vect)
{
	timestamp++;	
}
 
//
// Ultrasonic initialization
//
void ultrasonic_init(void)
{
	// Initial state
	ultrasonic.state  = 0;
	ultrasonic.result = 0;
 
	// Setup pins
	setup_output_pin(US_TRIGGER);
	setup_input_pin(US_ECHO);
 
	// External interrupt on any logical change
	EICRB = BIT(ISC40);
 
	// Enable external interrupt 4
	EIMSK = BIT(INT4);
}
 
//
// Trigger ultrasonic pulse
//
void ultrasonic_trigger(void)
{
	// Cannot trigger when listening
	if (ultrasonic.state > 0)
		return;
 
	// Trigger ultrasonic pulse
	ultrasonic.state = 1;
	set_pin(US_TRIGGER);
	delay(1);
	clear_pin(US_TRIGGER);	
}
 
//
// External interrupt - on echo pulse
//
ISR(INT4_vect)
{
	unsigned char b;	
 
	get_pin_value(US_ECHO, b);
 
	// Rising edge ?
	if (b && (ultrasonic.state == 1))
	{
		ultrasonic.front = timestamp;
		ultrasonic.state = 2;
	}
 
	// Falling edge ?
	else if (!b && (ultrasonic.state == 2))
	{		
		ultrasonic.result = timestamp - ultrasonic.front;
		ultrasonic.state = 0;
	}
}
 
//
// Get ultrasonic result
//
unsigned short ultrasonic_getresult(void)
{
	unsigned short result;
 
	// Interrupt safe result reading
	cli();
	result = ultrasonic.result;	
	sei();
	asm volatile ("nop");
 
	return result;
}
 
//
// Program entrance function
//
int main(void)
{ 		 
	volatile unsigned short lowValue  = 0xFFFF;
	volatile unsigned short highValue = 0x0000;
	volatile unsigned short value = 0;
	volatile unsigned char relativeValue;
 
	// Initializing
	clock_init();
	ultrasonic_init();
	segment_diplay_init();	
	setup_output_pin(LEDR);
 
	// Enable global interrupts
	sei();	
 
 	// Endless loop
	while (1)
	{		
		// Blink LED every second
		cli();
		set_pin_to(LEDR, (timestamp % 10000) > 1000);							
		sei();
 
		// Constantly try triggering ultrasonic pulses
		ultrasonic_trigger();
 
		// Read ultrasonic result	
		INTEGRATE(value, ultrasonic_getresult(), INTEGRATION_STEP);
 
		// Check for new lower limit
		lowValue = MIN(lowValue, value);
 
		// Check for new higher limit
		highValue = MAX(highValue, value);
 
		// Calculate relative value
		// Range from lowValue to highValue is converted to 0 to 9		
		relativeValue = 9 * (value - lowValue) / (highValue - lowValue);
 
		// Write digit
		segment_display_write(relativeValue);		
 
		// Delay a while
		delay(50);
	}
}
en/examples/sensor/ultrasonic.1238586729.txt.gz · Last modified: 2020/07/20 09:00 (external edit)
CC Attribution-Share Alike 4.0 International
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0