به نام خدا!

سلام خدمت دوستان گل و همطنان عزیز!

امروز یه خورده به ماژول SRF05 ور رفتم، بالاخره به یه جاهایی رسیدم! اومدم تا دین ام رو ادا کنم و چیزایی رو که یاد گرفتم رو با شما عزیزان به اشتراک بگذارم!

راستی رحلت آیت الله هاشمی رفسنجانی رو هم تسلیت میگم! واقعا برای من که خیلی سخت بود...! (خدا رحمتش کنه)

خوب ببینید...! کار کرد این ماژول خیلی ساده است! دو تا چیز شبیه بلندگو داره، یکیش یه صوت میفرسته بعد میخوره به یه مانع بر میگرده اون یکی دیگش دریافت میکنه!

نحوه اتصال به میکرو هم خیلی سادست! با دو تا سیم وصل میشه به میکرو اسم یکیش Echo و دیگری اش Trig هست!

در واقع برای اینکه فاصله تا مانع رو اندازه گیری کنیم باید برای چند میکرو ثانیه یا میلی ثانیه یه پالس بفرستیم به پایه ECHO (یعنی برای چند میکرو ثانیه پایه ی مربوطه که همون Echo هست رو روی سطح 1 ولت منطقی قرار بدیم و دوباره روی 0 قرار بدیم، به این میگن پالس) برای مطالعه بیشتر میتونید توی نت سرچ کنید! چون من قصد توضیح این نیست بلکه میخوام نحوه اتصال و برنامه نویسی اش رو با میکرو توضیح بدم!

خوب برای برنامه نویسی این ماژول باید با تایمر کار کنیم! کار خیلی سادست!

ابتدا باید یکی از تایمر ها رو فعال کنیم! (من از تایمر 2 استفاده میکنم)

بعدش باید برای مدت کوتاه یه پالس به Echo بفرستیم!

بعد منتظر بمونیم که اون هم یه پالسی برامون بفرسته! با اندازه گیری زمان پالس میتونیم با فرمول های فیزیک ، فاصله رو بدست بیاریم!

خوب حالا میخوایم اینا رو به زبون کد بگیم!

1- ابتدا تایمر رو فعال میکنیم!

با کد زیر این کار رو انجام میدیم! (برای مطالعه بیشتر تایمر کانتر کلیک کنید)

   LPC_SC->PCONP |= 1<<22; // روشن کردن  واحد تایمر 2
LPC_TIM2->TCR = 0x02; // ریست کردن و خاموش کردن تایمر کانتر
LPC_TIM2->CTCR = 0; // زیاد بهش گیر ندید
LPC_TIM2->MR0 = 25000000-1; // تا این عدد میشمره و بعد وارد تابع وقفه میشه
LPC_TIM2->MCR = 3; // بعد از تساوی تایمر / کانمتر با رجیستر بالا تابع وقفه اجرا میشه و شمارش از اول شروع میشه
LPC_TIM2->TC = 0x0; // مقدار اولیه تایمر کانتر رو مشخص میکنیم
LPC_TIM2->PR = 0; // ضریب تقسیم
NVIC_EnableIRQ(TIMER2_IRQn); // فعال کردن وقفه ی تایمر کانتر 2


2- ارسال پالس به پایه Trig

خوب برای اینکار باید یکی از پایه های میکروکنترلر رو در نظر بگیرید! که من P0.0 رو در نظر گرفتم! بعدش به مدت 10 میلی ثانیه یا کمتر یا بیشتر این پایه رو فعال و دوباره غیر فعال میکنیم!

در ابتدا پایه مورد نظر رو خروجی قرار میدیم!

LPC_GPIO0->FIODIR = 1<<0;

بعدش باید یه پالس بفرستیم! به صورت زیر اینکار رو میکنیم!

   LPC_GPIO0->FIOSET = 1<<0;
Delay(10);
LPC_GPIO0->FIOCLR = 1<<0;

چگونه یک زمان ایجاد کنیم؟

لازم میدونم که یه نکته خیلی لازم رو بگم!

