UART یک روش انتفال دیتا به صورت سریال می باشد . این ارتباط به صورت آسنکرون است در واقع غیر همزمان می باشد و نیازی به پالس ساعت ندارد . ارتباط UART کاربرد بسیار گسنرده ای در مدارات مبتنی بر میکروکنترلر و پرسسور ها دارد . از این ارتباط جهت انتقال دیتا و نیز فرمان های کنترلی استفاده می شود اما قابلیت انتقال فایل های مالتی مدیا با حجم بالا را نیز دارد . در بسیاری از ارتباط های سریال مابین دو سیستم ، در لایه های فیزیکی از UART استفاده می شود . به طور مثال یک سیستم ممکن است از طریق یک ارتباط رادیویی دیتا را مخابره کند اما نحوه ارسال بیت به بیت دیتا بر پایه UART باشد . UART به طور کلی مدل های مختلفی دارد که در میکروکنترلر های AVR که هسته برد های آدروینو هستند ،  از نوع تمام دو طرفه آن پشتیبانی می شود . در واقع به طور همزمان امکان ارسال و دریافت دیتا وجود . از ارتباط UART که اختصارا آن را سریال نیز می نامند می توان برای گزارش عملکر MCU ، پروگرام کردن و… استفاده کرد . در کلیه مودم هایی که از فریمور هایس پشتیبانی می کنند از رابط UART برای راه اندازی آن ها استفاده می شود .

راه اندازی واحد UART در میکروکنترلر های AVR مستلزم مقدار دهی به رجیستری های مختلفی است . خوشبختانه آردوینو با دارای بودن کتابخانه HardwareSerial.h راه اندازی UART را بسیار ساده تر کرده است . علاوه بر این توابع به کار رفته در کتابخانه های HardwareSerial.h بسیار بهینه و به شیوه ای بسیار کار آمد و حرفه ای پیدا سازی شده اند که با باز کردن کتابخانه و مشاهده متد های مربوط به آن می توان متوجه این موضوع شد .

 

قبل از هر چیز لازم است به شرح ارتباط UART بپردازیم .

در یک ارتبط UART از ذو خط RX و TX استفاده می شود که TX خروجی دیتا و RX نیز ورودی دیتا می باشد . همچنین باید GND دو طرف ارتباط به همدیگر متصل باشد . در یک ارتباط UART حالت های مختلفی برای نحوه ارسال دیتا وجود دارد که دو سیستم قبل از ارتباط باید در یکی از این حالت ها توافق کنند .

در برد های آردوینو UNO پین های TX و RX پین های 0 و 1 می باشند :

قبل از ارسال دیتا ، خط TX در وضعیت یک یا HIGH قرار دارد . در ارسال هر فریم دیتا یک بیت Start ، بیت های دیتا و در نهایت یک بیت Stop ارسال می شود . اما این شکل کلی ارتباط می باشد به طوریکه UART از قابلیت ارسال بیت Parity نیز پشتیبانی می کند . بیت Parity و نیز تعداد بیت های دیتا توسط کاربر تنظیم می شوند که این تنظیمات باید برای هر دو طرف ارتباط یکسان باشد . به طور معمول از بیت Parity استفاده نمی شود همچنین دیتا را به صورت هشت بیتی ارسال می کنند در نتیحه در هر فریم ده بیت پشت سر هم به گیرنده ارسال می شود . در تصویر زیر دیاگرام یک ارتباط 8 بیتی بدون بیت Parity نشان داده شده است :

یکی از مهم ترین پارامتر های ارتباط UART نرخ ارسال دیتا یا همان بادریت می باشد که به معنی تعداد بیت های ارسالی در یک ثانیه می باشد . چون این ارتباط آسنکرون است پس قبل از ارتباط باید دو طرف ارتباط بر سر یک بادریت مشخص توافق کنند . بادریت علاوه بر سرعت ارسال دیتا در سمت فرستنده ، سرعت نمونه برداری از سیگنال ورودی در سمت گیرنده را نیز تعیین می کند . از آن جایی که فرکانس کاری دو سیستم نمی تواند دقیقا یکی باشد ( حتی با وجود کریستال هایی با یک فرکانس مشخص ) لذا دیتا به صورت فریم به فریم ارسال می شود . با اتمام هر فریم یا یک شدن خط ارتباطی ، نمونه برداری در سمت گیرنده متوقف شده و با دریافت فریم بعدی دوباره نمونه برداری شروع می شود . با فرض اینکه یک بیت Start و چندین بایت دیتا پشت سرهم و در پایان ارسال Stop شوند ، امکان خطا در سمت گیرنده بسیار بالا می رود . همچنین برای ایجاد زمان بندی های دقیق باید از بادریت های مناسب بر اساس فرکانس میکروکنترلر استفاده نمود . به طور مثال میکروکنترلری که دارای فرکانس کاری 1MHz است حداقل تاخیری که می تواند ایجاد کند 1us است لذا در ارتباطی که بادریت آن 1 مگا بیت بر ثانیه است نمی توان از این میکروکنترلر استفاده کرد .

