ARM, STM32, آموزش, آموزش STM32 با توابع LL, توصیه شده, مقاله های سیسوگ

ریدایرکت printf و scanf به کمک USART در STM32 | آموزش قسمت چهاردهم STM32 با توابع LL

ریدایرکت printf و scanf به کمک USART در STM32 | آموزش قسمت چهاردهم STM32 با توابع LL

در بخش‌های هشتم و نهم، به ترتیب با نحوه ارسال و دریافت اطلاعات توسط واحد USART آشنا شدیم و در قسمت قبلی هم با Timer-Input capture آشنا شدیم. در این بخش، می‌خواهیم واحد USART بورد Blue Pill را راه‌اندازی کنیم و ریدایرکت Printf و Scanf به کمک USART آموزش دهیم. همان‌طور که می‌دانید برای دریافت یا ارسال اطلاعات از طریق USART، باید از طریق دستورات سطح پایین (تنظیم و چک کردن رجیسترها) استفاده کنیم. درحالی‌که کار با توابع کتابخانه‌های ورودی/خروجی استاندارد زبان C، آسان است و قابلیت‌های بسیار خوبی به ما می‌دهد. با ریدایرکت کردن این توابع با USART، می‌توانیم از این امکانات در کار با این واحد، بهره ببریم.

با سیسوگ همراه باشید.

 

مرحله اول – ایجاد پروژه در محیط STM32CubeMX

ابتدا باید روال عادی ایجاد پروژه در نرم‌افزار CubeMX طی شود:

از منوی File، New Project یک پروژه جدید می‌سازیم. اسم میکروی موردنظرمان را در قسمت Part Number جست‌وجو و آن را انتخاب می‌کنیم. سپس باید از تب Pinout & Configuration منوی System core، کلاک و رابط دیباگ را تنظیم کنیم، بدین منظور از قسمت RCC برای کلاک HSE، کریستال انتخاب می‌شود:

 

تنظیم رابط دیباگ

برای رابط دیباگ نیز باید از بخش SYS، Serial Wire به‌عنوان رابط دیباگ انتخاب شود. سپس باید تنظیمات واحد USART را انجام دهیم. برای این منظور از همین تب Pinout & Configuration، منوی Connectivity و از این منو USART1 را انتخاب می‌کنیم. در منوی بازشده حالت آسنکرون (Asynchonous) را برمی‌گزینیم و در بخش Parameter Settings که در زیر این منو قرار دارد تنظیمات Buad Rate، تعداد بیت داده، بیت آغاز و پایان و همچنین جهت اطلاعات را به‌صورت زیر انجام می‌دهیم:

 

توجه شود که این مقادیر به‌صورت دلخواه انتخاب‌شده‌اند و بنا به نیاز هرکدام می‌توانند تغییر کنند. جهت اطلاعات نیز بسته به این‌که می‌خواهیم از این واحد USART1، تنها اطلاعات بفرستیم یا بخوانیم، یا اینکه هر دو عمل را انجام دهیم تعیین می‌شود. در اینجا چون هر دو عمل موردنیاز است Receive and Transmit انتخاب‌شده است.

بخش بعدی برای ریدایرکت printf و scanf به کمک USART که باید تنظیم شود، وقفه واحد USART است که در صورت نیاز باید از بخش تنظیمات وقفه (NVIC) این کار را انجام دهیم. در صورتی نیاز به دریافت اطلاعات بهتر است وقفه این واحد را فعال کنیم.

قابل‌ذکر است که همانند همه وقفه‌های دیگر، فعال‌سازی این وقفه از منوی System Core بخش NVIC نیز قابل انجام است. پس‌ازاین تنظیمات در صورت نیاز پین‌های ورودی، خروجی دیگر نیز با کلیک روی آن‌ها روی IC نمایش داده‌شده  و انتخاب GPIO_Input یا GPIO_Output تنظیم می‌شوند.

 

تنظیم کلاک

