به نام خدا

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

امروز UART رو یاد گرفتم تصمیم گرفتم توی سایت قرار بدم!

خوب بدون حاشیه میریم سراغ آموزش ...

 یه مطلب کوتاه از انجمن ECA که بچه های اونجا داشتن برای هم دیگه توضیح میدادن! ( من دزدیم)

خوب به این صورته!


در ارتباط ما دو طرف داریم یکی گیرنده و دیگری فرستنده . برای اینکه شما به عنوان مثال بایت 0b01101000 را از فرستنده به گیرنده انتقال دهید ( به منظور فرستادن کاراکتر h ) 
برای انقال این بایت ما می توانیم به دو روش عمل کنیم:

1- موازی : هشت تا سیم بین گیرنده و فرستنده داریم که هر بیت را روی یکی از سیم ها قرار میدیم و از قبل بین فرستنده و گیرنده توافق میکنیم کدوم سیم چه ارزشی دارد(سیم ها را ارزش بندی میکنیم ( msb و lsb )
مزایا: سرعت بالا
معایب: خرجمون بالا میره 8 تا سیم داریم . ( خرج = 8 * فاصله دو طرف * قیمت واحد سیم استفاده شده) - عیب دیگرش نویز سیم های موازی رو هم است که تو سرعت بالا زیاده.

2- سریال: بوسیله یک تیکه سیم که یک سرش به فرستنده وصل است و سر دیگر به گیرنده متصل است ، انتقال صورت می گیرد. ولی یهوو که نمیشه همه ی بیت ها را روی یک سیم قرار داد. باید بیت ها دونه به دونه روی سیم قرار گیرند یعنی در برهه ی زمانه اول بیت اول ، در برهه زمانی دوم بیت دوم الی آخر.
باید طول این برهه زمانی برای دو طرف مشخص باشد. برای مشخص کردن آن دو روش داریم:

الف) ارتباط سنکرون:
در این ارتباط ، ارتباط بوسیله ی سیم دیگری که بهش SCK یا CLK یا... میگویند ، سنکرون میشود. این سیم هم به دو طرف وصله و همیشه در هنگام ارتباط یک کلاک روش قرار میگیره و هر پریود این کلاک به معنی یک برهه زمانی است .

ب) ارتباط آسنکرون: 
تو ارتباط آسنکرون فقط همون یک سیم را داریم و دیگه از sck خبری نیست(البته در هر ارتباطی باید گراند دو طرف یکی باشد) . به خاطر همین بهش میگن آسنکرون.
ولی بالاخره باید به نحوی این برهه زمانی برای دو طرف مشخص باشد و گرنه نمیشه که .
به نظرتون باید چی کار کنیم؟؟
اومدن برای اینکه خط sck را کم کنن تا خرجشون بیاد پایین ، به مغزشون فشار آوردن و نظر زیر را دادن:
آقا چرا اینهمه دردسر بکشیم ، میایم قبل ارتباط به هر دو طرف میگیم که برهه زمانه این مقداره مثلا برهه زمانی 1 میکرو ثانیه است . و اینجوری دو طرف را سنکرون میکنیم.
این شد که مفهوم baud rate بوجود اومد و گفتن حالا که برهه زمانی یک میکرو ثانیه است پس یک بیت در 1 میکرو ثانیه فرستاده میشه ، پس تو 1 ثانیه یک میلیون بیت فرستاده میشه پس baud rate تقریبا 1Mbps است.


این سایت زیر هم هست که اونم قشنگ و کامل توضیح داده!

کلیک کنید!


مراحل تنظیم uart0 (البته همه uart ها هم باید همین مراحل رو طی کنن)

  1. نخست کلاک UART0,2 رو از طریق رجیستر PCLKSEL انتخاب میکنیم!
  2. سپس طول داده رو از طریق رجیستر LCR (Line Control Rgister) تعیین مکنیم! همچنین بیت DLAB رو در همین رجیستر ست میکنیم تا بتونیم DLL و DLM رو تعیین کنیم!
  3. سپس DLL و DLM رو تنظیم میکنیم و دوباره بیت DLAB رو ریست (صفر) میکنیم!
  4. بعد رجیستر FIFO رو فعال و اونو از RX و TX ریست میکنیم!
  5. سپس از طریق PINSEL پین های (4:5)  و (6:7) رو برای UART0 به صورت 01 ست میکنیم!
  6. کار تنظیمات تمام شد! حال میتوانید کاراکتر های خود را ارسال و دریافت کنید

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

