Arman Barkhordar
Arman Barkhordar
خواندن ۱۳ دقیقه·۳ سال پیش

سریال USART در AVR

در تمام میکروکنترلرها مثل AVR و PIC و یا میکروهای سطح بالا نظیر ARM، همواره برای تبادل اطلاعات میان میکروکنترلرها و یا برقراری ارتباط با بردهای الکترونیکی مثل سنسورهایی که با سریال اطلاعات را رد و بدل می‌کنند، پورت‌ها یا رابط‌هایی مثل USART وجود دارد که این امر را میسر می‌سازد. USART نوعی از یک ارتباط سریال است و وقتی اسمی از ارتباط سریال برده می‌شود، تنها USART مد نظر نیست. چون به غیر از USART ارتباطات سریال دیگری مثل SPI و I2C هم وجود دارد.

رابط سریال USART

ارتباط سریال به نوعی از ارتباط گفته می‌شود که بیت به بیت اطلاعات به صورت سری از یک رشته سیم منتقل می‌شود تمام این بیت‌ها بصورت پشت سرهم و با فاصله زمانی مشخص است.

همانطور که گفتیم USART نوعی ارتباط سریال است که اول حروف Universal Synchronous Asynchronous Receiver Transmitter بوده و به معنای فرستنده گیرنده سنکرون و آسنکرون جهانی است. در میکروکنترلرهای AVR سه پایه برای سریال USART تعبیه شده که این سه پایه مطابق شکل زیر عبارت‌اند از: TXD ،RXD و XCK.


TXD: پایه Transmit یا ارسال داده است و باید به پایه RXD دستگاه مقابل متصل شود.
RXD: پایه Receive یا دریافت داده است و باید به پایه TXD دستگاه مقابل متصل شود.
XCK: این پایه مربوط به زمانی است که ارتباط سریال ما سنکرون یا همزمان باشد. در این صورت این پایه به پایه XCK میکروکنترلری که میخواهیم با آن ارتباط برقرار کنیم متصل می‌شود.

· پایه XCK جز استاندارد (RS232) استاندارد جهانی ارتباط سریال UART نبوده و تنها درمیکروکنترلر AVRوجود دارد.

· منظور از “دستگاه مقابل” یک میکروکنترلر، کامپیوتر، سنسور و یا هرچیزی است که دارای ارتباط USART می‌باشد.

شرح عملکرد USART

برای تبادل ارتباط میان دستگاه‌ها باید RXD ها به TXD ها متصل شوند. با توجه به شکل زیر پایه TXD مربوط به Device 1 به پایه RXD مربوط به Device 2 متصل است. باید گفت که در شکل زیر فقط می‌توان اطلاعات را از Device 1 به Device 2 انتقال داد و برای اینکه ارتباط دو طرفه شود باید TXD دستگاه 2 را به RXD دستگاه 1 متصل کنیم. اما برای شرح عملکرد سریال، فعلا ما ارتباط را بصورت یک طرفه در نظر می‌گیریم.

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

هر فریم از 4 قسمت اصلی تشکیل شده است:

1. بیت Start (St) که همواره 0 منطقی است و در اول شروع فریم می‌آید.

2. بیت‌های داده که حامل داده اصلی هستند و بین 5 تا 9 بیت می‌توانند باشند. اینکه تعداد بیت‌های داده چقدر باشد، توسط ما مشخص می‌شود.

3. بیت Parity (P) که به آن بیت توازن هم گفته می‌شود. این بیت می‌تواند وجود داشته باشد یا اینکه اصلا مورد استفاده قرار نگیرد.

4. بیت Stop (Sp) که همیشه 1 منطقی است و حداقل 1 بیت و حداکثر 2 بیت می‌تواند باشد که این مورد هم توسط ما مشخص می‌شود. بیت Sp بر خلاف بیت St در آخر هر فریم می‌آید.

· بیت Start، بیت Parity (درصورت فعال سازی) و بیت Stop بصورت اتوماتیک و سخت افزاری به داده‌ چسبانده می‌شوند و ما تنها باید داده‌هایی را که میخواهیم بفرستیم مشخص کنیم.

