لنتعلم برمجة الأنظمة المدمجة

Embedded Systems Programming Bootcamp

كورس تعليمي يهدف الى اكسابك المعرفة اللازمة والمهارات التقنية المتعلقة ببرمجة وتطوير الأنظمة المدمجة وفهم خصائصها ومكوناتها

الصفحة الرئيسية
قائمة الدروس
خدمة RSS

للتواصل

11. بروتوكول الإتصال الغير متزامن UART

2018-07-06






في هذا الدرس، سنجعل المتحكم يتواصل مع أجهزة أخرى مثل أجهزة الكمبيوتر وشاشات LCD ومتحكمات أخرى حيث يمكننا القيام بذلك باستخدام إما طريقة الاتصال المتوازي parallel communication أو الإتصال المتسلسل serial communication.

في الاتصال المتوازي parallel، يتم نقل بتات متعددة في الوقت ذاته بينما في الاتصال المتسلسل serial نرسل البتات واحدة تلو الأخرى.

الدافع وراء استخدام الإتصال المتسلسل هو إستخدام عدد أقل من الأطراف pins. حيث أنه إذا أردنا نقل قيمة مكونة من 8 بت باستخدام الإتصال المتوازي سنحتاج إلى 8 أطراف pins لإرسال هذه القيمة مما سيؤدي بطبيعة الحال الى زيادة حجم المتحكم وزيادة التعقيد في توصيل هذا المتحكم بأجهزة أخرى. بينما في الإتصال المتسلسل serial نستخدم عدد أقل من الأطراف pins مما يجعل من تطوير لوحة الدوائر المطبوعة (PCB) أسهل بكثير وأقل كلفة وعرضة للأخطاء.

وبالرغم من أنه في الإتصال المتسلسل يتم إرسال البتات الواحد تلو الآخر الا أن هذا لا يمنعنا من نقل بيانات بأي حجم كانت. فلو كان حجم البيانات التي يمكن إرسالها في المرة الواحدة تساوي 8 بت مثلاً وكنا بحاجة الى إرسال 32 بت، فكل ما علينا فعله ببساطة هو إرسال هذه القيم بشكل متتالي أي 8 بت في كل مرة الى أن يتم إرسال البيانات بشكل كامل.

بعض الأمثلة على الاتصال المتسلسل هي UART، SPI ،I2C وسيغطي هذا الدرس بروتوكول الـ UART ولاحقاَ بمشيئة الله سوف نغطي البروتوكولات الأخرى.


Universal Asynchronous Receiver and Transmitter - UART

عند ربط أكثر من جهاز معاً، نحتاج إلى طريقة لمزامنتها مع بعضها البعض، أي أن يكون كل جهاز على علم ومعرفة بحالة الآخر. وما نقصده فعلياً بالتزامن هنا هو جعل السرعة بين الأجهزة المختلفة والمتصلة معاً متوافقة في السرعة مع بعضها البعض.

يجب هنا التوضيح بأن كلمة Asynchronous في UART يعني أن بروتوكول الإتصال هذا لا يتضمن وجود ساعة مشتركة بين الأجهزة، إذن كيف يحدث التزامن؟ يكون ذلك عن طريق إتفاق الجهاز المرسل والمستقبل على سرعة نقل معينة Baud Rate أو سرعة نقل البت في الثانية (بت/ثانية) وبذلك يعرف الجهاز المتلقي متى يتم تسجيل بداية ونهاية البيانات المنقولة.

فلو قلنا أننا ننقل البيانات بسرعة 9600 بت/ثانية فهذا يعني أن كل بت يستغرق 1/9600 أي تقريباً 104 مايكروثانية لنقله.

فيما يخص الهاردوير، فإن ما نحتاجه لتوصيل جهازين باستخدام الـ UART هو الوصلات التالية:

الهدف من إيصال الطرف الأرضي في كلا الجهازين هو الحفاظ على مرجع الجهد (reference voltage) لكلا الجهازين وذلك لأن الإشارات في الـ UART تتكون من إشارات ذات مستوى منخفض 0 ومستوى عال 1 ويجب على الجهاز المستقبِل أن يكون مدركًا إن كانت الإشارات المستقبلة منخفضة أم عالية.

