برنامه نویسی, توصیه شده, متفرقه, مقاله های سیسوگ

برنامه نویسی میکروکنترلر را به صورت حرفه ای بیاموزیم

آموزش برنامه نویسی حرفه ای میکروکنترلر

برنامه نویسی حرفه ای تاثیر خیلی زیادی در راندمان سخت افزار دارد،  قبلا در مقاله ای تحت عنوان “میکروکنترلر مقصر نیست مقصر برنامه نویسی است” بررسی کردیم که چقدر برنامه نویسی می تواند تاثیر بسزایی در راندامان و بازدهی سخت افزار داشته باشد، با روشن شدن این مساله مهم ، نکته ای که باید به آن توجه داشت ، بهبود سطح برنامه نویسی است. یکی از مسائلی که به شخصه فکر می کنم نقطه ضعف طراح های الکترونیک و البته برنامه نویس های سیستم های نهفته (embedded systems) است عدم تسلط کافی به مقوله برنامه نویسی است؛ برای بررسی بیشتر این مساله با سیسوگ همراه باشید.

اهمیت برنامه نویسی برای مهندسین الکترونیک

امروزه بیشتر مدارات الکترونیکی از میکروکنترلرها و پردازنده ها استفاده می کنند که نیازمند برنامه نویسی برای عملکرد دلخواه هستند، مقوله ای که در دانشگاه ها به آن پرداخته نمی شود آموزش صحیح برنامه نویسی برای مهندسین الکترونیک است ، مهندسین الکترونیک دید خوبی نسبت به سخت افزار و عملگرد آن دارند اما آیا واقعا فکر می کنید گذراندن یک درس دو واحدی “برنامه نویسی” برای یاد گرفتن مهارت برنامه نویسی کافی است ؟

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

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

چالش برنامه نویسی این پست

امروزه که میکروکنترلر های ARM رواج پیدا کرده‌اند باعث تغییرات شگرفی در طراحی سخت افزار شده است ، پردازنده 32 بیتی که مقدار RAM و FLASH قابلی توجهی دارد و سرعت بالایی را کنار توان مصرفی کم ارائه می کند ، شما ممکن است به یاد نداشته باشید که طراحی میکروکنترلری با استفاده از Z80 یا 8086 چقدر دشوار و پیچیده بود از طرفی برنامه نویسی به زبان اسمبلی برای محاسبات ریاضی بر روی اعداد 32 بیتی یک کابوس تمام عیار بود و یا محاسبات اعشاری و ممیز شناور کار هر کسی نبود اما امروزه به لطف تکنولوژی تمام این کابوس های تلخ تبدیل به یک رویای شیرین شده است. با این همه، تکنولوژی نمی تواند برخی مسائل را حل کند ، برنامه نویسی نیز یکی از این مسائل است. برای چالش این پست فرض می کنیم که یک متغیر 32 بیتی داریم!(با توجه به وجود میکروکنترلرهای 32 بیتی ARM) و قصد داریم تعداد بیت های 1 را در این متغییر شمارش کنیم. برای روشن شدن مساله به جدول زیر توجه کنید

در واقع ما نیازی به برنامه ای داریم که اگر عدد 0xA0000500 را در ورودی دریافت کرد ، عدد 4 را در خروجی نمایش دهد. ممکن است نوشتن چنین برنامه ای کار ساده ای باشد ولی روش های مختلفی که می شود این برنامه را نوشت بررسی کنیم.

برنامه ای که همه می نویسند

قطعا ساده ترین برنامه ای که میشه نوشت برنامه بالاست ولی برنامه بالا خیلی کند عمل خواهد کرد؛ شاید برای برنامه نویس کامپیوتر که قراره برنامه بر روی یک پردازنده چند گیگاهرتزی چند هسته ای اجرا بشه ؛ شاید زیاد اهمیت نداشته باشه این مساله ولی برای اجرا روی یک پردازنده Cortex-m که فرکانس چند مگاهرتزی داره مساله بازدهی خیلی مهمه !

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

اما چرا میگیم این برنامه به لحاظ پرفومنسی بهینه نیست اولین مساله وجود حلقه است (که ظاهرا اجنتاب ناپذیره) دوم محاسباتی که توی حلقه انجام میشه همونطور که می بینید عملیات مقایسه ای داریم ، شیفت بیتی داریم عملیات منطقی(AND) و جمع داریم یعنی برای هر بار اجرای حلقه کلی محاسبه نیازه که انجام بشه ! اما چطور میشه برنامه رو بهینه کرد ؟ با مطالعه پست “میکروکنترلر مقصر نیست مقصر برنامه نویسی است” میتونید ایده بگیرد.