· در حالت عادی (IDLE) اگر اطلاعاتی رد و بدل نشود، وضعیت خط انتقال در حالت 1 منطقی قرار دارد. به همین خاطر است که بیت استارت بصورت همیشه 0 ظاهر می‌شود تا آغاز یک فریم را مشخص کند.

· سرعت انتقال داده یکی از فاکتورهای اصلی ارتباط USART است و به آن نرخ ارسال گویند و واحد آن بیت بر ثانیه (bps) می‌باشد. مثلا نرخ ارسال 9600 یعنی تعداد 9600 بیت می‌تواند در 1 ثانیه ارسال شود.

بیت توازن

دلیل وجود این بیت، تشخیص خطا در فریم است. بیت توازن دو نوع است:

1. توازن زوج (Even Parity) که تعداد 1 موجود در داده و بیت توازن باید زوج شوند.

2. توازن فرد (Odd Parity) که تعداد 1 موجود در داده و بیت توازن باید فرد شوند.

مقدار بیت توازن بستگی به داده‌ای که میخواهیم منتقل کنیم دارد. فرض کنید نوع توازن را زوج انتخاب کرده‌ایم و داده‌ای که می‌خواهیم ارسال شود 8 بیتی بوده و بصورت 11001001 باشد. با توجه به این داده، تعداد 1 ها 4 می‌باشد. پس چون 4 عددی زوج است، بیت توازن 0 منطقی می‌شود.

مزیت بودن بیت توازن

توازن زوج و داده ارسالی 01101110 را در نظر بگیرید. چون تعداد 1 برابر 6 می‌شود و زوج است، در طرف گیرنده هم باید همین تعداد 1 شناسایی شود. اگر در طول مسیر یکی از بیت‌های ارسالی تغییر وضعیت دهد، تعداد 1 ها فرد شده و گیرنده از این طریق متوجه رخ دادن خطا در داده می‌شود. خطای مربوط به بیت توازن با PE نشان داده می‌شود.

· نوع توازن بیت Parity، در هر دو طرف فرستنده و گیرنده، باید هر دو فرد و یا هر دو زوج باشد.

رجیسترهای USART در AVR

برای دسترسی به ارتباط سریال USART در تمامی میکروکنترلرهای AVR رجیسترهایی تعبیه شده‌اند که تمامی موارد فوق را پیاده‌سازی می‌کنند. مواردی مثل توازن فرد یا زوج، تعداد بیت‌های داده و نرخ ارسال همگی از طریق این رجیسترها تنظیم می‌شوند. 7 رجیستر برای ارتباط USART وجود دارد که عبارت اند از : UCSRB ،UCSRA ،UBRRH ،UBRRL و UCSRC و 2 رجیستر با اسم یکسان UDR.

رجیسترهای UBRRL و UBRRH برای تنظیم نرخ ارسال داده و رجیسترهای UCSRA تا UCSRC وظیفه کنترل و تنظیم نوع عملکرد رابط سریال را بر عهده دارند. همچنین دو رجیستر که نام هر دوی آنها UDR است، یکی برای ارسال داده و دیگری برای دریافت داده خواهد بود.

رجیسترهای UBRRL و (Usart Baud Rate Register) UBRRH

این دو رجیستر برای تنظیم نرخ ارسال هستند که مقدار کم ارزش آن UBRRL و مقدار با ارزش آن UBRRH است.

مقدار UBRR از 12 بیت تشکیل شده که 8 بیت کم ارزش آن در UBRRL و 4 بیت با ارزش آن در UBRRH قرار دارد. نرخ ارسال با توجه به یکی از سه فرمول زیر محاسبه می‌شود.

فرمول اول

در اول توضیحات این مطلب گفتیم که USART در دو مد سنکرون و آسنکرون می‌تواند عمل کند. اگر USART در مد آسنکرون باشد و بیت U2X در رجیستر UCSRA برابر 0 باشد، از فرمول زیر برای تنظیم Baud Rate استفاده می‌کنیم.

