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

آموزش STM32 با توابع LL قسمت دوم: روش‌های پیکره‌بندی و انواع توابع

آموزش STM32 با توابع LL

در قسمت اول از آموزش STM32 با توابع LL، در رابطه با پردازنده و میکروکنترلر صحبت کردیم و به تفاوت‌های میکروکنترلر و پردازنده پرداختیم. همچنین گفته بودیم که خود شرکت ARM فقط طراح پردازنده است، نه میکروکنترلر. و سه دسته‌ی مهم از پردازنده‌های نوین این شرکت را با ذکر جزئیات و کاربردها بررسی کردیم.

در نهایت در قسمت اول، میکروکنترلرهای شرکت ST که یکی از استفاده‌کنندگان پردازنده‌های ARM است را با ذکر انواع میکروکنترلرهای مبتنی بر این نوع پردازنده‌ها معرفی کردیم.

اگر به یاد داشته باشید گفتیم که شرکت ST دو دسته میکروکنترلر 8 بیتی و 32 بیتی دارد که میکروکنترلرهای 32 بیتی آن مدنظر ما بودند. در ادامه قصد داریم کمی به همین 8 بیتی یا 32 بیتی بودن میکروکنترلرها و اینکه چگونه با STM32 شروع به کار کنیم بپردازیم.

8 بیتی یا 32 بیتی؟

اگر این آموزش را دنبال می‌کنید به احتمال زیاد با مفهوم بیت آشنا هستید و از بابت مفهوم بیت مسئله‌ای نیست. وقتی می‌گوییم پردازنده‌ای n بیتی است یعنی اینکه رجیسترهای آن پردازنده n بیتی هستند. حال شاید سوال کنید که رجیستر چیست؟ رجیستر از کنار هم قرار دادن چندین بیت تشکیل می‌شود. پس وقتی 32 بیت را برای پردازنده‌های ARM به کار می‌بریم یعنی اینکه درون این پردازنده‌ها رجیسترهای 32 بیتی وجود دارند.

خب تا بحث در مورد بیت و رجیستر است اجازه بدهید همین ابتدای کار به یک مفهوم مرتبط با این موضوع نیز اشاره کنیم.

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

به عنوان مثال اگر بیت چهارم و پنجم رجیستر A مقدار 1 منطقی را داشتند یعنی اینکه فلان واحد جانبی مشغول به پردازش دیتای قبلی است و نمی‌توان دیتای جدیدی را به این واحد فرستاد. یا اگر بیت هفتم رجیستر B مقدار 0 منطقی را داشت یعنی اینکه در شمارنده‌ی شما سرریز رخ داده است.

مزایای 8 بیتی یا 32 بیتی

8 بیتی یا 32 بیتی

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

به عنوان مثال یکی از مزایا این است که هرچه تعداد بیت‌های رجیستر بیشتر باشد می‌تواند فضای بیشتری را آدرس‌دهی کند.

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

نحوه‌ی پیکره‌بندی میکروکنترلر

پیکره‌بندی میکروکنترلر

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

اینکه میکروکنترلر برای هدف خاصی تنظیم شود چیزی جز اینکه در رجیسترهای مختلف آن 0 یا 1 منطقی را بنویسیم نیست، به همین سادگی؟

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

پس راه‌حل چیست؟

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

فکر کردید که اگر با روش بالا بخواهید فقط یک LED را خاموش و روشن کنید، چقدر زمان لازم است؟

در خوشبینانه‌ترین حالت اگر دانش زبان C خوبی داشته باشید و معماری و سخت‌افزار را نیز به خوبی بشناسید. در وهله‌ی اول این کار می‌تواند چندین ساعت طول بکشد.

برای خاموش و روشن کردن یک LED چندین ساعت!

بله درست متوجه شدید این کار می‌تواند چندین ساعت طول بکشد. اگر مثل من این راه‌حل را غیرمنطقی می‌دانید با ما همراه باشید تا راه‌حل بهتری را به شما معرفی کنیم.

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

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

خود این راه‌حل به چندین روش مختلف قابل استفاده است که در ادامه هر کدام از این روش‌ها را شرح می‌دهیم.

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

روش‌های پیکره‌بندی میکروکنترلرهای STM32

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

Register

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

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