ببینید هر for یا while که اتفاق میفته 5 سیکل طول میکشه! به این ترتیب ما میتونیم یه زمان مدیریت شده ایجاد کنیم!

فرمول اونو میتونیم به صورت زیر در بیاریم

n=Time*CPU_CLK/5

یعنی باید زمانی که میخوام تولید کنیم رو در کلاک CPU ضرب کنبم و عدد بدست امده رو به 5 تقسیم کنیم حالا عدد بدست آمده (n) عددی هست که باید به while یا for بدیم!

مثال:

یه LED رو هر 20 میلی ثانیه به 20 میلی ثانیه روشن و خاموش کنید!

خوب باید 20 میلی ثانیه رو به ثانیه تبدیل کنیم که میشه 0.000020  ثانیه که باید این عدد رو وارد رابطه کنیم!

حالا از فرمول استفاده میکنیم!

n=0.000020*100000000/5    => n=400

یعنی حالا باید همچین کدی بنویسیم!

int a=400;
while(a--);

یعنی کد بالا 20 میلی ثانیه طول میکشه که اجرا بشه!


3- اندازه گیری طول پالس دریافت شده از Echo

خوب بعد از انجام مراحل گفته شده، الان باید ماژول یه پالس برامون بفرسته و ما با اندازه گیری اون میتونیم مدت زمانی که صوت ارسال شده و برگشته رو بدست بیاریم و با استفاده از روابط فیزیک اونو به فاصله تبدیل کنیم!

برای اینکار:

ابتدا بعد از ارسال پالس به Trig منتظر میونیم که اون هم پایه Echo رو 1 کنه (پالس بفرسته) (با اندازه گیری مدت 1 بودن این پایه میتونیم طول پالس رو بدست بیارم) برای اینکار باید اول صبر کنیم تا ماژول پایه Echo رو 1 کنه پس:

while ((LPC_GPIO0->FIOPIN &(1<<1)) == 0);

بعد به محض اینکه اون پایه 1 شد باید زمان بگیریم و ببینیم کی دوباره 0 میشه (یک پالس تموم میشه)

بنابراین باید کد زیر رو بنویسیم:

   LPC_TIM2->TC = 0x0;
LPC_TIM2->TCR = 0x01;
while(((LPC_GPIO0->FIOPIN>>1)&1) == 1);

تو خط اول TC رو برابر با 0 میزاریم! یعنی از 0 شروع کن و بشمار! و توی خط بعد شمارش رو شروع میکنیم! و توی خط سوم منتظر میمونیم که پالس تموم بشه و دوباره برابر با 0 بشه (یعنی ما توی وایل میگیم که تا وقتی 1 هست همینجوری درجا بزن و وقتی صفر شد دیگه از وایل خارج میشه)

بعد مقدار سیکل هایی که طی شده رو باید در یک متغییر ذخیره کنیم و با اون زمان رو بدست بیاریم!

پس داریم:

   S = LPC_TIM2->TC;
LPC_TIM2->TCR = 0x02; 

توی خط دوم شمارش رو قطع میکنیم (متوقف میکنیم)

حالا باید زمان رو از این پالس طی شده بدست بیاریم!... ببینید الان بستگی داره به کلاک CPU و کلاک تایمر! ما فرض میکنیم کلاک CPU برابره 100 مگاهرتز باشه! و چون کلاک تایمر به طور پیشفرض یک چهارم کلاک CPU است (CPUCLK/4) یعنی میشه 25 مگاهرتز، درصورتی که اگه زمان پالس بیش از 30 میکرو ثانیه بشه دیگه عدد بدست آمده از ماژول درست نیست (یعنی اگه تعداد پالس ها به 25 مگاهرتز برسه میشه 1 ثانیه و این امکان پذیر نیست برای ماژول چون نباید زمان رفت و برگشت صوت بیشاز 30 میکرو ثانیه بشه) بنابراین عدد که ما در بخش اول گذاشتیم که نوشتیم MR0=25MHZ هیچوقت تایمر/کانتر به این عدد نمیرسه پس هیچوقت تابع وقفه اجرا نمیشه! (ولی ما همینطوری مینوسیمش)