Fosc فرکانس کاری میکروکنترلر، UBRR مقدار رجسترهای UBRR که 12 بیت هستند و BAUD که میزان نرخ ارسال یا همان Baud Rate است. اعداد 1 و 16 هم که ثابت هستند.

فرمول دوم

اگر USART در مد آسنکرون باشد و بیت U2X در رجیستر UCSRA برابر 1 شود، سرعت انتقال داده 2 برابر خواهد شد. در این حالت باید از فرمول زیر استفاده کرد.

تنها تفاوت این فرمول نصف شدن عدد ثابت 16 و تبدیل به 8 است. چون سرعت 2 برابر شده است.

فرمول سوم

اگر مد کاری بصورت سنکرون انتخاب شود، بیت U2X تاثیری در نرخ ارسال ندارد و باید از رابطه زیر برای تنظیم Baud Rate استفاده کرد.

این فرمول هم مشابه فرمول‌های ذکر شده است و تنها عدد ثابت 2 در مخرج قرار می‌گیرد.

رجیسترهای (Usart Data Register) UDR

وقتی صحبت از ارسال و یا دریافت اطلاعات می‌شود، باید به این دو رجیستر توجه کرد. این دو رجیستر کاملا همنام هستند و یکی از آنها برای دریافت اطلاعات(Read) و دیگری برای ارسال اطلاعات(Write) است.

نکته: اگر تعداد بیت‌های داده را 8 بیت انتخاب کنیم که اکثرا مواقع هم همینگونه است، اطلاعات دریافتی در قالب یک بایت رد و بدل می‌شوند.

اگر یک بایت دریافت شود (یک بایت از طریق پایه RXD وارد شود)، با خواندن UDR، در اصل مقدار رجیستری که برای دریافت داده است، خوانده می‌شود. به عبارتی دیگر تمایز بین این دو رجیستر را کامپایلر (CodeVision) انجام می‌دهد.

unsigned char A;

A = UDR;

اگر بخواهیم یک بایت را ارسال کنیم، باید بر روی UDR بنویسیم. بلافاصله پس از مقدار دادن به UDR، ارسال اطلاعات از پایه TXD میکروکنترلر آغاز می‌شود.

UDR = 0xAA;

به عنوان مثال، یک بایت با مقدار “10101010” (0xAA) بر روی UDR نوشتیم که ارسال این بایت بصورت سخت‌افزاری انجام می‌شود.

رجیستر (Usart Control Status Register A) UCSRA

رجیسترهای UCSR جهت کنترل و تعیین وضعیت رابط سریال عمل می‌کنند. اما رجیستر UCSRA بیشتر وضعیت‌ها و اخطارهای جاری رابط سریال را نشان می‌دهد.

بیت RXC

اگر یک بایت دریافت شود، این بیت 1 می‌شود. در غیر این صورت 0 است.

بیت TXC

پس از اتمام ارسال یک بایت این بیت 1 می‌شود. در غیر این حالت 0 است.

بیت (Usart Data Register Empty) UDRE

پس از اتمام ارسال یک بایت، مدت زمانی طول می‌کشد تا رجیستر UDR ارسالی خالی شود. پس از خالی شدن UDR، این بیت 1 شده و می‌توان بایت بعدی را برای ارسال روی آن نوشت.
نکته: اگر این بیت 1 نشده باشد و بایت بعدی بلافاصله روی UDR نوشته شود، خطای سخت افزاری رخ می‌دهد.

بیت ( Frame Error) FE

این بیت در گیرنده کاربرد دارد و زمانی 1 می‌شود که در فریم دریافتی خطاهایی مثل یکسان نبودن نرخ انتقال یا عدم تشخیص بیت‌های Start و Stop رخ دهد. مثلا اگر نرخ ارسال فرستنده 9600bps و در گیرنده 38400bps تنظیم شده باشد، این بیت مداوم در گیرنده 1 شده و 1 باقی می‌ماند. از این طریق می‌توان وقوع خطا را متوجه شد.

بیت (Data Over Run) DOR

اگر در گیرنده یک بایت دریافت شود و برنامه‌نویس این بایت را نخواند و سپس یک بایت دیگر دریافت شود، در این صورت مقدار بایت قبلی از بین خواهد رفت و این بیت 1 می‌شود.