رجیستر RBR (Receiver Bufer Register)

همونطور که از اسمش پیداست! دریافت کننده بایت از فرستنده هست! یعنی وقتی فرستنده یه چیزی رو میفرسته توی این بیت قرار میگیره!

رجیستر THR (Transmit Holding Register)

بازم همونطور که از اسمش پیداست این رجیستر برای نگه داری بایت ارسالی می باشد! که ما چیزی رو که میخواهیم بفرستیم توی این بیت میزاریم!

رجیستر TER (Trasmit Enable Rgister)

بازم مثل همیشه این بیت همونطور که از اسمش پیداست فعال کننده ارسال است! یعنی برای اینکه بایتی که در THR قرار گرفته ارسال بشه این بیت باید یک باشه!

رجیستر FCR (FIFO Control Rgister)

در زیر به تشریح بیت های مورد استفاده پرداخته ایم

بیت 0: فعال و غیرفعال سازی رجیستر FIFO

بیت1: اگر ست شود تمام رجیستر های RXFIFO رو ریست میکند!

بیت 2: اگر ست شود تمام رجیستر های TXFIFO رو ریست میکند!

بیت 7:6 : تعداد بیت های دریافتی که باعث فعال شدن وقفه یا درخواست DMA میشود را مشخص میکند!

رجیستر LCR (Line Control Rgister)

این رجیستر برای کنترل خط می باشد! که در زیر به بیت های آن پرداخته ایم!

بیت 0:1 : مشخص کننده طول داده

5 بیت  = 00

6بیت = 01

7 بیت = 10

8 بیت = 11

یعنی برای انتخاب طول داده هشت بیت باید بیت های 0 و 1 این رجیستر 1 شوند!

بیت 2: مشخص کننده تعداد بیت stop! که اگر 0 باشد 1 بیت stop و اگر 1 باشد 2 بیت stop داریم

بیت 3: مشخش کننده تولید یا عدم تولید بیت پاریتی - صفر نشانگر عدم تولید و یک نشانگر تولید بیت پاریتی

بیت 4:5 : مربوط به تعداد بیت پاریتی!

بیت 7: دسترسی یا عدم دسترسی به رجیستر های مقسم DLM , DLL این بیت همون بیت DLAB هست!


رجیستر LSR (Line Status Rgister)

همونطور که از اسمش پیداست وضعیت خط رو به ما میده!

بیت های مهم اون رو در زیر میتونید ببینید!

بیت 0 : هنگامی که فرستنده داده ای را فرستاده و داده در RBR قرار گرفته ولی هنوز خوانده نشده این بیت 1 می شود!

بیت 5: هنگامی که رجیستر THR که مربوط به ارسال داده است خالی شود این بیت 1 می شود!


خوب همه مراحل بالا رو میتونید توی کد زیر ببینید! (کلاک CPU روی 96MHZ تنظیم کنید و PLL0 رو روی 384MHZ تنظیم کنید)
#include <lpc17XX.h>
unsigned char getchar (void)
{
while (!(LPC_UART0->LSR & 0X1));
return LPC_UART0->RBR;
}
void sendchar (unsigned char ch)
{
while (!(LPC_UART0->LSR & 1<<5));
LPC_UART0->THR=ch;
LPC_UART0->TER=0X80;
}
int main (){
unsigned char set;
LPC_GPIO2->FIODIR=0XFF;
LPC_SC->PCLKSEL0|=0X0;     //SET CLOCK OF UART0    CPUCLK/4=24MHZ
LPC_UART0->LCR=0X83;      //SET 8bit data & enable dlab
LPC_UART0->DLL=13;        // SET BAUD RATE = 115200
LPC_UART0->DLM=0;
LPC_UART0->LCR=0X3;      // DESABLE DLAB
LPC_UART0->FCR=0X7;      // SET FIFO AND CLAER
LPC_PINCON->PINSEL0=0X50;// SET PIN FOR UART0



while (1){
  set=getchar();
sendchar(set);
LPC_GPIO2->FIOPIN=set;
}
}