source: https://learn.sparkfun.com/tutorials/serial-communication

هيكل الرسالة Message Frame

تتكون رسالة الـ UART من البتات التالية:

وبناءً على ذلك يتضح لنا أنه لكل بايت byte من البيانات التي نريد نقلها فإنه يتم أيضًا نقل بعض البتات الإضافية.

هناك عدة أشكال للرسالة في الـ UART. فمن الممكن أن تكون بتات البيانات 5 أو 6 أو 7 أو 8 بتات. ومن الممكن أن يكون لدينا أيضًا بت التوازن parity bit أو لا. ويمكن أن يكون لدينا إما 1 أو 2 بت توقف.

ولكننا في هذا الدرس سنستخدم الهيكل الافتراضي default للرسالة وهي:

وبذلك يكون لدينا ما مجموعه 10 بتات لكل بايت byte من البيانات التي نرغب في إرسالها حيث أن 8 بتات مخصصة للبيانات، و 2 بتات إحداهما للبداية والآخر للتوقف.

source: https://courses.edx.org/courses/course-v1:UTAustinX+UT.6.20x+2T2018

نقل الرسالة Transmiting a Frame

كل بايت byte نوّد إرساله يوضع وسط إطار يبدأ ببت البداية start bit وينتهي ببت التوقف stop bit. وهذه العملية تسمى التأطير framing.

دعونا نرسل الحرف ‘K’ كمثال.

نجد أنه في جدول الـ ASCII:

https://www.asciitable.com

يتكون هذا الحرف من الرقم الست عشري والرقم الثنائي التالي:

'K' = 0x4B = 0100 1011

وبذلك ستكون خطوات الإرسال كالآتي:

  1. تكون إشارة UART في حالة الخمول idle (عندما لا يكون هناك نقل للبيانات) وتظل عالية (1) عند 3.3 فولت.

  2. عندما نكون مستعدين لبدء الإرسال، يتم إسقاط خط Tx الى الوضع المنخفض (0) لمدة 1 بت وهذا يعتبر بت البداية start bit.

  3. بعد ذلك يتم وضع بتات البيانات في الرسالة بدءاً من الـ least significant bit أو lsb وهي 1 هنا وإنتهاءاً بالـ most significant bit أو msb وهي 0 في مثالنا.

  4. بعد ذلك يعود خط Tx الى الحالة العالية 1 وذلك يعني أننا أنتهينا من الرسالة وعدنا الى حالة الخمول idle state.

هذا يعني أنه سيتم إرسال الرسالة على النحو التالي:

يمكنك بعد ذلك البدء في إرسال رسائل أخرى إن أردت كأن يكون لديك عبارة أو كلمة تود إرسالها مثل “Khalid” فبعد إرسال الحرف الأول K ستقوم بالمرور على بقية الحروف وإرسالها بشكل متتالي.


التواصل بين جهاز الكمبيوتر والمتحكم

سوف نجعل المتحكم يتواصل مع الكمبيوتر من خلال الـ UART. ولعمل ذلك نحن بحاجة الى محول من USB إلى UART والعكس لتحويل البيانات من منفذ USB إلى بيانات UART. هذا المنفذ موجود في البورد ولسنا بحاجة الى إستخدام مكونات إضافية.

في بورد TI LaunchPad المستخدم، نجد أن منفذ UART0 في المتحكم TM4C123GH6PM متصل بمتحكم آخر وهو متحكم المصحح debugger في أعلى البورد والتي تعمل كجسر بين الـ USB والـ UART. عندما نوصل الـ Tiva LaunchPad بالكمبيوتر عن طريق الـ USB، يكون ذلك من جهة البورد عن طريق UART0 وفي الكمبيوتر يكون هنالك اتصال إفتراضي virtual connection كمنفذ COM أو COM port.

