خدایا با نام تو با یاد تو و برای تو.
سلام دوستان و همراهان عزیز مهدی حسن زاده آملی، با جلسه سوم آموزش کاملا رجیستری STM32F10x در خدمت شما هستم.
در قسمت دوم در رابطه با GPIO در حالت ورودی صحبت کردیم.
موضوع این جلسه رو بعد از کلی مشغله و دیر شدن به مبحث شیرین و بسیار کاربردی UART میپردازیم. خب همونطور که شاید میدونید ارتباط سریال به دو دسته سنکرون (همزمان) و آسنکرون (غیر همزمان) تقسیم میشود. اینکه سنکرون و یا آسنکرون چی هست رو به خودتون میسپارم بالاخره تحقیق کردن رو باید از چیزای کوچیک و دم دستی شروع کرد.
UART و USART
بدون اتلاف وقت برویم سر اصل مطلب. میکروکنترلر STM32F10x معمولا چند عدد USART و چند عدد UART در دسترس ما قرار داده است که در پریفرالهای USART این قابلیت وجود دارد که به مانند UART از این پریفرالها بهره بگیریم.
از نظر مداری یکی از سادهترین مدلهای ارتباط و خوشدستترین مدل ارتباط از نظر من همین ارتباط سریال است که انصافا با کمترین دانش مداری و برنامه نویسی (مثل من) میشه راهاندازیش کرد.
خب به عکس زیر توجه کنید:
در عکس بالا مشخصه که ارتباط سریال به سه سیم نیازمند است که یکی TXبرای ارسال و دیگری RX برای دریافت و سیم سوم که خیلی مهمه در این ارتباط GND است که عدم توجه به این اتصال باعث میشه کل کارمون رو هوا باشه.
خب از نظر مداری همین حد بسه دیگه وقتشه که بریم سروقت رجیسترها و تنظیمات UART.
اول مرتبه باید ببینیم پایه UART1 rx-tx بر روی میکرو موردنظرمان (stm32f103re) کجاست، که من برای پیدا کردنش از نرمافزار cubemx استفاده میکنم.
همین اول کار یه چیزی بگم تا یادم نرفته اگه خوب به عکس بالا توجه کنیم میبینیم پایه A9-A10 برای UART استفاده شده، اما ما نمیخواهیم از این پین استفاده کنیم (البته به دلایل متعدد) شرکت St به ما این دسترسی را از طریق رجیستر remap داده که بتونیم پایهها را جابهجا کنیم، البته نه هرچیزی که دلمون بخواد.
AFIO_MAPR رجیستر remap کردن پایهها
همینطور که در عکس بالا مشخصه خانه شماره 2 در این رجیستر برای USART1 هستش که طبق عکس زیر مقداردهی میشود.
فکر میکنم عکس بالا لازم به توضیح نداشته باشه، اما من اگر بخوام در برنامهنویسی مشخص کنم که ریمپ صورت نگیره چه کاری باید بکنم؟
1 | AFIO -> MAPR &=~ (1UL << 2); // clear remap |
کد بالا بیشتر برای اطمینان نوشته میشه اگر هم بخواهیم ریمپ کنیم از کد زیر استفاده میکنم:
1 | AFIO -> MAPR |= (1UL << 2); |
تنظیمات UART دو بخش داره، اول پایههایی که میخواهیم ازشون برای UART استفاده کنیم و دوم تنظیمات خود پریفرال UART. در زیر به تشریح هر کدام خواهیم پرداخت:
بخش اول:
پایه هایی که میخواهیم از آنها اطلاعات بفرستیم و دریافت کنیم باید کانفیگ خاص خودشو داشته باشه مثلا زمانی که TX دیتایی رو میخواهد بفرستد، دیتای ارسالی مانند شکل زیر ترکیبی از صفر و یکهایی است که باید در خروجی نمایش داده شود:
پس نتیجه میگیریم پایه TX باید خروجی باشد اما خروجی معمولی نه، بلکه از نوع Alternate Function output به عکس زیر توجه کنید:
خب به این صورت برنامهنویسی میکنیم:
1 2 3 | GPIOA -> CRH &= ~ (1 << 1 );// GPIOA -> CRH &= ~ (0xFF << 4 ); GPIOA -> CRH |= (0x0BUL << 4 );// Alternate Function output |
اگر مقداردهی بالا گنگ است به عکس زیر و یا به مطلب قسمت اول مراجعه کنید.
اما پایه RX را چون دریافتکننده است ورودی از نوع Input floating میکنم.
1 | GPIOA -> CRH |= 0x00000400 ;// Input floating |
بخش دوم:
در این قسمت تنظیمات خود UART رو پیکربندی میکنیم، اولین قدم برمیگرده به درک عملکرد UART. منظورم از درک عملکرد UART اینه که چون ما هیچ کلاکی جهت همزمان کردن دستگاه ارسال کننده و دریافت کننده پیام نداریم و دستگاه دریافتکننده نمیدونه دیتای شروع کدومه، پیام کدومه، سر و ته کدومه، به خاطر همین از چیزی به اسم بادریت استفاده میکنیم تا بتونیم همزمانی رو یک جوری به صورت قراردادی در هر دو سمت (فرستنده و گیرنده) داشته باشیم.
البته اینکه بادریت کلا چی هست، با خودتون (ساده است اما تحقیق کنید) اماخب برای تنظیم بادریت یک رجیستر داریم به اسم baud rate register.
UART_BRR:
به عکس بالا توجه کنید در این رجیستر دو قسمت داریم، [DIV_Fraction[3:0 و [DIV_Mantissa[11:0 مقداری که در این دو قسمت نوشته شود
بادریت رو مشخص میکند. اما چطور؟
فرمولش رو در عکس بالا میبینید، اما شیوه محاسبش را در ادامه خواهیم گفت.
اول فرکانسی که به پریفرال ما میاد رو باید بدونیم به دو عکس زیر توجه کنید:
TX/RX baud: بادریتی که میخواهیم.
Fclk: فرکانس UART ما (توجه کنید که فرکانس هر باس با هم فرق میکند طبق عکسهای بالا).
16: ثابت.
حالا میخواهیم بادریت 115200 را در رجیستر BRR قرار دهیم.
1 | (72 000 000)/(16*115200) = 39.0625 |
خب عددی که حاصل شده از دو قسمت 39 و 0.0625 است که مقدار صحیح را در [DIV_Mantissa[11:0 قرار میدهیم، اما مقدار اعشاری 0.0625 را باید ضرب در عدد ثابت 16 کرده و در مقدار [DIV_Fraction[3:0 قرار دهیم.
1 | 16*0.0625 = 1 |
که اگرمقدارها را تبدیل به عدد هگز کنیم 39 میشود 0x027 و عدد 1 که میشود همان 0x1 که برای نوشتن در رجیستر BRR از روش زیر استفاده میکنیم:
1 | USART1 -> BRR = 0x0271 // 0x027 --- 0x1 |
به طور مثال برای 9600 و فرکانس 12 مگ داریم:
1 2 3 4 | 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 که چهار بیت دارد مقدار 0 تا 15 رو میتواند در خود قرار دهد حالا اگر ضرب 16 با [DIV_Fraction[3:0 یک عدد بزرگتر از 15 بود یک کری به [DIV_Mantissa[11:0 اضافه میشود.
تا اینجای کار توانستیم بادریت رو فعال کنیم حالا میوریم سروقت رجیستر های UART.
رجیستر CR1 :Control register 1
خب همونطور که از عکس بالا مشاهده میکنید 14 بیت از 32 بیت آن در دسترس است که هر کدام رو که لازم باشه در ارتباط UART توضیح میدهم.
RE: بیت شماره 2 از رجیستر 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
1 | USART1 -> CR1 |= (1UL<<2); |
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
1 | USART1 -> CR1 |= (1UL<<3); |
البته بعد از فعالسازی این رجیستر باید یک زمان کوتاهی رو delay در نظر بگیریم (طبق گفته دیتاشیت)
When TE is set there is a 1 bit-time delay before the transmission starts :Note
برای ایجاد تاخیر هم از روش زیر استفاده کنید:
1 2 3 4 | For(int i = 0 ; I < 0x1000 ; i++) { _ _nop(); } |
تابع ()nop هم به کامپایلر میفهماند که این تکه کد جز حلقه اصلی است (مانند کد اسمبلی) که در هنگام کامپایل و بهینهسازی کامپایلر حذفش نکند.
M: بیت شماره 12 از رجیستر CR1 برای مشخص کردن تعداد data بیت است.
0: 1 استارت بیت و 8 دیتا بیت.
1: 1 استارت بیت و 9 دیتا بیت.
1 | USART1 -> CR1 &=~ (1<<12); |
UE: بیت شماره 13 فعال کننده کل UART است (USART enable)
0: غیرفعالکننده UART.
1: فعالکننده UART.
1 | UART1 -> CR1 |= (1<<13); |
تا اینجای کار رو داشته باشید تا در قسمت چهارم ادامشو باهم یاد بگیریم.
سلام
ببخشید پسوند UL چی هست؟
ایا معادلی داره؟
سلام دوست عزیز داریم با این پیسوند به کامپایلر میگیم نوع عددی رو از نوع unsigned long در نظر بگیر
سلام
در قسمت محاسبه باودریت بخش DIV_FRAC چرا مقدار اعشاری رو باید در عدد ۱۶ ضرب کنیم؟ یا مثلا در STM32 وقتی OVER8=1 باشه چرا باید در ۸ ضرب کنیم؟
سلام
خسته نباشید
اگه ممکنه راجب مزایای برنامه نویسی رجیستری هم توضیح بدین.
ممنون از بابت آموزش های ارزشمندتون … خیلی زحمت می کشید …