به عنوان یک مثال ساده، در این روش اگر قرار باشد در یک رجیستر 32 بیتی مقداری را بنویسیم از یک ماکرو استفاده می‌کنیم و فقط یک عبارت مانند عبارت “LL_GPIO_PIN_1” را در رجیستر قرار می‌دهیم. اما اگر قرار بود از راه‌حل اول استفاده بکنیم باید یک عبارت مانند عبارت “11110000111100001111000011110000” یا معادل هگز آن که برابر با “0xF0F0F0F0” است را در رجیستری که آدرسش را هم باید خودمان تنظیم کنیم، بنویسیم.

مثال بالا کوچک‌ترین مزیتی است که این روش نسبت به راه‌حل اول دارد، و با بررسی جزئیات به مزیت‌های بیشتری پی خواهیم برد.

توابع (Low Layer)LL

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

توابع (Hardware Abstraction Layer)HAL

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

وقتی که از یک تابع HAL استفاده می‌کنیم علاوه بر اینکه خودش رجیسترهای یک بخش را تنظیم می‌کند، در اکثر موارد بسیاری از کارهایی که در توابع LL باید خود کاربر انجام می‌داد را نیز انجام می‌دهد.

مثلا اگر قرار بود در توابع LL، از 5 تابع استفاده کنیم و کمی هم توابع زبان C را به کار می‌بردیم تا یک واحد جانبی راه‌اندازی شود، ممکن است تمامی این کارها با یک تابع HAL انجام شود.

توابع (Standard peripheral libraries)SPL

توابع SPL در سطح میانی قرار دارند و می‌توان گفت سطحی بین LL و HAL را دارا هستند. البته این توابع دیگر به‌روزرسانی نمی‌شوند و بهتر است که شما هم از این توابع استفاده نکنید.

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

مقایسه توابع LL با توابع HAL

فرض کنید می‌خواهیم رشته‌ی “Kamin” را بر روی پورت سریال بفرستیم.

در توابع LL پس از اینکه تنظیمات اولیه پورت سریال را انجام دادیم و همچنین آن را فعال کردیم ابتدا باید کارکتر ‘K’ از این رشته را بر روی پورت سریال قرار بدهیم و منتظر بمانیم که آیا ارسال به اتمام رسیده است یا خیر، و اگر ارسال انجام شد کارکتر ‘a’ و سپس تکرار همین روند تا آخرین کارکتر.

اما وقتی با توابع HAL کار می‌کنیم پس از اینکه تنظیمات اولیه را انجام دادیم و پورت را فعال کردیم، تمام رشته‌ی “Kamin” را در ورودی تابع مربوطه قرار می‌دهیم و خود تابع تمامی کارهایی که در توابع LL لازم بود خودمان انجام بدهیم را با زمان‌بندی مناسب برای ما انجام می‌دهد.

توابع HAL به قدری همه چیز را آماده کرده‌اند که اگر به خوبی آن‌ها را بررسی کنید، می‌بینید که در بعضی موارد اگر شما سهوا یا از روی ندانستن اشتباهی انجام داده باشید، آن اشتباه را اگر ممکن باشد و تشخیص بدهد، برایتان تصحیح می‌کند.

اکنون که هر کدام از انواع راه‌حل‌ها، روش‌ها و توابع را با ذکر جزئیات برسی کردیم، وقت آن است که طبق قولی که داده بودیم با ذکر دلایل منطقی یک روش را برای ادامه‌ی راه انتخاب کنیم.

توابع LL

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

به عنوان مثال اگر هدف سرعت برنامه باشد، توابع HAL اصلا توصیه نمی‌شوند و رجیستری بهترین انتخاب است. در نقطه‌ی مقابل اگر هدف سرعت توسعه‌ی پروژه باشد و سرعت برنامه مدنظر نباشد، بهترین انتخاب توابع HAL هستند و رجیستری اصلا توصیه نمی‌شود.

اما هدف ما چیست؟

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

توابع HAL به این دلیل که تنها با فراخوانی یک تابع کنترل کار را به دست می‌گیرند و غالب کار را خودشان انجام می‌دهند و برنامه‌نویس را درگیر با سخت‌افزار و جزئیات برنامه‌نویسی نمی‌کنند برای هدف ما مناسب نیستند.

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