ويمكن الإطلاع على مخرجات الـ UART على جهاز الكمبيوتر عن طريق برامج مثل Putty و Tera Term وغيرها من البرامج الطرفية terminals. مع الأخذ بالإعتبار الى أن هناك حاجة لضبط إعدادات هذه البرامج لتصبح تماماً مثل تلك التي تم تحديدها في البرنامج على المتحكم.

إفتح Device Manager وتحت القائمة Ports (COM & LPT) ستجد Stellaris Virtual Serial Port (COMn) علماً أن n هنا من الممكن أن تكون أي رقم وذلك يعتمد على تعيين Windows للمنافذ:

إنقر عليها باليمين ثم إختر Properties. إختر تبويب Port Settings في النافذه الظاهرة وتأكد أن لديك الإعدادات التالية:

إضغط على OK لقفل النافذه.

حمل برنامج Tera Term من الرايط التالي:

https://osdn.net/projects/ttssh2/releases/

وبعد تشغيله إختر Serial والـ port الخاص بـ Stellaris Virtual Serial Port:

إضغط على OK لقفل النافذه.

من القائمة الرئيسية في البرنامج إختر Setup ومن ثم Serial Port من القائمة المنسدلة:

تأكد أن لديك نفس الإعدادات التالية:

إضغط على OK ليبدأ البرنامج بالعمل بالإعدادات الجديدة.


تهيئة الـ UART

إذا فتحنا صفحة 902 في دليل البيانات، فإنه بإمكاننا العثور على الخطوات المطلوبة لتهيئة الـ UART وهي:

1. قم بتمكين وحدة الـ UART باستخدام سجل RCGCUART (راجع صفحة 344).

#define SYSCTL_RCGCUART_R    (*((volatile unsigned long *)0x400FE618))

يتحكم الحقل R0 (بت 0) في ساعة UART0 التي سنستخدمها. وسيؤدي تعيين القيمة 1 الى هذا الحقل إلى تمكين UART0.

SYSCTL_RCGCUART_R |= (1<<0); // 0x01

2. قم بتمكين ساعة وحدة الـ GPIO المناسبة عبر سجل RCGCGPIO (انظر صفحة 340). لمعرفة أي منفذ GPIO يجب عليك تمكينه، راجع الجدول 5-23 في الصفحة 1351.

#define SYSCTL_RCGCGPIO_R    (*((volatile unsigned long *)0x400FE608))

لنذهب لصفحة 1351 لنرى أي منفذ GPIO يجب علينا تفعيله:

يمكننا أن نرى أن UART0 يستخدم المنفذ PORT A. الطرف PA0 لتلقي البيانات Rx والطرف PA1 لنقل البيانات Tx. وبالعودة إلى سجل RCGCGPIO، يتضح أنه لتمكين PORT A علينا تعيين 1 إلى الحقل R0 (بت 0)

SYSCTL_RCGCGPIO_R |= (1<<0); // 0x01;

3. ﻗﻢ ﺑﻀﺒﻂ بتات GPIOAFSEL ﻟلأطراف ﺍﻟﻤﻨﺎﺳﺒﺔ (ﺍﻧﻈﺮ ﺻﻔﺤﺔ ٦٧١). لتحديد أي GPIO يجب علينا ضبط إعداداته، راجع جدول 4-23 في الصفحة 1344.

يمكن العثور على تفاصيل سجل GPIOAFSEL في صفحة 671:

وسبق وأن حددنا المنفذ الذي سنتعامل معه وهو PORT A.

#define GPIO_PORTA_AFSEL_R    (*((volatile unsigned long *)0x40004420))

لتمكين الوظائف البديلة لـلمنافذ PA0 و PA1، نقوم بإسناد 1 الى بت 0 وبت 1 في حقل AFSEL

GPIO_PORTA_AFSEL_R |= (1<<1)|(1<<0); // 0x03

إسناد القيمة 1 في سجل AFSEL يقوم بتمكين الوظيفة البديلة للطرف pin. الا أن هذا في حد ذاته لا يكفي حيث أن بعض الأطراف تدعم أكثر من وظيفة بديلة واحدة. وهنا ياتي دور سجل التحكم في المنفذ (PCTL) والذي نقوم فيه بتحديد بالضبط ماهي الوظيفة البديلة التي سيقوم بها المنفذ.

