ARM, STM, STM32, آموزش, توصیه شده, مقاله

آموزش میکروکنترلر STM32 : مثال عملی رابط سریال UART

آموزش میکروکنترلر STM32 :

سیسوگ در قسمت هفتم  از  آموزش میکروکنترلر STM32 تنظیمات نرم‌افزار CubeMX برای رابط سریال UART را آموزش داد. در این قسمت از آموزش میکروکنترلر STM32 قصد دارد آموزش ها را در قالب یک مثال عملی نشان دهد. با سیسوگ همراه باشید.

 

خوب حالا که با وظیفه و نحوه عملکرد تابع HAL_UART_Transmit آشنا شدیم بد نیست یک مثال عملی برای کار با آن در میکروکنترلر STM32 بزنیم:

 

همین‌طور که در مثال بالا میبینید ما یک رشته 15 کاراکتری را از طریق فرمان یاد شده توسط huart1 در حداکثر زمان 1 میلی ثانیه ارسال می‌کنیم، دلیل گذاشتن (uint8_t *) هم قبل از رشته مورد نظر بخاطر این است که رشته از نوع char است و از طریق این عملگر به نوع آرگومان مشابه مورد نیاز تابع تبدیل می‌شود، تا کامپایلر پیام اخطار ندهد و توجه داشته باشید در آینده نیز از این شکل عملگر زیاد استفاده خواهیم کرد. در صورت نیاز نیز می‌توانیم خروجی تابع را بررسی کنیم تا متعاقباً دستورات لازم در شرایط مختلف صورت پذیرد.
فرمان بعدی که باید در کتابخانه hal مورد بررسی قرار دهیم فرمان دریافت یک رشته از رابط سریال است.

 

در آرگومان *huart تابع نام uart مورد استفاده ما قرار می‌گیرد و در آرگومان *pData رشته‌ای که قرار است از رابط سریال دریافت شود، مشخص می‌شود. در آرگومان Size سایز ، تعداد بایتی که قرار است دریافت شود تعیین می‌شود. آرگومان Timeout حداکثر زمانی را مشخص می‌کند که این تابع باید در این مدت زمان رشته را از رابط سریال دریافت کند.
در اینجا هم شکل کار مشابه نحوه عملکرد تابع ارسال می‌باشد و مقدار برگشتی تابع هم از همان نوع می‌باشد. بدین صورت که اگر به بدنه این تابع در برگه stm32f1xx_hal_uart.c نگاه کنیم، با ارسال هر کاراکتر یکی از مقدار متغیر RxXferCount کم می‌شود تا به صفر برسد و دریافت تمام شود. پس در نتیجه ما می‌توانیم با چک کردن وضعیت این متغیر همواره از تعداد بایت دریافت شده باخبر شویم.

 

برگه stm32f1xx_hal_uart.c

آموزش میکروکنترلر STM32

 

و اگر توجه کنید در بدنه این تابع برخلاف تابع ارسال که پرچم ارسال یعنی پرچم UART_FLAG_TXE چک می‌شد. در اینجا پرچم دریافت با نام UART_FLAG_RXNE چک می‌شود تا اگر دریافت از مدت زمان Timeout بیشتر طول کشید، ادامه عملیات منتفی و برنامه به خط بعد منتقل شود. نکته مهم در اینجا این است که اگر در مدت زمان Timeout فقط مثلا از 10 بایتی که می‌خواهیم دریافت کنیم 7 بایت دریافت شود تابع مقدار HAL_TIMEOUT را برمیگرداند ولیکن ما میتوانیم همان هفت بایت را داخل متغیری که در اشاره گر *pData معرفی کردیم مشاهده کنیم برای این هم که بفهمیم چند بایت دریافت کرده ایم هم که باید همان متغیر RxXferCount را چک کنیم. یعنی اگر مقدار این متغیر 3 بود یعنی از 10 که مقدار اولیه ان بود 7 عدد کم شده و متعاقبا 7 بایت دریافت شده است.
در اینجا هم لازم است یک نمونه مثال عملی با این تابع را برای شما قرار دهیم.

 