برای ریدایرکت printf و scanf به کمک USART باید به سراغ تنظیم کلاک برویم. با انتخاب Crystal به‌عنوان منبع کلاک و با تنظیمات پیش‌فرض، کلاک برابر با  MHz8 قرار داده‌شده است. اگر مقدار دیگری برای کلاک مدنظر باشد باید در این بخش و در قسمت HCLK این مقدار را تنظیم کنیم. همچنین برای تنظیم کلاک هر بخش به پارامترهای PLL و Prescaler نیز دسترسی داریم.

 

تنظیمات نهایی

در آخر باید به سراغ تب Project Manager برویم. در اولین بخش یعنی Project، نام و مسیر پروژه مشخص می‌شود. در قسمت IDE  Toolchain /، باید نرم‌افزاری موردنظر برای توسعه پروژه انتخاب شود که چون در اینجا با نرم‌افزار Keil کار می‌کنیم روی گزینه MDK-ARM کلیک می‌کنیم.

در منوی بعدی یعنی Code Generator حتماً چک شود که گزینه Keep User Code when re-gererating، فعال باشد، زیرا در غیر این صورت هرگاه که با برنامه CubeMX تغییراتی در پروژه ایجاد کنیم کدهای نوشته‌شده توسط ما پاک می‌شوند.

آخرین منو که همان Advanced Setting است، مربوط به نوع درایورها یا توابع مورداستفاده است که می‌توانند از نوع HAL یا LL انتخاب شوند، در اینجا ما با توابع LL کار می‌کنیم.

اکنون تمامی تنظیمات موردنظر ما انجام‌شده است. روی GENERATE CODE کلیک می‌کنیم تا پروژه ایجاد شود. حالا روی Open Project کلیک می‌کنیم تا پروژه در محیط Keil باز شود.

 

 مرحله دوم – تعریف توابع مورد نیاز در محیط Keil

برای ریدایرکت و ایجاد امکان استفاده از دستورات scanf و printf به‌وسیله USART  باید اقداماتی که در ادامه گفته می‌شود (منبع) را در محیط برنامه Keil در پروژه انجام داد؛ در پنجره اصلی برنامه Keil، گزینه Project را انتخاب می‌کنیم و از بخش Manage، Run-Time Environment را کلیک می‌کنیم. در پنجره بازشده از زیرمنوی Compiler  و سپس I/O دو پارامتر STDIN و STDOUT را به‌صورت زیر تغییر می‌دهیم:

منوی KEIL

تغییر تعریف توابع ورودی STDIN و خروجیSTDOUT به حالت User.

 

 نکته1: برای امکان از وقفه دریافت اطلاعات توسط واحد USART حتما باید دستور زیر را به برنامه اضافه نمود:   

 نکته2: فراموش نشود که برای استفاده از توابع scanf و printf باید کتابخانه “stdio.h” را اضافه کرد. 

اکنون باید تعریف دو تابع stdout_putchar و stdin_getchar را در ابتدای فایل اصلی برنامه (main.c) و یا هر فایلی که دسترسی به آن تعریف‌شده است، انجام داد. بدین‌وسیله توابع scanf و printf را ریدایرکت خواهیم کرد. اما قبل از انجام این کار، برای دریافت داده‌های ورودی از USART (به‌وسیله وقفه) و همچنین ارسال اطلاعات دو تابع read_uart و write_uart را تعریف می‌کنیم.

در تابع write_uart می‌توانیم به‌سادگی پرچم ارسال اطلاعات واحد USART را چک کنیم و در صورت آزاد بودن داده موردنظر را ارسال کنیم:

اما برای تابع read_uart موضوع کمی پیچیده‌تر است. همان‌طور که گفته شد دریافت اطلاعات را توسط وقفه انجام می‌دهیم. پس باید ابتدا در روال وقفه اطلاعات دریافت شده توسط میکرو را بایت به بایت بخوانیم، سپس اطلاعات خوانده‌شده رو در یک بافر ذخیره کنیم و توسط تابع read_uart این بافر را خوانده و برگردانیم. برای نمونه روال وقفه خواندن واحد USART را می‌توان به‌صورت زیر نوشت:

که در آن متغیرهای buffer، w_index و counter به‌صورت گلوبال و همچنین از نوع volatile ساخته‌شده‌اند، همچنین متغیر r_index را نیز برای اندیس خواندن در فایل تعریف stm32f1xx_it.c می‌کنیم؛