4. قم بتهيئة مستوى التيار لـ GPIO و / أو معدل slew كما هو محدد للوضع المختار (راجع صفحة 673 وصفحة 681).

يمكننا تجاهل هذه الخطوة في الوقت الحالي.

5. قم بضبط إعدادات حقول PMCn في سجل GPIOPCTL لتعيين إشارات UART إلى الأطراف المناسبة (انظر صفحة 688 والجدول 5-23 في الصفحة 1351).

نستخدم السجل register التالي للمنفذ PORT A:

#define GPIO_PORTA_PCTL_R    (*((volatile unsigned long *)0x4000452C))

بمجرد تمكيننا للوظائف البديلة، يتعين علينا عندئذ اختيار الوظيفة البديلة المحددة التي نريدها. في الجدول 5-23 في صفحة 1351 في دليل البيانات يمكننا رؤية أن UART0 يقع في العمود 1:

هذا يعني أنه يجب أن نضع 1 في بت PMCn. لذلك نذهب إلى سجل GPIOPCTL (ص 689) والذي يحتوي على بت PMCn. ويمثل PMC0 (البتات 0-3) الطرف PA0 لذلك علينا أن نضع 1 فيها. ويمثل PMC1 (بت 4-7) الطرف PA1 وعلينا أيضا أن نضع 1 فيه أيضاً.

GPIO_PORTA_PCTL_R = (1<<0)|(1<<4); // 0x11

وبما أنها إشارات رقمية فإنه يجب علينا تمكين الوظائف الرقمية للأطراف:

#define GPIO_PORTA_DEN_R    (*((volatile unsigned long *)0x4000451C))

وهذا يكون كالتالي:

GPIO_PORTA_DEN_R = (1<<0)|(1<<1); // 0x03; // enable digital I/O on PA1-0

ضبط إعدادات الـ UART

الإعدادات التي سنضبط الـ UART عليها هي كما يلي:

أول شيء يجب مراعاته عند برمجة الـ UART هو إيجاد مقسوم معدل نقل البيانات baud-rate divisor (BRD). باستخدام المعادلة الموضحة في “Baud-Rate Generation” في صفحة 896، يمكن حساب BRD باستخدام المعادلة التالية:

Baud Rate = SysClk / (16 × ClkDiv)

حيث أن:

وبالتالي يكون لدينا:

BRD = 16,000,000 / (16 * 9600) = 104.1666666666667

وسيتم إحتساب الكسر كما يلي:

UARTFBRD[DIVFRAC] = integer(0.1666666666667 * 64 + 0.5) = 11

وبعد أن حصلنا على قيمة BRD، نضبط إعدادات الـ UART بالترتيب التالي:

1. قم بتعطيل UART عن طريق مسح (إسناد 0) الحقل UARTEN (بت 0) في سجل UARTCTL (ص 918).

#define UART0_CTL_R   (*((volatile unsigned long *)0x4000C030))
UART0_CTL_R &= ~(1<<0); // ~(0x00000001);

2. اكتب العدد الصحيح من الـ BRD إلى سجل UARTIBRD (ص 914).

#define UART0_IBRD_R   (*((volatile unsigned long *)0x4000C024))
UART0_IBRD_R = 104;

3. اكتب الكسر من الـ BRD إلى سجل UARTFBRD (ص 915).

#define UART0_FBRD_R   (*((volatile unsigned long *)0x4000C028))

يتكون سجل UARTIBRD من 32 بت، نستخدم منها أول 16 بت. وبالنسبة للسجل UARTFBRD فيتم استخدام أول 6 بتات فقط. وهذا يعطينا ما مجموعه 22 بت (16 بت للعدد الصحيح + 6 بت للكسر).

UART0_FBRD_R = 11;

4. اكتب قيم الإعدادات المطلوبة للـ UART في سجل UARTLCRH (ص 916).

هذا هو السجل الذي نستخدمه لضبط عدد البتات لكل حرف يتم إرساله (طول البيانات data bits) وعدد بتات التوقف stop bits الإضافة الى إعدادت أخرى.