بیت (Parity Error) PE

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

بیت U2X

اگر این بیت 1 شود، نرخ ارسال داده 2 برابر خواهد شد.

بیت (Multi Processor Communication Mode) MPCM

اگر این بیت را 1 کنیم، ارتباط سریال وارد مد چند پردازنده‌ای می‌شود.

رجیستر (Usart Control Status Register B) UCSRB

این رجیستر بصورت شکل زیر است و جهت کنترل سخت افزاری رابط سریال به کار می‌رود.

بیت RXC Interrupt Enable) RXCIE)

اگر این بیت 1 شود، وقفه دریافت USART فعال شده و در صورت گرفتن یک بایت، وقفه رخ می‌دهد. شماره Vector این وقفه عدد 12 است.

بیت TXC Interrupt Enable) TXCIE)

اگر این بیت را 1 کنیم، در صورت کامل شدن ارسال یک بایت، وقفه رخ می‌دهد. شماره Vector این وقفه عدد 14 است.

بیت Usart Data Register Empty Interrupt Enable) UDRIE)

در صورت 1 کردن این بیت، اگر پس از ارسال بایت، رجیستر UDR نوشتنی خالی شده و آماده دریافت بایت بعدی شود، وقفه رخ می‌دهد. شماره Vector این وقفه عدد 13 است.

نکته: برای رخ دادن وقفه به غیر از فعال کردن هر کدام از این سه بیت، باید بیت وقفه عمومی هم 1 شود.

بیت RX Enable) RXEN)

برای حالت گیرندگی باید این بیت را 1 کرد. در غیر این صورت نمی‌توانیم داده دریافت کنیم.

بیت TX Enable) TXEN)

برای حالت فرستندگی این بیت باید 1 شود. در غیر این صورت نمی‌توان ارسال داده انجام داد.

بیت Usart Character Size 2) UCSZ2)

بیت‌های UCSZ از 3 بیت تشکیل شده که بیت سوم آن یعنی UCSZ2 در این رجیستر قرار دارد و دو UCSZ0 و UCSZ1 در رجیستر UCSRC واقع شده‌اند. گفتیم که طول داده دریافتی و ارسالی می‌تواند 5، 6، 7، 8 و یا 9 بیت باشد. این مقدار توسط این 3 بیت مطابق شکل زیر تنظیم می‌شود.

به عنوان مثال اگر بخواهیم طول داده‌های ارسالی یا دریافتی 8 بیت باشد، وضعیت این 3 بیت باید “011” مقداردهی شود.

بیت RX Bit 8) RXB8)

در جدول بالا اگر طول داده بصورت 9 بیتی تنظیم شود، این بیت نهمین بیت دریافتی است و باید قبل از رجیستر UDR خوانده شود. به عنوان یادآوری باید گفت که بیت‌های 0 تا 7 در رجیستر UDR فقط خواندنی قرار دارند.

بیت TX Bit 8) TXB8)

اگر طول داده را 9 بیت تنظیم کنیم، این بیت نهمین بیت ارسالی است و باید قبل از نوشتن بر روی UDR نوشتنی، مقداردهی شود. باز هم یادآور می‌شویم که بیت‌های 0 تا 7 در رجیستر UDR نوشتنی قرار دارند.

رجیستر Usart Control Status Register C) UCSRC)

این رجیستر هم قسمت‌های دیگر رابط سریال را کنترل می‌کند.

بیت Usart Register Select) URSEL)

اگر به رجیستر UBRRH دقت کرده باشید، آخرین بیت این رجیستر دقیقا بیت URSEL است. چون رجیستر UCSRC و UBRRH در حافظه از آدرس مشترکی استفاده می‌کنند، این بیت تمایز بین این دو رجیستر را انجام می‌دهد. به عبارتی دیگر اگر بخواهیم بر روی رجیستر UCSRC مقداری بنویسیم باید این بیت را بصورت 1 شده اعمال کنیم و از طرفی اگر بخواهیم مقداری را بر روی UBRRH بنویسیم باید این بیت را 0 شده در نظر بگیریم.

بیت Usart Mode Select) UMSEL)

رابط USART در دو مد سنکرون و آسنکرون کار می‌کند.

· اگر UMSEL برابر 0 شود، مد آسنکرون انتخاب می‌شود.

· اگر UMSEL برابر 1 شود، مد سنکرون فعال خواهد شد.

در اکثر موارد مد آسنکرون استفاده می‌شود. اما اگر مد سنکرون انتخاب شود، کافی است در هر دو میکرو، پایه‌های XCK به یکدیگر وصل شوند. در این صورت پایه XCK یکی از میکروها بصورت خروجی و پایه XCK میکرو دیگر، باید بصورت ورودی تعریف شود.

بیت‌های UPM0 و Usart Parity Mode) UPM1)

در مورد بیت Parity صحبت کردیم. بیت توازن یا غیر فعال است و یا فعال بوده و در حالت زوج یا فرد قرار دارد.

· اگر این دو بیت “00” شوند، بیت توازن غیرفعال بوده و در Frame ارسالی یا دریافتی وجود ندارد.

· حالت “01” غیر مجاز است.

· حالت “10” بیت توازن فعال شده و بصورت توازن زوج عمل می‌کند.

· حالت “11” بیت توازن فعال شده و بصورت توازن فرد عمل می‌کند.

بیت Usart Stop Bit Select) USBS)

تعداد بیت‌های Stop را معلوم می‌کند.

· اگر 0 باشد، یک بیت Stop در آخر فریم می‌آید.

· اگر 1 باشد، دو بیت Stop استفاده می‌شود.

بیت‌های UCSZ0 و Usart Character Size) UCSZ1)

این بیت‌ها در توضیحات رجیستر UCSRB شرح داده شدند.

بیت Usart Clock Polarity) UCPOL)

این بیت زمانی کاربرد دارد که رابط USART در مد سنکرون عمل کند.

مثال 1

برنامه‌ای بنویسید که بصورت مداوم هر 1 ثانیه حرف A را بر روی خروجی چاپ کند. بیت Parity غیرفعال، تعداد بیت‌های Stop یک و طول داده 8 بیت است. همچنین نرخ ارسال هم 9600bps می‌باشد.

تذکر: در تمام مثال‌ها فرکانس کاری میکروکنترلر بصورت 8MHz داخلی تنظیم شده است و مد عملکرد هم آسنکرون می‌باشد.

#include <mega16.h>
#include <delay.h>
void main(void){
UBRRH = 0;
UBRRL = 51;
UCSRA = 0x00;
UCSRB = 0x08;
UCSRC = 0x86;
while(1){
//UDR = 65;
UDR = 'A';
delay_ms(1000);
}
}

تنظیم UBRRH و UBRRL

اولین کار مشخص کردن نرخ ارسال یا Baud Rate است. چون در مد آسنکرون هستیم و بیت U2X واقع در رجیستر UCSRA صفر است، باید از فرمول اول استفاده کنیم.

با گذاشتن 8000000 بجای Fosc و 9600 بجای BAUD، مقدار UBRR برابر 51 می‌شود. پس UBRRH برابر 0 و UBRRL برابر 51 خواهد شد.

تنظیم UCSRA

گفتیم که این رجیستر بیشتر وضعیت رابط را نشان می‌دهد. اما دو بیت مهم آن یعنی MPCM و U2X باید 0 شوند. نوشتن 0 یا 1 بر روی U2X روی Baud Rate تاثیر می‌گذارد و اگر در این مثال آن را 1 کنیم، مقدار Baud Rate دو برابر خواهد شد.

تنظیم UCSRB

از هیچ وقفه‌ای استفاده نمی‌کنیم. پس سه بیت TXCIE ،RXCIE و UDRIE باید 0 شوند. تنها می‌خواهیم ارسال داده انجام دهیم. پس بیت RXEN برابر 0 و بیت TXEN برابر 1 می‌شود. چون طول داده 8 بیتی است، وضعیت بیت‌های UCSZ باید “011” شود. در نتیجه بیت UCSZ2 باید 0 شود. در آخر هم به دلیل 8 بیتی بودن طول داده، نیازی به دو بیت RXB8 و TXB8 نیست. بنابراین مقدار این رجیستر 0x08 خواهد شد.

