This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revision | |||
| en:examples:projects:finger_counter [2009/03/05 12:10] – raivo.sell | en:examples:projects:finger_counter [2010/02/04 12:32] (current) – removed mikk.leini | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| - | ====== Project - Finger counter ====== | ||
| - | |||
| - | * {{examples: | ||
| - | |||
| - | ===== main.c ===== | ||
| - | |||
| - | The project uses IR sensor and servo motor for scanning sector. | ||
| - | Putting hands on the front of scanning sector the result should be number of spread out fingers. | ||
| - | |||
| - | |||
| - | |||
| - | <code c> | ||
| - | #include < | ||
| - | #include < | ||
| - | #include < | ||
| - | #include " | ||
| - | #include " | ||
| - | #include " | ||
| - | #include " | ||
| - | #include " | ||
| - | #include " | ||
| - | |||
| - | // Math operations | ||
| - | #define DIFF(a, b) ((a) < (b) ? (b) - (a) : (a) - (b)) | ||
| - | #define INTEGRATE(value, | ||
| - | |||
| - | // | ||
| - | // Main entrance | ||
| - | // | ||
| - | int main(void) | ||
| - | { | ||
| - | unsigned short distance, compare_distance = 0; | ||
| - | unsigned char matches = 0, num_fingers = 0; | ||
| - | signed short servo_pos = -100, scan_dir = 1; | ||
| - | char text[10]; | ||
| - | |||
| - | // Initialize | ||
| - | adc_init(); | ||
| - | dcmotors_init(); | ||
| - | segment_display_init(); | ||
| - | servomotors_init(); | ||
| - | setup_output_pin(LED_RED); | ||
| - | |||
| - | lcd_init(LCD_DISP_ON); | ||
| - | lcd_clrscr(); | ||
| - | lcd_puts(" | ||
| - | |||
| - | // Endless loop | ||
| - | while (1) | ||
| - | { | ||
| - | // Scan | ||
| - | servomotors_position(1, | ||
| - | servo_pos += scan_dir; | ||
| - | |||
| - | // Servo on edge ? | ||
| - | if ((servo_pos < -100) || (servo_pos > 100)) | ||
| - | { | ||
| - | scan_dir = (servo_pos > 0 ? -1 : 1); | ||
| - | |||
| - | // Output results | ||
| - | segment_display_write(num_fingers); | ||
| - | itoa(num_fingers, | ||
| - | lcd_gotoxy(0, | ||
| - | lcd_puts(text); | ||
| - | lcd_puts(" | ||
| - | |||
| - | // Reset fingers count | ||
| - | num_fingers = 0; | ||
| - | } | ||
| - | |||
| - | // Measure distance | ||
| - | distance = adc_sample_value(0, | ||
| - | |||
| - | // Check for drastic changes | ||
| - | // Look for decreasing distance (increasing sensor output voltage) | ||
| - | if (distance > compare_distance + 100) | ||
| - | { | ||
| - | // Light on finger | ||
| - | clear_pin(LED_RED); | ||
| - | |||
| - | // Changes has to last for some time | ||
| - | if (matches++ == 5) | ||
| - | { | ||
| - | // Count fingers | ||
| - | num_fingers++; | ||
| - | } | ||
| - | } | ||
| - | else | ||
| - | { | ||
| - | // Reset matches and turn off the LED | ||
| - | set_pin(LED_RED); | ||
| - | matches = 0; | ||
| - | } | ||
| - | |||
| - | // Calculate compare distance (integrated distance) | ||
| - | INTEGRATE(compare_distance, | ||
| - | |||
| - | // Pause | ||
| - | _delay_ms(10); | ||
| - | } | ||
| - | } | ||
| - | </ | ||
| - | |||
| - | ===== configuration.h ===== | ||
| - | |||
| - | <code c> | ||
| - | // Hardware pin configurations | ||
| - | |||
| - | #define BUTTON_1 | ||
| - | #define BUTTON_2 | ||
| - | #define BUTTON_3 | ||
| - | |||
| - | #define LED_RED | ||
| - | #define LED_YELLOW | ||
| - | #define LED_GREEN | ||
| - | |||
| - | #define DCMOTOR_1A | ||
| - | #define DCMOTOR_1B | ||
| - | #define DCMOTOR_2A | ||
| - | #define DCMOTOR_2B | ||
| - | #define DCMOTOR_3A | ||
| - | #define DCMOTOR_3B | ||
| - | #define DCMOTOR_4A | ||
| - | #define DCMOTOR_4B | ||
| - | |||
| - | #define SERVOMOTOR_1 | ||
| - | #define SERVOMOTOR_2 | ||
| - | |||
| - | #define SEGMENT_DISPLAY_LATCH | ||
| - | #define SEGMENT_DISPLAY_DATA_OUT | ||
| - | #define SEGMENT_DISPLAY_CLOCK | ||
| - | </ | ||
| - | |||
| - | ===== adc.c ===== | ||
| - | |||
| - | <code c> | ||
| - | #include < | ||
| - | #include " | ||
| - | |||
| - | // | ||
| - | // ADC initialization | ||
| - | // | ||
| - | void adc_init(void) | ||
| - | { | ||
| - | // ADC setup | ||
| - | // Prescaler 8 | ||
| - | ADCSRA = BIT(ADEN) | BIT(ADPS1) | BIT(ADPS0); | ||
| - | |||
| - | // Reference voltage to external (+5V) | ||
| - | ADMUX = BIT(REFS0); | ||
| - | } | ||
| - | |||
| - | // | ||
| - | // ADC conversion waiting | ||
| - | // | ||
| - | void adc_wait_until_done(void) | ||
| - | { | ||
| - | while (IS_BIT_SET(ADCSRA, | ||
| - | { | ||
| - | asm volatile (" | ||
| - | } | ||
| - | } | ||
| - | |||
| - | // | ||
| - | // ADC channel value sampling | ||
| - | // | ||
| - | unsigned short adc_sample_value(unsigned char channel, unsigned char num_samples) | ||
| - | { | ||
| - | unsigned short result = 0; | ||
| - | |||
| - | // Specify channel | ||
| - | ADMUX &= 0xF0; | ||
| - | ADMUX |= channel & 0x0F; | ||
| - | |||
| - | // Take test sample to "warm up" converter | ||
| - | // Usually the first sample is discarded | ||
| - | SET_BIT(ADCSRA, | ||
| - | adc_wait_until_done(); | ||
| - | |||
| - | // Real sampling, sum up specifed number of samples | ||
| - | for (unsigned char i = 0; i < num_samples; | ||
| - | { | ||
| - | SET_BIT(ADCSRA, | ||
| - | adc_wait_until_done(); | ||
| - | |||
| - | // Sum-up | ||
| - | result += ADCW; | ||
| - | } | ||
| - | |||
| - | // Return averaged result | ||
| - | return (result / num_samples); | ||
| - | } | ||
| - | </ | ||
| - | |||
| - | ===== adc.h ===== | ||
| - | |||
| - | <code c> | ||
| - | // ADC function headers | ||
| - | void adc_init(void); | ||
| - | unsigned short adc_sample_value(unsigned char channel, unsigned char num_samples); | ||
| - | </ | ||
| - | |||
| - | ===== motors.c ===== | ||
| - | |||
| - | <code c> | ||
| - | #include < | ||
| - | #include " | ||
| - | #include " | ||
| - | |||
| - | // PWM full period | ||
| - | // 14.745600 Mhz / 8 / 50 Hz = 36864 | ||
| - | #define PWM_PERIOD | ||
| - | |||
| - | // PWM servo middle position | ||
| - | // 36864 / 20 ms * 1.5 ms = 2764 | ||
| - | #define PWM_MIDDLE_POS | ||
| - | |||
| - | // PWM ratio to get position from -100 to 100 | ||
| - | // 36864 / 20 ms / 2 / 100 | ||
| - | // We add +1 to get a full range and a little bit more | ||
| - | #define PWM_RATIO | ||
| - | |||
| - | // | ||
| - | // Initialize motors | ||
| - | // | ||
| - | void dcmotors_init(void) | ||
| - | { | ||
| - | setup_output_pin(DCMOTOR_1A); | ||
| - | setup_output_pin(DCMOTOR_1B); | ||
| - | setup_output_pin(DCMOTOR_2A); | ||
| - | setup_output_pin(DCMOTOR_2B); | ||
| - | setup_output_pin(DCMOTOR_3A); | ||
| - | setup_output_pin(DCMOTOR_3B); | ||
| - | setup_output_pin(DCMOTOR_4A); | ||
| - | setup_output_pin(DCMOTOR_4B); | ||
| - | } | ||
| - | |||
| - | // | ||
| - | // Drive command for specified motor | ||
| - | // | ||
| - | void dcmotors_drive(unsigned char nr, signed char dir) | ||
| - | { | ||
| - | switch (nr) | ||
| - | { | ||
| - | case 1: | ||
| - | set_pin_to(DCMOTOR_1A, | ||
| - | set_pin_to(DCMOTOR_1B, | ||
| - | break; | ||
| - | |||
| - | case 2: | ||
| - | set_pin_to(DCMOTOR_2A, | ||
| - | set_pin_to(DCMOTOR_2B, | ||
| - | break; | ||
| - | |||
| - | case 3: | ||
| - | set_pin_to(DCMOTOR_3A, | ||
| - | set_pin_to(DCMOTOR_3B, | ||
| - | break; | ||
| - | |||
| - | case 4: | ||
| - | set_pin_to(DCMOTOR_4A, | ||
| - | set_pin_to(DCMOTOR_4B, | ||
| - | break; | ||
| - | } | ||
| - | } | ||
| - | |||
| - | // | ||
| - | // Intialize servo motors | ||
| - | // | ||
| - | void servomotors_init(void) | ||
| - | { | ||
| - | setup_output_pin(SERVOMOTOR_1); | ||
| - | |||
| - | setup_output_pin(SERVOMOTOR_2); | ||
| - | |||
| - | // Set timer control registers | ||
| - | // Clear OUTA and OUTB on compare match | ||
| - | // Fast PWM mode with ICR = TOP | ||
| - | // Prescaler 8 | ||
| - | TCCR1A = BIT(COM1A1) | BIT(COM1B1) | BIT(WGM11); | ||
| - | TCCR1B = BIT(CS11) | BIT(WGM13) | BIT(WGM12); | ||
| - | |||
| - | // TOP period | ||
| - | ICR1 = PWM_PERIOD; | ||
| - | } | ||
| - | |||
| - | // | ||
| - | // Position servo motors | ||
| - | // pos is from -100 to 100 | ||
| - | // | ||
| - | void servomotors_position(unsigned char nr, signed short pos) | ||
| - | { | ||
| - | // | ||
| - | switch (nr) | ||
| - | { | ||
| - | case 1: OCR1A = PWM_MIDDLE_POS + pos * PWM_RATIO; break; | ||
| - | case 2: OCR1B = PWM_MIDDLE_POS + pos * PWM_RATIO; break; | ||
| - | } | ||
| - | } | ||
| - | </ | ||
| - | |||
| - | ===== motors.h ===== | ||
| - | |||
| - | <code c> | ||
| - | // Motor function headers | ||
| - | void dcmotors_init(void); | ||
| - | void dcmotors_drive(unsigned char nr, signed char dir); | ||
| - | void servomotors_init(void); | ||
| - | void servomotors_position(unsigned char nr, signed short pos); | ||
| - | </ | ||
| - | |||
| - | ===== segment_display.c ===== | ||
| - | |||
| - | <code c> | ||
| - | #include < | ||
| - | #include < | ||
| - | #include " | ||
| - | #include " | ||
| - | |||
| - | // | ||
| - | // 7 segment display initialization | ||
| - | // | ||
| - | void segment_display_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); | ||
| - | } | ||
| - | </ | ||
| - | |||
| - | ===== segment_display.h ===== | ||
| - | |||
| - | <code c> | ||
| - | // 7 segment display function headers | ||
| - | void segment_display_init(void); | ||
| - | void segment_display_write(unsigned char digit); | ||
| - | </ | ||