#define UART0_LCRH_R   (*((volatile unsigned long *)0x4000C02C))

نريد هنا إسناد القيمة 0x3 الى الحقل WLEN (بت 5-6) حيث أن عدد بتات البيانات data bits التي سنرسلها هو 8 بت.

تحتوي وحدة الـ UART في TI Tiva على مخزن مؤقت FIFO داخلي بحجم 16 بايت لتخزين البيانات المعدة للإرسال. ويوجد أيضاً مخزن FIFO آخر بحجم 16 بايت أيضاً لحفظ البايتات bytes المتلقاة. ومن خلال إسناد 1 الى الحقل FEN (بت 4) سنقوم بتمكين الـ FIFO والذي يمكننا من كتابة ما يصل إلى 16 بايت للـ UART وستقوم من ذاتها بإرسال بايت تلو الآخر الى أن تصبح الـ FIFO فاضية. كما أن الـ FIFO للبيانات المتلقاه تمكن الـ UART من استقبال 16 بايت بينما يقوم برنامجنا بالتعامل مع الواحدة تلو الأخرى.

UART0_LCRH_R = (0x3<<5)|(1<<4);

5. قم بإعداد مصدر ساعة الـ UART بالكتابة إلى سجل UARTCC (ص 939).

#define UART0_CC_R   (*((volatile unsigned long *)0x4000CFC8))

في حقل CS (بت 0-3) نحدد مصدر ساعة الـ UART. حيث نقوم بإسناد القيمة 0x0 الى الحقل لإختيار ساعة النظام System Clock.

UART0_CC_R = 0x0;

6. هذه الخطوة إختيارية، قم بإعداد قناة MicroDMA (راجع “Micro Direct Memory Access (MicroDMA)” في صفحة 585) وقم بتمكين خيارات الـ DMA في سجل UARTDMACTL.

سنتجاهل هذه الخطوة.

7. قم بتمكين الـ UART عن طريق إسناد 1 الى حقل UARTEN (بت 0) في سجل UARTCTL (ص 918).

يمكن العثور على تفاصيل هذا السجل في الخطوة الأولى.

سنقوم بإسناد 1 الى حقل UARTEN (بت 0) لتمكين الـ UART. وسنقوم أيضًا بإسناد 1 الى حقل TXE (بت 8) وحقل RXE (بت 9) لتمكين UART من الإرسال والإستقبال

UART0_CTL_R  = (1<<0)|(1<<8)|(1<<9);

إرسال البيانات

source: http://users.ece.utexas.edu/~valvano/Volume1/E-Book/C11_Interactives.htm

لإرسال بايت byte من البيانات فإنه يجب وضعه في سجل البيانات UARTDR. وعلى الرغم من أنه سجل من 32 بت، الا إنه سيتم استخدام أول 8 بت فقط (بت 0-7).

#define UART0_DR_R   (*((volatile unsigned long *)0x4000C000))

ولكن، قبل ذلك فإننا نقوم بمراقبة الحقل TXFF (بت 5) في السجل UARTFR:

#define UART0_FR_R   (*((volatile unsigned long *)0x4000C018))

ويكون ذلك قبل الكتابة الى UARTDR وطالما كانت قيمة TXFF تساوي 1 فهذا يعني أن الـ FIFO ممتلئ ولا يمكنه قبول أي بيانات أخرى وأنه يجب علينا أن نتنتظر. وعندما تصبح القيمة 0 فهذا يعني أن المخزن المؤقت للإرسال FIFO غير ممتلئ وبإمكاننا الكتابة اليه ونقوم عندئذ بكتابة بايت إلى السجل UARTDR والذي سيضعها في الـ FIFO ليتم إرسالها.

بعد الكتابة الى سجل البيانات UARTDR، يتم تمرير هذه البتات الثمانية إلى الـ FIFO وهو عبارة عن مخزن مؤقت للرسائل مكون من 16 عنصر يمكن البرنامج من كتابة العديد من البيانات اليها ليتم إرسالها الواحدة تلو الأخرى فيما بعد.