حالا باید تابع read_uart را برای خواندن از بافر تعریف کنیم؛

در این تابع ابتدا متغیر counter (که تعداد کاراکترهای دریافت شده توسط وقفه و خوانده‌نشده توسط تابع read_uart را نشان می‌دهد)، چک می‌شود تا در صورت صفر بودن این مقدار، برنامه منتظر دریافت کاراکتر بعدی باشد. سپس کاراکتری از بافر که با اندیس r_index تعیین می‌شود، خوانده‌شده و در متغیر data قرار داده می‌شود تا توسط تابع برگردانده شود. پس از هر بار خواندن بافر متغیر counter یک واحد کاهش می‌یابد. همچنین می‌توان برای اطمینان بیشتر و درجایی که امکان ایجاد وقفه قبل از کاهش counter وجود دارد، وقفه را غیرفعال، و سپس دوباره فعال کرد. بدین‌وسیله مقدار counter همیشه درست خواهد بود. توجه شود درصورتی‌که این تابع را در فایل stm32f1xx_it.c تعریف کرده‌ایم، باید در تابع main قبل از استفاده از آن، تابع را اعلان کنیم.

اکنون‌که توابع موردنیاز نوشته‌شده‌اند، باید عمل ریدایرکت کردن printf و scanf را انجام دهیم. همان‌طور که گفته شد برای این‌کار باید دو تابع stdout_putchar (به‌کاررفته در printf) و stdin_getchar (به‌کاررفته در scanf) را تعریف کنیم. با استفاده از توابع خواندن و نوشتن که تعریف‌شده‌اند این دو تابع را می‌توان به‌سادگی به‌صورت زیر تعریف کرد:

 

مرحله سوم – استفاده از توابع نوشته‌شده برای دریافت و ارسال اطلاعات با scanf و printf توسط واحد USART

اکنون‌که عمل ریدایرکت کردن را انجام داده‌ایم، می‌توانیم از توابع scanf و printf استفاده کنیم و اطلاعات را دریافت یا ارسال کنیم، برای مثال در بدنه while می‌توان دستورات زیر را برای تست نوشت و یک اسم از کاربر دریافت کرد.

متغیر data را میتوان خارج از بدنه (1)while تعریف کرد.

اکنون‌که نوشتن کد به‌پایان رسیده است، از برنامه build گرفته و آن را روی میکرو لود می‌کنیم. قابل‌ذکر است که اگر از برنامه Keil برای download کد روی میکرو استفاده می‌شود، بهتر است از قسمت project، Options for Target را انتخاب کنیم، سپس از قسمت سمت راست  در تب  Debug، روی Setting کلیک کرده و در پنجره بازشده، از تب Flash Download، گزینه Reset and Run را فعال کنیم.

برای دریافت و ارسال اطلاعات بین میکرو و کامپیوتر، احتیاج به یک تبدیل TTL به USB داریم که باید با توجه به پایه‌هایی که در میکرو برای TX و RX تعریف‌شده‌اند، به ترتیب پایه مربوط به TX میکرو را به RX متصل به کامپیوتر و پایه RX میکرو را به TX متصل به کامپیوتر وصل کنیم.

 

   پس از ران کردن میکرو، نتیجه اجرای کد را می‌توان در ترمینال مشاهده کرد. در اینجا برای نمایش اطلاعات، از ترمینال RealTerm استفاده شده است.

 

 