برنامه ای که بعد از فکر کردن می نویسید

برنامه فوق باز بهتر از برنامه قبلی شد ، چراکه یک عملیات شیفت بیتی و یک عملیات مقایسه ای رو حذف کردیم ؛ در واقع عملیات شیفت و مقایسه رو به داخل حلقه منتقل کردیم به این صورت که مقایسه با خود حلقه انجام بشه و کل متغییر به سمت چپ درون عملگر حلقه شیفت پیدا کنه ، با این صرفه جویی ها راندمان برنامه بهتر شد ولی هنوز اون مطلوبی که باید باشه نیست ؛ آیا هنوز ایده ای برای بهتر شدن برنامه دارید ؟

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

این جایی است که دید سخت افزاری و آشنایی با سخت افزار به کمک شما می آید و برنامه رو بهتر میکنه ! همونطور که می بینید حلقه که به قوت خودش باقی است ولی عملیات شیفت و And منطقی حذف شده که باعث افزیش سرعت میشه ! اما واقعا در برنامه چه اتفاقی می افته ؟ چطور سخت افزار به کمک ما میآد ؟

سری میکروکنترلر های Cortex-m قابلیتی دارند تحت عنوان Bit-Banding ؛ این قابلیت به میکروکنترلر اجازه میده که به صورت بیتی به حافظه SRAM دسترسی داشته باشد ، یعنی یک بیت از RAM رو بخونیم یا بنویسیم! از اونجایی که خانواده Cortex-m مخصوص میکروکنترلر ها توسعه پیدا کرده ، این قابلیت که کمک فراوانی به سادگی برنامه نویسی میکنه بهش اضافه شده ، اما این کار چطور ممکنه ؟ برای درک بهتر به تصور زیر دقت کنید.

قابلیت بیت بند مورد استفاده در برنامه نویسی

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

برنامه ای که حرفه ای ها می نویسند

تا اینجا چند روش ساده رو بررسی کردم و تا جای ممکن اون روش رو با دانش برنامه نویسی و دید سخت افزاری بهینه کردیم ، اما آیا فکر می کنید باز هم میشه بهتر این برنامه رو نوشت ؟ قطعا جواب مثبت هست اما چطور ؟ برای دید بهتر به برنامه زیر دقت کنید

بله در برنامه فوق حلقه For حذف شده است و به جای آن از جدول استفاده کرده ایم ، این کار باعث افزایش چشم گیر سرعت اجرای برنامه خواهد شد ، در واقع جدول BitsSetTable256 شامل تعداد بیت های یک اعداد 0 تا 255 هست یعنی یک بایت.

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

چالش انتهایی

خوب به سادگی برنامه فوق هم میشه این کار رو انجام داد!اما این برنامه دقیقا چطور کار میکنه ؟

این روشی نیست که همه بخوان ازش استفاده کنند؛ نوشتنش که هیچ ، حتی درک این که چطور این برنامه کار میکنه هم کار هر کسی نیست !

آیا کسی میتونه بگه چطور این برنامه کار میکنه ؟

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

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