بعد ذلك يتم تحميل العناصر الموجودة في الـ FIFO إلى shift register من 10 بتات متصل بطرف الإرسال Tx. وعندما يحين وقت الإرسال سيتم إرسال البتات كما يلي:

وبذلك يكون الكود:

while ((UART0_FR_R & 0x0020) != 0);      	
UART0_DR_R = 'K';

إستقبال البيانات

source: http://users.ece.utexas.edu/~valvano/Volume1/E-Book/C11_Interactives.htm

بالنسبة للإستقبال فإن العملية ستحدث بالعكس. سيستقبل الـ shift register المتصل بخط الإستقبال Rx الرسالة وسيضعها لك في الـ FIFO لتتمكن من قرائتها عن طريق السجل UARTDR.

ولكن، وقبل قراءة السجل UARTDR فإنه يجب علينا التأكد من أن الـ FIFO ليس فارغاً بل يحمل بيانات لنا لقرائتها. وعلى ذلك، سنقوم بالتحقق من قيمة الحقل RXFE (بت 4) في السجل UARTFR. فطالما كانت القيمة المعادة هي 1 فهذا يعني أنه لا توجد رسائل مستقبلة وسيدخل البرنامج في عملية انتظار دائم busy wait الى أن تصبح القيمة 0. وعندما تصبح القيمة المعادة 0، فهذا يعني أن هناك على الأقل بعض البيانات البيانات التى بإمكاننا قرائتها.

البتات الـ 8 الأولى (بت 0-7) في UARTDR ستحتوي على البايت المستقبل. وتستخدم 4 بتات إضافية أخرى من 8 الى 11 للكشف عن الأخطاء. ويوجد سجلان آخران وهما UARTRSR و UARTRCR يمكن إستخدامها للتأكد من مصدر المشكلة.

وفيما يلي الكود المستخدم لإستقبال الرسائل من الـ UART:

char c;
while ((UART1_FR_R & 0x0010) != 0);     
c = (char)(UART0_DR_R & 0xFF);

يوجد شرح تفاعلي رائع يوضح عملية الإرسال والإستقبال في الـ UART على الرابط التالي:

http://users.ece.utexas.edu/~valvano/Volume1/E-Book/C11_Interactives.htm#ITool11.4


البرنامج

البرنامج التالي يقوم ببساطة بتمكبن المستخدم من إرسال حرف يدخله عن طريق برنامج Tera Term وسيتم إرساله الى المتحكم عن طريق UART0 ومن ثم إعادة إرساله أيضاً عن طريق UART0 الى جهاز الكمبيوتر ليتم طباعته.

لا تنسى بعد كتابة البرنامج الى المتحكم الضغط عل زر Reset على البورد ليبدأ البرنامج بالتنفيذ.

#define SYSCTL_RCGCUART_R     (*((volatile unsigned long *)0x400FE618))
#define SYSCTL_RCGCGPIO_R     (*((volatile unsigned long *)0x400FE608))
#define GPIO_PORTA_AFSEL_R    (*((volatile unsigned long *)0x40004420))
#define GPIO_PORTA_PCTL_R     (*((volatile unsigned long *)0x4000452C))
#define GPIO_PORTA_DEN_R      (*((volatile unsigned long *)0x4000451C))
#define UART0_CTL_R           (*((volatile unsigned long *)0x4000C030))
#define UART0_IBRD_R          (*((volatile unsigned long *)0x4000C024))
#define UART0_FBRD_R          (*((volatile unsigned long *)0x4000C028))
#define UART0_LCRH_R          (*((volatile unsigned long *)0x4000C02C))
#define UART0_CC_R            (*((volatile unsigned long *)0x4000CFC8))
#define UART0_DR_R            (*((volatile unsigned long *)0x4000C000))
#define UART0_FR_R            (*((volatile unsigned long *)0x4000C018))

void uart0_init (void);
char uart0_in_char (void);
void uart0_out_char (char c);
void uart0_out_string (char *string);

int main ( ){
  uart0_init();

  char c;
  while ( 1 ){
    c = uart0_in_char();  /* receive char */
    uart0_out_char(c);    /* echo received char */
  }
	
  return 0;
}