انتخاب ما توابع LL خواهد بود که در ادامه‌ی این مجموعه آموزشی به صورت مفصل با این نوع توابع و نحوه‌ی به کارگیری آن‌ها آشنا خوهیم شد.

توجه داشته باشید اکنون که این مقاله در حال نگارش است، هیچ آموزش فارسی زبانی در ایران برای راه‌اندازی میکروکنترلرهای STM32 با استفاده از توابع LL ارائه نشده است. بر همین اساس تصمیم گرفته شد تا آموزشی کاربردی و مطابق با نیاز، تدوین و به صورت رایگان در اختیار علاقه‌مندان قرار داده شود.

شاید هنوز در انتخاب توابع LL تردید داشته باشید، به همین خاطر قبل از اینکه این قسمت را به پایان برسانیم، می‌خواهیم نتیجه‌ی یک تست عملی بین توابع LL و توابع HAL را ارائه بدهیم. اما چون هنوز با ابزارهای برنامه‌نویسی و پیکره‌بندی آشنا نشدیم فقط نتیجه‌ی تست را ارائه می‌دهیم و توضیحات تکمیلی در قسمت مربوطه ارائه خواهد شد.

به نمودار زیر که سرعت پین میکروکنترلر با استفاده از توابع LL و HAL را نشان می‌دهد دقت کنید:

مقایسه توابع LL و HAL

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

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

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

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

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

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