میکروکنترلر STM32

آموزش میکروکنترلر STM32

 

در مثال بالا ابتدا ما یک آرایه از نوع char تعریف می‌کنیم و در فرمان بعد هم یک ساختار به نام Response از نوع HAL_StatusTypeDef ، تا بتوانیم خروجی تابع را بررسی کنیم و در خط 117 با فرمان دریافت به مدت زمان حداکثر 5000 میلی ثانیه صبر میکنیم تا 5 بایت از رابط سریال دریافت شود و بایتهای دریافتی را هم در داخل ارایه pData دریافت خواهیم کرد. که ما میتوانیم با توجه به خروجی تابع بررسی کنیم که آیا در مدت زمان مجاز 5 بایت دریافت شده است یا نه که به دو صورت میتوان این مسئله را چک کرد. یکی اینکه تابع خروجی HAL_OK را بدهد و یا اینکه مقدار متغیر RxXferCount که در اینجا زیر مجموعه ساختار huart1 است مساوی صفر قرار گیرد. در خط 120 مقدار 5 بایت دریافت شده داخل آرایه به نمایش در خواهد امد و در خط 122 چک می‌شود اگر تابع در مدت زمان مجاز نتوانسته تعداد بایت درخواستی ما را دریافت کند چه دستوراتی اجرا شود. در خط 125 چک می‌کنیم که اگر حداقل چند بایت از بایت‌های درخواستی ما هم دریافت شده همان‌ها را برای ما نمایش دهد. یکی از کاربردهای عمومی که این تابع می‌تواند داشته باشد، در زمانی است که ما با یک ماژول جانبی مثل sim800 که به رابط سریال متصل شده است کار می‌کنیم و می‌خواهیم بعد از فرمان دادن به ماژول ببنیم آیا تا یک حداکثر زمان مشخص پاسخ مناسب را به ما می‌دهد یا نه.
حالا که یاد گرفتیم چطور می‌توانیم توسط توابع کتابخانه hal عملیات ارسال و دریافت از رابط سریال uart را داشته باشیم بهتر است به سراغ آموزش دو فرمان عمومی ارسال و دریافت از رابط سریال برویم، یعنی فرمان‌های printf و فرمان scanf .توجه داشته باشید شما در حالت عادی نمی‌توانید از این فرمان‌ها استفاده کنید مگر بعد از معرفی توابع خواندن و ارسال کارکتر به برنامه. عملیات معرفی این فرمان‌ها مطابق عکس‌های زیر می‌باشد. ابتدا باید طبق عکس زیر توابع را در فایل main.c به برنامه معرفی کنید :

 

 

میکروکنترلر STM32

آموزش میکروکنترلر STM32

 

 

و در پایین فایل main.c هم متن توابع را به این شکل طرح برای کار با UART1 آماده می‌کنیم:

 

آماده‌سازی توابع برای کار با UART1

آموزش میکروکنترلر STM32

 

برای واحدهای دیگر رابط UART در میکروکنترولر تنها لازم است عدد آنها را تغییر دهیم ، شما اگر به مثال‌های خود شرکت st یا مثال‌های داخل اینترنت نگاه کنید، آنها از فرمان‌های خود کتابخانه hal برای ارسال و دریافت تک کاراکتر استفاده کرده‌اند ، که کاملا یک کار غیرحرفه‌ای و غیر لازم است و بهترین راه همین مستقیم کار کردن بارجیستر و پرچم‌ها با خلاصه ترین شکل کدنویسی است. کلاً توصیه من به شما این است که در برنامه‌نویسی تا حد ممکن از فرمان‌های کتابخانه hal استفاده نکنید و خودتان مستقیماً با رجیسترها کار کنید تا کیفیت کد نهایی مطلوب باشد.

 