تنظیم UCSRC

گفتیم که برای نوشتن روی UCSRC باید بیت URSEL را هنگام مقداردهی 1 کنیم. چون عملکرد در مد آسنکرون است، بیت UMSEL باید 0 شود. بیت توازن نداریم پس UPM0 و UPM1 هر دو باید 0 باشند. تعداد بیت Stop هم 1 بیت است. در نتیجه USBS باید 0 باشد. اما چون وضعیت بیت‌های UCSZ برابر “011” شد، هر دو بیت UCSZ0 و UCSZ1 باید 1 شوند. در آخر هم UCPOL که در مثال‌های بعدی در مورد آن توضیح می‌دهیم، باید 0 مقداردهی گردد.
با این تفاسیر مقدار رجیستر UCSRC برابر 0x86 می‌شود.

بدنه while

چون قرار است بصورت مداوم اطلاعات ارسال شود، دستورات را داخل (1)while می‌نویسیم. برای ارسال یک بایت، کافی است به رجیستر UDR مقدار دهیم. حرف A در داخل برنامه بصورت ‘A’ تفسیر می‌شود و این مقدار را به UDR می‌دهیم که بلافاصله پس از مقدارگیری ارسال اطلاعات آغاز شده و CPU به دستور delay می‌رسد و این چرخه ادامه دارد.

تذکر: به عنوان کامنت عبارت UDR = 65 را نوشته‌ایم. تمام حروف انگلیسی، اعداد و علامت‌ها در جدولی به نام جدول اسکی ذکر شده‌اند که هر حرف یا علامت از یک بایت منحصر به فرد برای نمایش استفاده می‌کند. این مقدار برای حرف A برابر 65 است.

برنامه مثال 1 را طوری ارتقا دهید که بجای حرف A عبارت Hello را چاپ کند. تمام تنظیمات یکسان است.

#include <mega16.h>
#include <delay.h>
unsigned char Array[] = {'H', 'e', 'l', 'l', 'o'};
unsigned char i;
void main(void){
UBRRH = 0;
UBRRL = 51;
UCSRA = 0x00;
UCSRB = 0x08;
UCSRC = 0x86;
while(1){
for(i=0;i<5;i++){
UDR = Array[i];
while((UCSRA&0x20)==0x00);
}
delay_ms(1000);
}
}

تعریف آرایه

چون عبارت Hello از 5 حرف تشکیل شده است، بنابراین یک آرایه با طول 5 بایت تعریف می‌کنیم که هر حرف یک بایت را اشغال کرده است.

حلقه For

در حلقه For مقدار i با هر بار اجرا یک واحد زیاد می‌شود. مقدار اولیه متغیر i برابر 0 است و تا عدد 5 ادامه پیدا می‌کند. اما مقدار رجیستر UDR از عناصر آرایه و به ترتیب از حرف H تا حرف آخر ادامه می‌یابد.

پس از اینکه به UDR مقدار داده شد، باید منتظر بمانیم تا داده ارسال شده و رجیستر UDR خالی و آماده ارسال بایت بعدی شود. اینکار با دستور (while((UCSRA&0x20)==0x00 انجام می‌شود. به عبارتی بیت UDRE واقع در رجیستر UCSRA وقتی رجیستر UDR خالی شود 1 خواهد شد. پس اگر مقدار UCSRA را با 0x20 بصورت منظقی & کنیم و حاصل را با 0x00 مقایسه کنیم، در حالت عادی شرط صحیح بوده و CPU در دستور while صبر می‌کند. اما به محض 1 شدن بیت UDRE، شرط نادرست شده و CPU از while خارج می‌شود. بنابراین حلقه به انتها رسیده و از اول حلقه، رجیستر UDR مقدار بعدی را گرفته و این روال ادامه خواهد یافت.

شاید از این پست‌ها خوشتان بیاید