خطاهای احتمالی

  • دستور مربوط به فعال‌سازی وقفه دریافت اطلاعات توسط USART (نکته 1) باید حتماً در تابع int main و بعد از فراخوانی SystemClock_Config نوشته شود. در غیر این صورت، برنامه دچار خطا خواهد شد. همچنین درصورتی‌که نوشتن این دستور فراموش شود همین نتیجه را خواهیم گرفت و روال وقفه اجرا نخواهد شد.
  • در بدنه تابع خواندن اطلاعات ورودی از واحد USART، مانند کد نمونه، باید از یک بافر استفاده شود، زیرا اطلاعات ممکن است به‌صورت رشته وارد شوند. درصورتی‌که از بافر استفاده نکنیم ممکن است در اجرای کد و در دریافت اطلاعات خطا ایجاد شود.
  • یکی از راه‌های توصیه‌شده در وب‌سایت‌های مختلف، برای ریدایرکت کردن توابع scanf و printf، استفاده از قالب‌های کد آماده‌ای است که در منوی User Code Template (با کلیک راست کردن روی پوشه کدها در سمت چپ برنامه و انتخاب گزینه Add new item.. به این منو دسترسی داریم) قرار دارند. اما استفاده از این روش با خطاهای زیادی مواجه می‌شود. پیشنهاد می‌کنیم که همانند توضیحات داده‌شده، تنها فرمت تعریف دو تابع putchar و getchar که در این فایل‌ها وجود دارد استفاده کنید.

در این بخش نحوه ریدایرکت printf و scanf به کمک USART را آموختیم و در بخش بعدی با چگونگی راه‌اندازی واحد ADC و گرفتن اطلاعات آن توسط DMA، آشنا خواهیم شد.

لینک پروژه در گیت هاب

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

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

10 دیدگاه در “ریدایرکت printf و scanf به کمک USART در STM32 | آموزش قسمت چهاردهم STM32 با توابع LL

  1. Avatar for حمید حمید گفت:

    سلام
    تنظیم scanf و printf به این صورت چه مزیتی نسبت به کارکردن مستقیم با خود usart داره؟
    چون عملا میشه با usart و یه رابط USB to TTL دیتا به کامپیوتر ارسال و دریافت کرد…

    1. Avatar for Mahdi.h   Mahdi.h   گفت:

      سلام
      با کمک این دستورات میتونید رشته ها رو به صورت پیشرفته تر ارسال یا دریافت کنید
      مثلا با printf شما میتونید یک رشته ارسال کنید که داخلش متغیر های عددی هم باشه
      یا با کمک scanf میتونید یک رشته دریافتی رو پردازش کنید و مثلا بگید با این الگو بخون رشته رو و دوتا int از توش در بیار و بریز توی یه متغیر
      اطلاعات بیشتر :
      https://www.decodejava.com/c-scanf-and-printf-function.htm

  2. Avatar for امیر امیر گفت:

    بی‌نظیر هستید…

  3. Avatar for محمدرضا محمدرضا گفت:

    کلی توی اینترنت گشتم، اما نتونستم با HAL ریتارگت کنم! کل میکرو هنگ میکرد و آخرش نفهمیدم برای چیه.
    آخرش با LL این کارو کردم.
    حتی مرحله ی:
    تغییر تعریف توابع ورودی STDIN و خروجیSTDOUT به حالت User
    ، رو هم با HAL انجام دادم ولی نشد.(یه توضیح میدین که اصلا این توابعی که فعال کردیم چی هست؟)
    در کل LL خیلی بهتره ولی خب یه کم پیچیده تر.

  4. Avatar for فاضل فاضل گفت:

    سلام
    برای ریدایرکت کردن در CubeIDE چکار باید کرد؟

    1. Avatar for Zeus ‌ Zeus ‌ گفت:

      سلام دوست عزیز
      خوب لازمه بدونید که CubeIDE از کامپایلر gcc استفاده میکنه و اگر به دنبال راه حل برای gcc باشید به راحتی به جواب خواهید رسید، برای نمونه لینک زیر رو ببینید
      ریدایرکت printf در cubeide

  5. Avatar for پرنیا پرنیا گفت:

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

    کاش dsp هم یاد بدین شما که اینقد خوب میگید.

    1. Avatar photo سیاوش گفت:

      مرسی از همراهی و انرژی مثبتتون.
      سعی می‌کنیم در صورت امکان اون آموزش رو هم توی برنامه‌مون قرار بدیم.

  6. Avatar for VHD VHD گفت:

    مرسی که ادامه دادید

    1. Avatar photo سیاوش گفت:

      خواهش میکنم.
      مرسی از همراهی‌تون. به زودی قسمت‌های بعدی آموزش رو هم منتشر می‌کنیم.

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

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