18 دیدگاه در “برنامه نویسی میکروکنترلر را به صورت حرفه ای بیاموزیم

  1. Avatar for کدرلایف کدرلایف گفت:

    ممنون از این مقاله کاربردی

  2. Avatar for mhsh mhsh گفت:

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

    1. Avatar for Zeus Zeus گفت:

      قطعا جدول سریعتره – چون فقط به اندازه یک دسترسی به حافظه زمان میبره 🙂

  3. Avatar for امیرحسین روزیطلب امیرحسین روزیطلب گفت:

    احساس پوچی کردم ای بابا :)))

    1. Avatar for Zeus Zeus گفت:

      چرا احساس پوچی دوست عزیز !‌
      تا وقتی میشه چیزای جدید یاد گرفت، جای بسیار زیادی برای امیدواری هست

  4. Avatar for امیرحسین اریا امیرحسین اریا گفت:

    سلام. ممنون از سایت خوبتون. یه سوال داشتم. من برنامه نویسی avr كار كردم و از سخت افزار هم تا حدودی سر در میارم. سال بعد دانشكاه میرم. خواستم ببینم arm یاد بگیرم بهاره یا ای وی ار رو ادامه بدم. و این كه شركت های بزرك مثلا تسلا یا اسپیس ایكس و… كه پیچیده ترین كد نویسی ها رو برای سخت افزار انجام میدن از چه تراشه هایی استفاده میكنن؟ آیا تراشه های arm به اندازه كافی قدرت دارن؟ اكر كسی بخواد برنامه نویسی در اون حد بیشرفته رو یاد بگیره باید چیكار كنه؟

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

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

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

      بله متشکر

    2. Avatar for shm shm گفت:

      مطالب لینکی که بالا دادم فوق العادست برای همین Counting bits set اومده ۷ روش روگفته
      کلی چالش دیگه هم داره
      —سوال —-
      منبع کامل آموزش دقیق C با رویکرد embedded چیزی معرفی می کنید؟ مثلا همین volatile رو خیلی جاها توضیح نداده

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

        چالش های دیگه اش هم جالبه 🙂
        — جواب —
        نه متاسفانه ؛ فکر نمیکنم زبان سی فرقی بین امبدد و خیر امبدد داشته باشه ؛ شناخت از سیستم های امبدد هست که کمک میکنه برنامه شما خاص اون سخت افزار باشه یا نباشه

    3. Avatar for زئوس Zeus زئوس Zeus گفت:

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

  5. Avatar for محمد محمد گفت:

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

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

      سلام دوست گرامی
      تمام مطالبی که ترجمه هستند یا از منبعی بازنشر شده باشند دارای منبع هستند ِ به عنوان نمونه تمام آموزش های STM8 یا آموزش ها و رفرنس Arduino و… همه دارای منبع هستند ِ اگر میبینید مطلبی دارای منبع نیست ِ‌یعنی از اول نوشته شده توسط نویسنده نه این که از جایی کپی شده باشد که نیاز به ذکر منبع داشته باشد
      فکر میکنم همه سایت رو ندیدید !!!

  6. Avatar for علی علی گفت:

    (unsigned char *) &data; این یعنی چی

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

      سلام ؛
      &data در واقع آدرس حافظه ای که متغییر data توی اون ذخیره شده رو بر میگردونه ؛ خوب حالا این حافظه از چه نوعی هست ؟ خوب معلومه دیگه static const unsigned char ؛ وقتی بخوایم اونو تو یه اشاره‌گر از نوع unsigned char بریزیم کامپایلر خطا میده ! برای این که با این خطا مواجه نشیم با این شکل نوشتاری ((unsigned char *) &data;) به کامپایلر میگیم داداش تو فکر کن متغییر ما از نوع unsigned char* هستش 🙂

  7. Avatar for حسین حسین گفت:

    با سلام و خسته نباشید .
    اون کدی که با چند خط دیفاین جول رو تولید میکنه داره از توابع بازگشتی استفاده میکنه و این خطB6(0), B6(1), B6(1), B6(2) درواقع کل جدول رو تولید میکنه .به این صورت کهB2(n) مربوط به اعداد 2بیتی است .و B2(0) میشه 0,1,1,2
    اگر برای اعداد 3 بیتی هم بخواهیم محاسبه کنیم 0,1,1,2,1,2,2,3 اگر کمی دقت کنیم دنباله مربوط به 3 بیتی میشهB2(0),B2(1) یا به طور کلی B3(n)=B2(n),B2(n+1)
    به طور خلاصه هر بار که یک بیت به طول عدد اضافه میشه دنباله جدید عبارت است از دنباله مربوط به حالت قبلی که جملاتش 1 واحد اضافه شده و در ادامه دنباله قبلی اومده . به طور مثال برای 4 بیت میشه B3(0),B3(1) که اگر به جای b3 معادل اون بر اساس b2 رو بنویسیم میشه
    B2(0),B2(1),B2(1),B2(2) که در حالت کلی B4(n)=B2(n),B2(n+1),B2(n+1),B2(n+2) که همون فرمول جدول هست منتها برای صرفه جویی حالتهای B3(n) و B5 و B7 حذف شدن . و فرمولها مستقیم بر اساس 2 مرحله قبل نوشته شدن .

    ولی کد آخری فهمیدنش واقعا مشکل هست!!!

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

      بسیار عالی ^_^ ؛ بله همیطوره که میگید
      در مورد تابع آخر وقتی بیتی خودتون تجزیه تحلیلش کنید خیلی راحت تر میشه درکش 🙂
      برای منم اولش سخت بود و بی معنی

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

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