طبق رابطه فرکانس و زمان (سرچ کنید بیاد) الان ما باید فرکانس تایمر رو به پالس های بدست آمده (که در متغییر S ذخیره کردیم) تقسیم کنیم تا زمان بدست بیاد! (چون تعداد پالس ها خیلی کمتر از فرکانس تایمر هست عدد بدست آمده برای ثانیه خیلی کوچیک میشه(میلی ثانیه یا میکرو ثانیه یا...))

خوب برای اینکار داریم:

   T = (float)S/25000000.0;

خوب حالا که زمان رو بدست اوردیم وقتش رسیده که فاصله رو بدست بیاریم!

نکته 1: سرعت نور تقریبا بین 340 تا 344 متر در هر ثانیه است!

نکته 2: توجه کنید که سراعت بدست آمده، در واقع سرعت رفت و برگشت صوت است! و باید بر 2 تقسیم شود تا بتوان فاصله رو محاسبه کرد

طبق دو نکته بالا حال باید زمان بدست آمده رو در سرعت صوت ضرب کنیم و بر 2 تقسیم کنیم!

یعنی :

d = (float)T*344.0/2.0;


کار توم شد! حالا میتونید متغییر d رو هر کجا خواستید استفاده کنید!


یه برنامه در زیر براتون آوردم که یک نفر در سایت ECA گذاشته بود (دستشون درد نکنه) با LCD کاراکتری و بورد eca کار میکنه!

برنامه زیر کمی کاملتر از توضیحات است و با خواندن آن متوجه ی تغییرات و کد های جدید میشید! سوالی بود بپرسید!


#include "lpc17xx.h"
#include <stdio.h>
 
#define LCD_LPC1768       /* Char LCD definition */
#define LCD_PORT_2
#define LCD_RS     0
#define LCD_RW     1
#define LCD_E      2
#define LCD_DB4    4
#define LCD_DB5    5
#define LCD_DB6    6
#define LCD_DB7    7
#include "lcd.h"
#define CPU 100000000  // 100MHZ
#define ECHO PORT0.1
#define TRIG PORT0.0
 uint32_t S,dim;
void Delay (uint32_t Time)
{
    uint32_t i;
    
    i = 0;
    while (Time--) {
        for (i = 0; i < 5000; i++);
    }
}

volatile int T_Counter;
float T= 0.0;
float d= 0.0;
char str[32];
/******************************************************************************
**   Main Function  main()                     
******************************************************************************/
int main (void)
{    
  SystemInit();;
lcd_init();
lcd_clear();
lcd_gotoxy(1,1);
lcd_putsf("HC-SRF04.");
//*****************************************************
// timer
//*****************************************************
LPC_SC->PCONP |= 1<<22;
LPC_TIM2->TCR = 0x02;
LPC_TIM2->CTCR = 0;
LPC_TIM2->MR0 = 25000000-1;
LPC_TIM2->MCR = 2;
LPC_TIM2->TC = 0x0;
LPC_TIM2->PR = 0;
NVIC_EnableIRQ(TIMER2_IRQn);
LPC_GPIO0->FIODIR = 1<<0;
    
  while ( 1 )
  {  
Delay(4000);
T_Counter = 0;
LPC_GPIO0->FIOSET = 1<<0;
Delay(10);
LPC_GPIO0->FIOCLR = 1<<0;

while(((LPC_GPIO0->FIOPIN>>1)&1) == 0);

LPC_TIM2->TC = 0x0;
LPC_TIM2->TCR = 0x01;

while(((LPC_GPIO0->FIOPIN>>1)&1) == 1);
S = LPC_TIM2->TC;
LPC_TIM2->TCR = 0x02; 
T = 0;
d = 0;

T = (float)T_Counter + (float)S/25000000.0;
d = (float)T*343.0/2.0;
lcd_gotoxy(1,1);

sprintf(str,"d = %2.2f M  ",d);
lcd_putsf(str);
  }
}


void TIMER2_IRQHandler(void)
{
LPC_TIM2->IR = 0x02;
T_Counter++;
return;
}


حالا انشالله که به دردتون بخوره و چیزی فهمیده باشید!

فعلا

یا علی مدد...!