// Call only once
void uart0_init (void){
	// -------------------------------- //
	// 	Initialize the UART module  //
	// -------------------------------- //
	
	// 1. Enable the UART module using the RCGCUART register (see page 344).
	SYSCTL_RCGCUART_R |= (1<<0); // 0x01 // enable UART 0
	
	// 2. Enable the clock to the appropriate GPIO module via the RCGCGPIO register (see page 340).
	// To find out which GPIO port to enable, refer to Table 23-5 on page 1351.	
	SYSCTL_RCGCGPIO_R |= (1<<0); // 0x01 // enable PORT A
	
	// 3. Set the GPIO AFSEL bits for the appropriate pins (see page 671). To determine which GPIOs to
	// configure, see Table 23-4 on page 1344.
	GPIO_PORTA_AFSEL_R |= (1<<1)|(1<<0); // 0x03 // enable alternate functions on PA1-0
	
	// 4. Configure the GPIO current level and/or slew rate as specified for the mode selected (see
	// page 673 and page 681).
	
	// No need to worry about this for now
		
	// 5. Configure the PMCn fields in the GPIOPCTL register to assign the UART signals to the appropriate
	// pins (see page 688 and Table 23-5 on page 1351).
	GPIO_PORTA_PCTL_R = (1<<0)|(1<<4); // 0x11 // configure PA1-0 as UART0	
	GPIO_PORTA_DEN_R  = (1<<0)|(1<<1); // 0x03 // enable digital I/O on PA1-0
	
	// ------------------------------- //
	// 	Configure the UART module  //
	// ------------------------------- //
	
	// Find the Baud-Rate Divisor (BRD)
	// Formulas may be found in P903
	// BRD = 16,000,000 / (16*9600) = 104.1666666666667
	// UARTFBRD[DIVFRAC] = integer(0.166667 * 64 + 0.5) = 11
	
	// With the BRD values in hand, the UART configuration is written to the module in the following order:
	
	// 1. Disable the UART by clearing the UARTEN bit in the UARTCTL register.
	UART0_CTL_R &= ~(1<<0); // ~(0x00000001); // disable UART0
	
	// 2. Write the integer portion of the BRD to the UARTIBRD register.
	UART0_IBRD_R = 104;
	
	// 3. Write the fractional portion of the BRD to the UARTFBRD register.
	UART0_FBRD_R = 11;
	
	// 4. Write the desired serial parameters to the UARTLCRH register 
	UART0_LCRH_R = (0x3<<5)|(1<<4); // 8 bit data, no parity bits, 1 stop bit, FIFOs
	  
	// 5. Configure the UART clock source by writing to the UARTCC register.
	UART0_CC_R = 0x0;
	
	// 6. Optionally, configure the µDMA channel (see “Micro Direct Memory Access (µDMA)” on page 585)
	//    and enable the DMA option(s) in the UARTDMACTL register.

	// 7. Enable the UART by setting the UARTEN bit in the UARTCTL register.
	UART0_CTL_R  = (1<<0)|(1<<8)|(1<<9);
	//(bit 0: enable uart) (bit 8: enable Tx) (bit 9: enable Rx)
}

// Wait for new input, then return ASCII code
char uart0_in_char (void){
	char c;
	// wait until RXFE is 0 (buffer not empty)
	while ((UART0_FR_R & 0x0010) != 0);     
	c = (char)(UART0_DR_R & 0xFF);	
	return c;
}

void uart0_out_char (char c){
	// wait until TXFF is 0 (buffer not full)
	while ((UART0_FR_R & 0x0020) != 0);      	
	UART0_DR_R = c;
}

void uart0_out_string (char *string){
	while (*string) {
		uart0_out_char (*(string++));
	}
}

ملاحظة: هذه المقالة تحت التحديث المستمر،، وملاحظاتكم وإقتراحاتكم ستساعد بإذن الله في إخراجها بالصورة التي كتبت من أجلها وهي تمهيد الطريق أمامكم لتعلم برمجة الأنظمة المدمجة