This shows you the differences between two versions of the page.
| Next revision | Previous revision | ||
| et:examples:sensor:ultrasonic [2009/02/27 11:23] – tekitatud mikk.leini | et:examples:sensor:ultrasonic [2009/11/05 13:30] (current) – eemaldatud mikk.leini | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| - | ====== Ultraheli kaugusmõõdik ====== | ||
| - | Kasutatud on SRF 04 kaugusmõõdikut. | ||
| - | |||
| - | {{examples: | ||
| - | |||
| - | <code c> | ||
| - | // | ||
| - | // SFR04 ultrasonic distance measuring | ||
| - | // | ||
| - | // Mikk Leini | ||
| - | // | ||
| - | // 2009 | ||
| - | // | ||
| - | |||
| - | // Include avrlibc | ||
| - | #include < | ||
| - | #include < | ||
| - | #include < | ||
| - | |||
| - | // Include common library | ||
| - | #include " | ||
| - | |||
| - | // 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, | ||
| - | |||
| - | // Configure pins | ||
| - | #define SEGMENT_DISPLAY_LATCH | ||
| - | #define SEGMENT_DISPLAY_DATA_OUT | ||
| - | #define SEGMENT_DISPLAY_CLOCK | ||
| - | #define LEDR | ||
| - | #define US_TRIGGER | ||
| - | #define US_ECHO | ||
| - | |||
| - | // 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; // " | ||
| - | case 2 : map = 0b01011011; break; // " | ||
| - | case 3 : map = 0b01001111; break; // " | ||
| - | 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; | ||
| - | } | ||
| - | |||
| - | // 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, | ||
| - | |||
| - | // 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 (" | ||
| - | } | ||
| - | } | ||
| - | |||
| - | // | ||
| - | // Timer1 overflow interrupt | ||
| - | // | ||
| - | ISR(TIMER1_OVF_vect) | ||
| - | { | ||
| - | timestamp++; | ||
| - | } | ||
| - | |||
| - | // | ||
| - | // Ultrasonic initialization | ||
| - | // | ||
| - | void ultrasonic_init(void) | ||
| - | { | ||
| - | // Initial state | ||
| - | ultrasonic.state | ||
| - | 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, | ||
| - | |||
| - | // 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 (" | ||
| - | |||
| - | return result; | ||
| - | } | ||
| - | |||
| - | // | ||
| - | // Program entrance function | ||
| - | // | ||
| - | int main(void) | ||
| - | { | ||
| - | volatile unsigned short lowValue | ||
| - | 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, | ||
| - | sei(); | ||
| - | |||
| - | // Constantly try triggering ultrasonic pulses | ||
| - | ultrasonic_trigger(); | ||
| - | |||
| - | // Read ultrasonic result | ||
| - | INTEGRATE(value, | ||
| - | |||
| - | // Check for new lower limit | ||
| - | lowValue = MIN(lowValue, | ||
| - | |||
| - | // Check for new higher limit | ||
| - | highValue = MAX(highValue, | ||
| - | |||
| - | // 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); | ||
| - | } | ||
| - | } | ||
| - | </ | ||