خوب برای فعال کردن وقفه هیچ کاری خاصی لازم نیست انجام بدید!

فقط دو خط زیر رو به تابع main اضافه کنید

NVIC_EnableIRQ(UART0_IRQn);
LPC_UART0->IER=0X01;

و یه تابع هم با نام  UART0_IRQHandler درست کنید و کد خودتون رو برای وقفه اونجا بزارید!

نکته بسیار مهم: من توی تابع وقفه UART یا همون تابع  UART0_IRQHandler وقتی برنامه دریافت کاراکتر رو مینویسم کار نمیکنه و حتما باید تابع دیگه ای که اون کار دریافت کاراکتر رو میکنه فراحوانی کنم!

شما هم اگه مشکل با وقفه در UART داشتید حتما در تابع UART تابع دیگه ای رو فراخوانی کنید ببینید چی میشه!


متن برنامه زیر از متن برنامه بالا گرفته شده و فقط فرقش اینه که وقفه دریافت کاراکتر داره! یعنی در هر جای برنامه به محض اینکه یه کاراکتر برای میکرو ارسال بشه! میکرو کارش رو رها میکنه و میره کاراکتر رو دریافت میکنه!

#include <lpc17XX.h>
void delay () // تابع برای گذشتن زمان
{
int a= 7000000;
while (a--);
}
unsigned char getchar (void) // تالع دریافت کاراکتر
{
while (!(LPC_UART0->LSR & 0X1)); // منتظر ماندن برای دریافت کاراکتر
return LPC_UART0->RBR; // بازگشت کاراکتر دریافتی
}
void UART0_IRQHandler (void) // تابع مروبط به وقفه UART0
{
LPC_GPIO2->FIOPIN=getchar ();

}
void sendchar (unsigned char ch) // تابع ارسال کاراکتر که توی این برنامه استفاده نشده
{
while (!(LPC_UART0->LSR & 1<<5));
LPC_UART0->THR=ch;
LPC_UART0->TER=0X80;
}
int main (){
unsigned char set;
LPC_GPIO2->FIODIR=0XFF;
NVIC_EnableIRQ(UART0_IRQn);
LPC_SC->PCLKSEL0|=0X0;     //SET CLOCK OF UART0    CPUCLK/4=24MHZ

LPC_UART0->LCR=0X83;      //SET 8bit data & enable dlab
LPC_UART0->DLL=13;        // SET BAUD RATE = 115200
LPC_UART0->DLM=0;
LPC_UART0->LCR=0X3;      // DESABLE DLAB
LPC_UART0->FCR=0X7;      // SET FIFO AND CLAER
LPC_PINCON->PINSEL0=0X50;// SET PIN FOR UART0

LPC_UART0->IER=0X01;



while (1){ // میکرو بیکاره و توی حلقه بینهایت میفته!


}
}


بدست آوردن مقدار DLL و DLM برای بدست آوردن Baud rate:

خوب من اینو اضافه میکنم چونکه خودم هم دنبالش بودم :)

ببینید کلا DLL برای تقسیم هست! ما فعلا کارش نداریم! چون فعلا ما ضرب میکنیم! شما میتونید خودتون هم اگه نیاز شد استفاده کنید!

برای بدست آوردن مقدار DLL باید از فرمول زیر استفاده کنیم!


DLM=PCLK/16*Baud rate


خیلی ساده است! شما میتونید این فرمول رو به صورت زیباتر روی کاغذ بنویسید و مجهول رو بدست بیارید!

در فرمول بالا Baud rate همون مقداری که ما میخوایم (در مثال بالا 115200) ، خود 16 هم ثابت هست. PCLK هم مقدار کلاک UART هست! که توی مثال بالا (24 مگاهرتز هست)

کلا کلاک وسایل جانبی به صورت CpuClock/4 هست! البته اون 4 رو خودمون باید از طریق رجیستر PCLKSEL0 تغییر بدیم (به طور پیشفرض 4 هست) و چون کلاک CPU ما 96 مگاهرتز هست و اونو تقسیم بر 4 کنیم عدد 24 مگاهرتز بدست میاد!


سوالی داشتید در حد توانم در خدمتتونم!

فعلا...

 یا علی مدد!