25 دیدگاه در “آموزش STM32 با توابع LL قسمت دوم: روش‌های پیکره‌بندی و انواع توابع

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

    خیلی خوب و کامل توضیح میدید
    تشکر فراوان

  2. سعید حقیقی پور سعید حقیقی پور گفت:

    سلام فونیکس 🙂
    درجه یک و عالی بود!
    موفق باشی ؛)

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

  3. Shahnazh98d شهناز گفت:

    با سلام‌
    بسیار عالی بود سپاسگزارم

    1. سلام شهناز عزیز. سپاس از نظر مثبت شما.

  4. Rafmehr گفت:

    امکانش هست برای cube ide هم اموزش نصب و راه اندازی قرار بدید؟

    1. به احتمال زیاد یه نگاهی هم به CubeIDE خواهیم داشت، اما تمرکز اصلی بر روی Keil خواهد بود.

  5. Rafmehr گفت:

    پیرو پیام قبلی منظورم لینک دانلود بود یوزر منوال های hal و ll بود اگر ممکنه تو سایت برای دانلود قرار بدید
    با تشکر

    1. قرار داده شد دوست عزیز. هم‌اکنون می‌توانید دانلود بفرمائید.

  6. Rafmehr گفت:

    سلام امکانش هست یوزر منوال توابع llبرای سری f0 و f1 رو قرار بدید؟تو سری های مختلف تفاوت دارن این توابع؟

    1. سلام دوست عزیز. از طریق لینک‌های زیر دانلود بفرمائید.

      سری F1:
      https://www.st.com/resource/en/user_manual/dm00154093-description-of-stm32f1-hal-and-lowlayer-drivers-stmicroelectronics.pdf

      سری F0:
      https://www.st.com/resource/en/user_manual/dm00122015-description-of-stm32f0-hal-and-lowlayer-drivers-stmicroelectronics.pdf

      بله تو هر سری ممکنه امکانات میکروکنترلر متفاوت باشه که متناسب با اون امکانات براش توابع وجود داره.

  7. سلام
    تشکر ویژه از اینکه همت دارید تا این دوره رو کامل ارائه کنید.
    سوالی که داشتم این توابع CMSIS برای همه مدل ها NXP ST ATMEL و برای هر مدلی از اونا وجود داره ؟ و اینکه این توابع در چه سطحی از نظر سرعت اجرا و راحتی پیاده سازی می باشد ؟
    و سوال دیگه اینکه (یه کم عجله دارم 😁😁) فایل ها سورس این توابع LL برای همه میکرو ها هست و اینکه برای STM این فایل ها برای هر میکرو رو از کجا میشه اورد که در پروژه ها همون از اونا استفاده کنیم.
    سوال دیگه هم اینکه شما گفتید در جلسه بعد با cubeMX کار می کند مگ خروجی اون توابع HAL نیست ؟ یعنی میشه ترکیبی کار کرد ؟

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

      در رابطه با سرعت و راحتی پیاده‌سازی هم که در مقاله توضیح دادیم، اگر باز سوالی داشتید بپرسید.

      توابع LL متاسفانه برای همه‌ی میکروها وجود نداره، اگر اشتباه نکنم برا سری F4 وجود نداره (باید یه بررسی بکنم) شما وقتی پک نرم‌افزاری را برای هر سری مثل سری F1 در CubeMX یا هر جای دیگر دانلود می‌کنید، در اون پک نرم‌افزاری مثال‌ها و کدهای مختلفی وجود دارد که می‌تونید از اونا استفاده کنید.

      در مقاله بعد توضیح می‌دهیم، داخل نرم‌افزار CubeMX می‌شه انتخاب کرد که خروجی با چه توابعی ساخته شود.

      1. خیلی ممنون
        من اینو از خود سایت ST دانلود کردم به نظر شما مرجع کاملی برای HAL و LL هست؟
        https://www.st.com/resource/en/user_manual/dm00154093-description-of-stm32f1-hal-and-lowlayer-drivers-stmicroelectronics.pdf

        1. تنها مرجع برای کار با این توابع برای سری F1 فقط همین فایل هستش چیز دیگه‌ای نیست که. نگران نباشید در قسمت‌های آتی هر آن چیزی که برای کار با این میکروکنترلرها نیاز باشه را معرفی می‌کنیم.

  8. Vvv.bagheri VHD گفت:

    سلام
    علی بود
    فقط میشه تفاوت cubeMx و cubeIDE رو بگید چیه؟
    ممنون

    1. درود بر شما دوست عزیز. CubeMX یک سری تنظیمات و پیکره‌بندی اولیه را برای ما انجام می‌دهد و در نهایت از همین تنظیمات و پیکره‌بندی‌های اولیه به ما خروجی می‌دهد. خروجی برای نرم‌افزارهایی مثل Keil، IAR و …

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

  9. ali گفت:

    سلام .
    منتظر قسمت هایی بعدی هستم . چون مرجع اموزش کتابخانه LL حتی به زبان انگلیسی هم کم گیر میاد
    ممنون

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

  10. نوید گفت:

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

  11. نوید گفت:

    سلام و خسته نباشید واقعا عالی دارید پیش میرید…
    فقط اگر امکانش هست کمی هم در مورد توابع cmsis صحبت کنید…
    تشکر فراوان

    1. سلام نوید نازنین. در واقع Cortex Microcontroller Software Interface Standard (CMSIS) همانطوری که از اسمش پیداست یک استاندارد هستش، یک اینترفیس نرم‌افزاری استاندارد برای میکروکنترلرهای سری Cortex که لایه‌ی بالای سخت‌افزار را شامل می‌شود و باعث می‌شه که کدنویسی برای ما راحت‌تر بشه.

      دقت شود که این استاندارد با توابعی مثل HAL یا LL اشتباه گرفته نشود، CMSIS شامل یک سری فایل‌ها مثل درایورها یا راه‌اندازهای پریفرال‌ها یا یک سری فایل برای ارتباط و دسترسی به Core و …

      کاری CMSIS این بود که ما را از سروکله زدن با رجیسترها، آدرس‌ها و کلا لایه‌های سخت‌افزاری که می‌تونه از میکروکنترلری به میکروکنترلر دیگه تغییر کنه راحت کنه. و اطلاق اسم تابع با عملکردی شبیه به توابع HAL یا LL برای CMSIS اشتباه است.

  12. محمد مهدی مرادی mm4hdim گفت:

    سلام

    ممنون که وقت میذارید و این دوره‌ی خیلی خوب رو تهیه می کنید.

    فقط نمی شه آموزش رو با STM32CubeIDE پیش ببرید؟

    ممنون

    1. سلام دوست عزیز. حقیقتا چون جامعه آماری که از نرم‌افزار Keil استفاده می‌کنند بسیار بیشتر است، Keil را انتخاب کردیم. حالا بنا به درخواست‌تان سعی می‌کنیم STM32CubeIDE و حتی شاید IAR را هم در کنارش آموزش بدهیم.