در برد های آردوینو UNO  از میکروکنترلر AVR با فرکانس کاری 16 مگاهرتزی استفاده شده است لذا بالاترین نرخ ارسال دیتا در یک ارتباط UART برای آن ، 9600 بیت بر ثانیه است . همچنین با وجود یک دو برابر کننده سرعت UART در AVR ها ، می توان حداکثر از بادریت 115200 بیت بر ثانیه استفاده کرد .

برای درک بهتر ارتباط UART ، می توان آن را به صورت نرم افزاری و از طریق صفر و یک کردن پین TX استفاده کرد .

در مثال زیر می خواهیم هر 500 میلی ثانیه یک بار ، کاراکتر ‘A’ را به خروجی UART ارسال کنیم . در این ارتباط از بادریت 9600  بیت بر ثانیه استفاده خواهیم کرد لذا با تقسیم یم ثانیه بر 9600 می توان به دست آورد که عرض هر بیت 104 میکرو ثانیه می باشد . کد های زیر را بر روی آردوینو UNO آپلود کرده و پس از ان وارد محیط Serial monitor  آردوینو IDE شوید و نرخ بادریت را بر روی 9600 تنظیم کنید :

void setup() {
  // put your setup code here, to run once:
pinMode(1,OUTPUT);
}

void loop() {
  //ارسال بیت Start
digitalWrite(1,LOW);//------------------>0
delayMicroseconds(104);


//ارسال کاراکتر A که مقدار ASCII آن برابر 0B01000001 است 
digitalWrite(0,LOW); //------------------>0
delayMicroseconds(104);
digitalWrite(0,LOW); //------------------>1
delayMicroseconds(104);
digitalWrite(0,LOW); //------------------>0
delayMicroseconds(104);
digitalWrite(0,LOW); //------------------>0
delayMicroseconds(104);
digitalWrite(0,LOW); //------------------>0
delayMicroseconds(104);
digitalWrite(0,LOW); //------------------>0
delayMicroseconds(104);
digitalWrite(0,LOW); //------------------>0
delayMicroseconds(104);
digitalWrite(0,LOW); //------------------>1
delayMicroseconds(104);


//ارسال بیت Stop
digitalWrite(0,LOW); //------------------>0
delayMicroseconds(104);


// تاخیر 500 میلی ثانیه
delay(500);
}

 

برنامه فوق تنها به حهت آشنایی بیشتر با ارتباط UART می باشد . در پروژه های عملی می توانید از واحد سخت افزاری UART استفاده کنید که دیگر نیازی به درگیر کردن CPU نمی باشد .

 

ارتباط UART در آردوینو :

کلیه متد ها و توابع UART در کتابخانه HardwareSerial.h قرار دارند که از طریق کتابخانه Arduino.h به برنامه اضافه می شوند که نیازی به اضافه کردن این کتابخانه ها به برنامه خود ندارید چراکه آردوینو IDE حود این کار را انجام می دهد .

در حدود 10 متد مختلف برای ارتباط سریال در آردوینو وجود دارد که لازم است که برای درک بهتر عملکرد این متد ها بهتر است با ساختار کلی کتابخانه آشنایی داشته باشد .

با فرض اینکه شما آشنایی با رجیستر های UART در AVR ها ندارید بهتر است تنها قابلیت های این رجیتسری ها را بدانید .

واحد سخت افزاری UART در AVR دارای چند رجیستری کنترلی و چند رجیستری دیتا و همچنین رجیستر های مربوط به بادریت می باشد . این واحد قابلیت پشتیبانی از وقفه ارسال و وقفه دریافت را دارد یعنی با دریافت دیتا و با پایان ارسال دیتا CPU را از طریق یک وقفه مطلع می کند . در کتابخانه HardwareSerial.h از این قابلیت استفاه شده است . در واقع از وقفه UART برای ارتباط استفاده شده است . با هر بار دریافت دیتا ، روتین وقفه اجرا می شود که در این روتین دیتای دریافتی در یک آرایه قرار داده می شود . این آرایه همان بافر یا مخزن دیتا می باشد که از ازبین رفتن دیتا جلوگیری می کند . در کتابخانه HardwareSerial.h برای هر مدل آردوینو با توجه به منابع RAM مقدار خاصی بافر در نظر گرفته شده است که بافر سریال در آردوینو UNO برابر 255 بایت قرار داده سده است . در واقع هر بار که آردوینو یک دیتا را از طریق سریال دریافت می کند این دیتا در بافر ذخیره می شود و هر زمان که بخواهید می توانید آن را بخوانید ( با خواند هر دیتا مقدار آن از بافر پاک می شود و دیتا های جدید جای خود را به آن می دهند ) .

نکته : خواندن دیتا از بافر همیشه به ترتیب اولویت می باشد و دیتا هایی که زود تر دریافت شده اند برگردانده می شوند .

همچنین یک بافر برای ارسال نیز در نظر گرفته شده است که شما با هر بار ارسال دیتا ، ابتدا دیتا در این بافر ذخیره و در اولین فرصت CPU آن ها را به واحد UART جهت ارسال می فرستد .

 

حال به شرح هر کدام از متد های راه اندازی ارتباط سریاف خواهیم پرداخت .

begin() :

اولین و مهترین متد begin می باشد . توسط این تابع واحد UART پیکر بندی شده و آماده ارسال و دریافت دیتا خواهد شد .

Serial.begin(Baud rate);

این تابع در تابع Setup تعریف می شود . ورودی این تابع بادریت ارتباط می باشد که باد ریت های معمول 9600 و 115200 می باشند . در صورتی که مقدار بادریت ریت را بر روی 115200 تنظیم کنید ، رجیستر بادریت برابر 9600 قرار داده می شود و بیت دو برابر کننده بادریت فعال می شود .

()available :

متد بعدی available می باشد . این متد تعداد بایت های موجود در بافر را بر می گرداند . از این تابع می توانید جهت تشخیص دریافت دیتا استفاده کنید .

uint8_t Serial.available();

برای درک بهتر عملکرد این تابع برنامه زیر را بر روی برد خود کپی کنید وسپس وارد Serial monitor شوید . با وارد کردن هر کاراکتر یک واحد به مقدار بافر اضافه شده و در نتیجه مقدار برگشتی تابع available یک واحد بالا می شود :

void setup()
{
Serial.begin(9600);
}
void loop()
{

Serial.println(Serial.available());
delay(500);
}

()print :

متد بعدی print می باشد . این تابع به چندین مدل اوررایت شده است که قابلیت چاپ مقادیر مختلف را دارد .حالت اول نمایش رشته ها و آرایه های کاراکتری است که می توانید به شکل زیر از آن استفاده کنید :

Serial.print("رشته برای چاپ در خروجی ");

حالت بعدی نمایش متغییر های مختلف است . اگر یک عدد ثابت یا یک متغییر را در ورودی این تابع قرار دهید ، معادل دسیمال آن به صورت کد های اسکی به خروجی ارسال می شود .

برای نمایش اعداد  به صورت هگز ، باینری و یا دسیمال می توانید به صورت زیر از تابع print استفاده کنید :

int y=100;

Serial.print(y,HEX);

Serial.print(y,BIN);

Serial.print(y,DEC);

()println :

تابع بعدی println می باشد که مشابه print عمل می کند با این تفاوت در پایان ارسال مقادیر وارد شده مقادیر 0x0A و 0x0D یا همان کاراکتر “\n\r” را ارسال می کند . این دو کاراکتر مکان نمای محیط Serial monitor را به خط بعدی می برد .

()write :

تابع بعدی write می باشد . این تابع یک متغیر تک بایتری را دریافت کرده و آن را از طریق سریال ارسال می کند . این تابع بر خلاف print مقادیر واقعی متغیر وارد شده را ارسال می کند و آن را به کاراکتر تبدیل نمی کند . در تابع print هر مقدار غیر کاراکتری به کاراکتر تبدیل می شد . به طور مثال تابع print(10) دو کاراکتر ‘1’ و ‘0’ را به تریتیب به خروجی ارسال می کند اما تابع write(10) دقیقا مقدار 10 را به خروجی ارسال می کند :

Serial.write(uint8_t Byte);

()read :

تابع بعدی read می باشد . این تابع یک بایت را از بافر می خواند . این تابع به ترتیب اولویت مقادیری را که زود تر وارد شده اند را می خواند و سپس مقدار آن متغییر از بافر دریافت پاک می شود . در مثال زیر هر گاه بافر دریافت متغیر دریافت کند آن متغییر توسط متد read خوانده شده و توسط متد write دوباره به خروجی ارسال می شود :

void setup() 
{ 
Serial.begin(9600); 
} void loop() 
{ 
if(Serial.available())
{
uint8_t y=Serial.read();
Serial.write(y);
}
}

برنامه فوق را بر روی برد خود آپلود کنید و سپس وارد محیز Serial monitor شوید . در این حالت هر کاراتری را که ارسال کنید مجدد همان کاراکتر ها ارسال خواهد شد .

مثال زیر نیز همان برنامه قبل تر می باشد که در اینجا یک بار از تابع read استفاده شده است لذا با هر بار دریافت دیتا و اجرای read مقدار بافر به حالت اول بر می گردد و در نتیجه همیشه مقدار صفر نشان داده می شود  :

void setup() 
{ 
Serial.begin(9600); 
} 
void loop() 
{ 
uint8_t y=Serial.read();
Serial.println(Serial.available()); 
delay(500); 
}

این ها تنها توابع پایه ای و ضروری کار با UART می باشند . در آموزش های بعدی به دیگر توابع خواهیم پرداخت .

Tags:
About Author: USER_4