در قسمت نهم آموزش میکروکنترلر STM32 قصد داریم طریقه کار با وقفه رابط سریال را با استفاده از توابع کتابخانه hal را توضیح دهیم. با سیسوگ همراه باشید.



انتشار مطالب با ذکر نام و آدرس وب سایت سیسوگ، بلامانع است.

شما نیز میتوانید یکی از نویسندگان سیسوگ باشید.  همکاری با سیسوگ

 

نوشته های مشابه

5 دیدگاه در “آموزش میکروکنترلر STM32 : مثال عملی رابط سریال UART

  1. Avatar Porya گفت:

    سلام مهندس
    وقت بخیر
    خیلی ممنون از آموزش هاتون
    ببخشید به یه مشکل حین کار با stm32f407 خوردم
    موقع کار با spi همه تنظیماتو انجام میدم

    ولی زمان ارسال یا دریافت رجیستر dr ظاهرا اصلا دیتایی دریافت یا ارسال نمیکنه

    تننظیمات هم کاملا درسته
    مد master انتخاب شده
    بیت BR با مقدار مناسب تنظیم شده
    بیت های cpol و cpha با مقدار درست مقدار دهی شدن
    بعد بیت spe ست شده
    مد ارسال ۸ بیتیه
    بعدش هم یه دیتا تویه رجیستر drنوشته میشه.
    برنامه منتظر میمونه تا txe یک بشه، بعد rxne بعد bsy.
    عجیبه با خوندن بیت txe برای چک شرط یک شدنش، بیت rxne صفر میشه خودکار!!
    و درنتیجه در شرط بعدی که چک کردن بیت rxneه کد گیر میکنه.
    اینکه rxne یک میشه ولی باز بافر دریافت خالیه و dr هیچ مقداری جز صفر نداره هم عجیبه!!
    بعد چک های متوالی برنامه هم از طریق توابع hal و هم کتابخونه هایی که خودم نوشتم، متوجه شدم بیت bsy هم یک نمیشه اصلا!
    پس انگار کلا واحد spi درگیر ارسال و دریافت نمیشه! ولی اگه اینجوریه چرا rxne تغییر حالت میده؟!
    هرچی چک میکنم و میخونم نتیجه ایی نمیگیرم، نمیدونم چیه مشکل واقعا

    اگه راهنماییم کنید ممنون میشم

    1. زئوس Zeus زئوس Zeus گفت:

      سلام
      امم ، اولین چیزی که به ذهنم میرسه اینه که چک کنید آیا کلاک SPI مورد استفاده رو تامین کردید یا خیر (موارد زیادی برای خودم پیش اومده که کلاک رو تنظیم نکرده بودم)
      اگر امکان داره تیکه کد کانفیگ و تیکه کدی که دیتا رو ارسال میکنید رو اینجا قرار بدید که بشه بررسی کرد. کارایی که برای ارسال انجام میدید ظاهرا درسته
      برای ارسال اول باید چک کنید که بافر ارسال خالی باشه ، بعد دیتا رو قرار بدید ؛ بعد منتظر بشید که بافر دریافت پر بشه و فرایند رو اینطور پیش ببرید

    2. زئوس Zeus زئوس Zeus گفت:

      آقای عبدالهی زحمت کشیدند و این تابع رو آماده کردند

      uint8_t SPI_ReadWriteByte(uint8_t num)
      {
      uint8_t retry=0;
      while((SPI1->SR&1< <1)==0) { retry++; if(retry>200)return 0;
      }
      SPI1->DR=num;
      retry=0;
      while((SPI1->SR&1< <0)==0) { retry++; if(retry>200)return 0;
      }
      return SPI1->DR;
      }

  2. Avatar وحید گفت:

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

    1. زئوس Zeus زئوس Zeus گفت:

      سلام دوست عزیز
      احتمالا سری دوم آموزش ها همینطور که پیشنهاد میدید پیش خواهد رفت
      موفق باشید

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *