Electronics & Embedded Systems

เล่น HY-SRF05 กับ AVR ATMEGA328p + Motelib Library

หลายท่านคงเคยใช้ Ultra Sonic Distance Sensor ตัวนี้มาบ้างแล้ว หรืออาจเคย Implement บน Arduino Platform ก็พูดได้ว่า ง่ายกว่า จะทำบน Interrupt บน C ของ AVR ตรงๆทำไม  ซึ่งก็ขอบอกว่า Accuracy แตกต่างกันอย่างแน่นอน ก่อนเริ่มขอให้อ่านการทำงานของ SRF05 และ Timer/Counter & PCINT ของ ATMEGA ได้จาก Link ต่อไปนี้

แล้วสามารถ Implement ตามได้โดย พลัน

#include <stdio.h>
#include <string.h>

#include <motelib/system.h>
#include <motelib/led.h>
#include <motelib/timer.h>
#include <motelib/uart.h>

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

volatile unsigned int microseconds = 0; // to save pulse length
volatile uint8_t interrupted = 0; // to indicate the interrupt has already occured
volatile uint8_t completed = 0; // inicate that the measurement is complete

#define ULTRASONIC_SPEED_OF_SOUND 33000 // cm per second

#define SRFout PC0 // SRF05 trigger pin is connected here
#define SRFin  PC1 // SRF05 echo pin is connected here

void init_SRF05(void) {
TCCR2A  = (1 << WGM21); // CTC Mode
OCR2A   = 15; // 155 steps -> interrupt every 10µs
//  where  ((12000000 / 8) / 100000) – 1 = 15
TIMSK2 |= (1 << OCIE2A); // Enable compare interrupt
//~~~~~~~~~~~~~~~~~
DDRC   |=  (1 << SRFout); // set as output, the TRIGGER
PORTC  &= ~(1 << SRFout); // set it to LOW

DDRC   &= ~(1 << SRFin);  // set as input, the ECHO
PORTC  |=  (1 << SRFin);  // internal pull-up

PCICR  |=  (1 << PCIE1);  // set PCIE1 to enable PCMSK1 scan,
//  so that PC0 -> PCINT8
//          PC1 -> PCINT9
PCMSK1 |= (1 << PCINT9);  // set PCINT9 to trigger an interrupt on state change
//~~~~~~~~~~~~~~~~~
}

ISR(PCINT1_vect) { // for PCINT9
if(PINC & (1 << SRFin)) { // LOW to HIGH pin change
//ledToggle(1);

if (interrupted == 0) { // only if there hasn’t been triggered on a rising edge yet
TCCR2B |= (1 << CS21); // start Timer with prescaler 8
interrupted = 1; // to indicate, that an interrupt has already occured
}

} else { // HIGH to LOW pin change
//ledToggle(2);

if (interrupted == 1) {
TCCR2B &= ~(1<<CS21); // stop Timer
interrupted = 0; // reset variable
completed = 1; // variable to indicate end of measurement
}
}
}

ISR(TIMER2_COMPA_vect) { //Interrput every 10µs
microseconds += 10;
}

static Timer t_dist;

void get_dist(Timer *t) {

uint16_t dist = 0;

if (completed == 0) {
ledSet(0, 1);

TCNT2 = 0; // set timer to 0

dist = 0; // reset distance to prevent adding up the distances
microseconds = 0; // reset microseconds counter variable

sei(); // turn global interrupt on

PORTC |= (1 << SRFout); // trigger the SRF05 measurement
_delay_us(12); // 12µs trigger signal
PORTC &= ~(1 << SRFout);

} else {
ledSet(0, 0);

completed = 0; // reset
// Convert time to distance:
//   distance = timer * (1 / (F_CPU / 8)) * speed / 2
dist = microseconds / 58;
char str[10];
sprintf(str, “%d\n\r”, dist);
uartWrite(“dist: “, 6);
uartWrite(str, strlen(str));
}
}

void boot() {
init_SRF05();

timerCreate(&t_dist);
timerStart(&t_dist, TIMER_PERIODIC, 250, get_dist);

uartEnable(true, true);
}

ปล. Motelib เป็น Lite-stack OS สำหรับ ATMEGA328p ซึ่งมีการเรียนการสอนที่ ม. เกษตร  หากโอกาสหน้ามีเวลาจะเรียนให้ทราบในเบื้องลึกอีกทีหนึ่ง

Advertisements
มาตรฐาน

ใส่ความเห็น

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / เปลี่ยนแปลง )

Twitter picture

You are commenting using your Twitter account. Log Out / เปลี่ยนแปลง )

Facebook photo

You are commenting using your Facebook account. Log Out / เปลี่ยนแปลง )

Google+ photo

You are commenting using your Google+ account. Log Out / เปลี่ยนแปลง )

Connecting to %s