آموزش میکروکنترلر Stm32f1 به صورت رجیستری قسمت سوم UART

0
109
UART
UART

ادامه

در قسمت دوم در رابطه با GPIO در حالت ورودی صحبت کردیم. موضوع این جلسه رو بعداز کلی مشغله و دیرشدن به مبحث شیرین و بسیار کاربردی UART می‌پردازیم. خب همونطور که شاید می‌دونید ارتباط سریال به دو دسته سنکرون(همزمان) و آسنکرون(غیرهمزمان) تقسیم می‌شود. اینکه سنکرون و یا آسنکرون چی هست رو به خودتون می‌سپارم بالاخره تحقیق‌کردن رو باید از چیزای کوچیک و دم‌دستی شروع‌کرد.

UART و USART

بدون اتلاف وقت برویم سر اصل مطلب. میکروکنترلر STM32F10x معمولا چند عدد USART و چند عدد UART در دسترس ما قرار داده است که در پریفرال‌های USART این قابلیت وجود دارد که به مانند UART از این پریفرال‌ها بهره بگیریم. ازنظر مداری یکی‌از ساده‌ترین مدل‌های ارتباط و خوش‌دست‌ترین مدل ارتباط ازنظر من همین ارتباط سریال است که انصافا با کمترین دانش مداری و برنامه‌نویسی (مثل من) می‌شه راه‌اندازیش کرد. خب به عکس‌زیر توجه‌کنید:

پروتکل UART
پروتکل UART

 

در عکس بالا مشخصه که ارتباط سریال به ۳سیم نیازمند است که یکی TXبرای ارسال و دیگری RX برای دریافت و سیم سوم که خیلی مهمه در این ارتباط GND است که عدم‌توجه به این اتصال باعث میشه کل کارمون رو هوا باشه. خب ازنظر مداری همین حد بسه دیگه وقتشه که بریم سروقت رجیسترها و تنظیمات UART. اول مرتبه باید ببینیم پایه UART1 rx-tx بر روی میکرو موردنظرمان (stm32f103re) کجاست، که من برای پیداکردنش از نرم‌افزار cubemx استفاده میکنم.

پروتکل UART
پروتکل UART

 

همین اول کار یه‌چیزی بگم تا یادم نرفته اگه خوب به عکس‌بالا توجه‌کنیم میبینیم پایه A9-A10 برای UART استفاده‌شده، اما ما نمی‌خواهیم از این پین استفاده‌کنیم(البته به دلایل متعدد) شرکت St به ما این دسترسی را ازطریق رجیستر remap داده که بتونیم پایه‌ها را جابه‌جا کنیم، البته نه هرچیزی که دلمون بخواد.

AFIO_MAPR رجیستر remap کردن پایه‌ها

رجیستر remap
رجیستر remap

 

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

رجیستر remap
رجیستر remap

 

فکر می‌کنم عکس‌بالا لازم به توضیح نداشته‌باشه، اما من اگر بخوام در برنامه‌نویسی مشخص‌کنم که ریمپ صورت نگیره چه کاری باید بکنم؟

 AFIO -> MAPR &=~ (1UL << 2); // clear remap

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

AFIO -> MAPR |=  (1UL << 2);

تنظیمات UART دو بخش داره، اول پایه‌هایی که می‌خواهیم ازشون برای UART استفاده کنیم و دوم تنظیمات خود پریفرال UART. در زیر به تشریح هرکدام خواهیم‌پرداخت:

بخش اول:

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

پروتکل UART
پروتکل UART

 

پس نتیجه می‌گیریم پایه TX باید خروجی باشد اما خروجی معمولی نه، بلکه از نوع Alternate Function output به عکس‌زیر توجه‌کنید:

پروتکل UART
پروتکل UART

 

خب به این صورت برنامه‌نویسی می‌کنیم:

GPIOA -> CRH &= ~ (1 << 1 );// GPIOA -> CRH &= ~ (0xFF << 4 );

GPIOA -> CRH |= (0x0BUL << 4 );// Alternate Function output

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

پروتکل UART
پروتکل UART

 

اما پایه RX را چون دریافت‌کننده است ورودی از نوع Input floating می‌کنم.

GPIOA -> CRH |= 0x00000400  ;// Input floating

 

بخش دوم:

در این قسمت تنظیمات خود UART رو پیکربندی می‌کنیم، اولین قدم برمیگرده به درک عملکرد UART. منظورم از درک عملکرد UART اینه که چون ما هیچ کلاکی جهت همزمان‌کردن دستگاه ارسال‌کننده و دریافت‌کننده پیام نداریم و دستگاه دریافت‌کننده نمی‌دونه دیتای شروع کدومه، پیام کدومه، سروته کدومه، بخاطر همین از چیزی به اسم بادریت استفاده می‌کنیم تا بتونیم همزمانی رو یک جوری به‌صورت قراردادی در هردو سمت(فرستنده و گیرنده) داشته‌باشیم. البته اینکه بادریت کلا چی هست، با خودتون‌(ساده‌است اما تحقیق‌کنید) اما خب برای تنظیم بادریت یک رجیستر داریم به اسم baud rate register. UART_BRR:

baud rate
baud rate

 

به عکس‌بالا توجه‌کنید در این رجیستر دو قسمت داریم، [DIV_Fraction[3:0 و [DIV_Mantissa[11:0 مقداری که در این دو قسمت نوشته‌شود بادریت رو مشخص می‌کند. اما چطور؟

baud rate
baud rate

 

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

 

TX/RX baud: بادریتی که می‌خواهیم.

Fclk: فرکانس UART ما (توجه‌کنید که فرکانس هر باس باهم فرق می‌کند طبق عکس‌های بالا).

16: ثابت. حالا می‌خواهیم بادریت 115200 را در رجیستر BRR قرار دهیم.

(72 000 000)/(16*115200) = 39.0625

خب عددی که حاصل‌شده از دو قسمت ۳۹ و ۰.۰۶۲۵ است که مقدارصحیح را در [DIV_Mantissa[11:0 قرار می‌دهیم، اما مقدار اعشاری۰.۰۶۲۵ را باید ضرب در عدد ثابت ۱۶ کرده و در مقدار [DIV_Fraction[3:0 قراردهیم:

16*0.0625 = 1

که اگرمقدارها را تبدیل به عدد هگز کنیم ۳۹ می‌شود 0x027 و عدد ۱ که می‌شود همان 0x1 که برای نوشتن در رجیستر BRR از روش‌زیر استفاده می‌کنیم:

USART1 -> BRR = 0x0271 // 0x027  --- 0x1

به‌طورمثال برای ۹۶۰۰ و فرکانس ۱۲مگ داریم:

12 000 000 /(16 * 9600 ) = 78.125
78 = 0x4E
0.125*16 = 2 
USART1 -> BRR = 0x4E2//0x4E----2

اگر مقدار [DIV_Fraction[3:0 یک عددی باشد که کری داشته‌باشد به قسمت [DIV_Mantissa[11:0 اضافه می‌شود، حالا یعنی چی؟ یعنی [DIV_Fraction[3:0 که چهاربیت دارد مقدار ۰ تا ۱۵ رو می‌تواند در خود قرار دهد حالا اگر ضرب ۱۶ با [DIV_Fraction[3:0 یک عدد بزرگتر از ۱۵ بود یک کری به [DIV_Mantissa[11:0 اضافه می‌شود.

baud rate
baud rate

 

تا اینجای کار توانستیم بادریت رو فعال‌کنیم حالا می‌وریم سروقت رجیسترهای UART.

رجیستر CR1 :Control register 1UART

Register
Register

 

خب همونطورکه از عکس‌بالا مشاهده می‌کنید ۱۴بیت از ۳۲بیت آن دردسترس است که هرکدام رو که لازم‌باشه در ارتباط UART توضیح می‌دهم.

RE: بیت شماره۲ از رجیستر CR1 برای فعال‌سازی حالت RX است.
Receiver enable This bit enables the receiver. It is set and cleared by software :Bit 2 RE

0: Receiver is disabled

1: Receiver is enabled and begins searching for a start bit

USART1 -> CR1 |= (1UL<<2);

TE: بیت شماره۳ از رجیستر CR1 برای فعال‌سازی حالت TXاست. Transmitter enable This bit enables the transmitter. It is set and cleared by software :Bit 3 TE 0: Transmitter is disabled 1: Transmitter is enabled

USART1 -> CR1 |= (1UL<<3);

البته بعداز فعال‌سازی این رجیستر باید یک زمان کوتاهی رو delay درنظر بگیریم(طبق گفته دیتاشیت) When TE is set there is a 1 bit-time delay before the transmission starts :Note برای ایجاد تاخیر هم از روش‌زیر استفاده‌کنید:

For(int i = 0 ; I < 0x1000 ; i++)
{
_ _nop();
}

تابع ()nop هم به کامپایلر می‌فهماند که این تکه کد جز حلقه اصلی است(مانند کد اسمبلی) که درهنگام کامپایل و بهینه‌سازی کامپایلر حذفش نکند.

M: بیت شماره۱۲ از رجیستر CR1 برای مشخص‌کردن تعداد data بیت است. 0: 1 استارت بیت و ۸دیتا بیت. 1: 1 استارت بیت و ۹دیتا بیت.

USART1 -> CR1 &=~ (1<<12);

UE: بیت شماره ۱۳ فعال‌کننده کل UART است (USART enable) 0: غیرفعال‌کننده UART. 1: فعال‌کننده UART.

UART1 -> CR1 |= (1<<13);

تا اینجای کار رو داشته باشید تا در قسمت چهارم ادامشو باهم یاد بگیریم.

 

منبع: سیسوگ

برای این مقاله نظر بگذارید:

لطفا دیدگاه خود را بنویسید
لطفا نام خود را وارد کنید