آموزش راه اندازی وب سرور با میکروکنترلر STM32 کنترل دستگاه ها از طریق مرورگر

آموزش راه اندازی وب سرور با میکروکنترلر STM32 ، کنترل دستگاه ها از طریق مرورگر ، چند سال پیش وقتی برای اولین بار خواستم یک رله را از راه دور و فقط با یک مرورگر ساده روشن و خاموش کنم، فکر میکردم کار پیچیدهای در پیش دارم. تصور اولیهام این بود که حتماً باید یک رزبریپای یا حداقل یک ESP32 وسط کار باشد تا بشود اسمش را “وبسرور” گذاشت. اما وقتی کمی عمیقتر رفتم و با پشته LwIP و رجیستر UART و GPIO میکروکنترلرهای STM32 آشنا شدم، فهمیدم که یک تراشه ۳۲ بیتی معمولی، بدون هیچ سیستمعاملی، بهراحتی میتواند درخواست HTTP بگیرد، آن را تفسیر کند و در جواب، یک وضعیت واقعی از دنیای فیزیکی را تغییر بدهد. همین تجربه باعث شد این موضوع را به یکی از پروژههای ثابت کارگاههای آموزشیام تبدیل کنم، چون بهترین راه برای فهمیدن شبکه، سختافزار و برنامهنویسی embedded در کنار هم است.
در این مقاله قصد دارم دقیقاً همان مسیری را طی کنم که یک نفر واقعاً روی میز کارش طی میکند: از انتخاب سختافزار درست گرفته تا تنظیم CubeMX، پیکربندی LwIP، نوشتن صفحه HTML، و در نهایت کنترل یک پین GPIO از طریق مرورگر گوشی یا لپتاپ. اگر دنبال آموزش وبسرور STM32 یا کنترل رله و LED با STM32 از طریق شبکه میگردید، این مقاله را تا انتها بخوانید چون سعی کردهام نکاتی که در تجربه واقعی گیر میکنند را هم پوشش بدهم، نه فقط تئوری خشک.
چرا اصلاً STM32 برای وبسرور؟
سؤال منطقی این است: وقتی ESP32 با وایفای داخلی و کتابخانههای آماده وجود دارد، چرا باید سراغ STM32 برویم که خودش هیچ رادیوی بیسیمی ندارد؟
جواب من بعد از سالها کار با هر دو خانواده این است: STM32 برای پروژههایی که به قطعیت زمانی (Real-Time)، پردازش سیگنال دقیق، یا رابطهای صنعتی مثل CAN و RS-485 نیاز دارند، انتخاب بهمراتب پایدارتری است. وقتی یک دستگاه صنعتی دارید که باید هم سنسورهای آنالوگ را با نمونهبرداری دقیق بخواند، هم یک موتور را با PWM کنترل کند و هم گزارش وضعیت را روی یک صفحه وب نمایش بدهد، ترکیب STM32 با یک ماژول اترنت مثل W5500 یا حتی یک ماژول وایفای سریال مثل ESP8266 در حالت AT Command انتخاب پایدارتری نسبت به تکتراشههای همهکاره است. علاوه بر این، خانواده STM32 طیف قیمتی و توان پردازشی بسیار گستردهای دارد؛ از تراشههای چند سِنتی سری F0 تا STM32H7 که هستهای با کارایی نزدیک به پردازندههای موبایل قدیمی دارد.
نکته دیگری که کمتر کسی به آن اشاره میکند این است که چون STم32 معمولاً بدون سیستمعامل کامل (یا با یک RTOS سبک مثل FreeRTOS) کار میکند، مصرف حافظه و توان مصرفی وبسرور شما قابل پیشبینی و کنترل است؛ چیزی که در پروژههای تجاری و صنعتی اهمیت زیادی دارد.
چیزهایی که واقعاً به آنها نیاز دارید
قبل از باز کردن STM32CubeIDE، بهتر است چکلیست سختافزاری و نرمافزاری را کامل کنید تا وسط کار مجبور نشوید دنبال قطعه یا درایور بگردید.
سختافزار پیشنهادی:
- یک بورد STM32 که پورت اترنت داخلی دارد (مثل STM32F407 روی برخی بردهای Discovery، یا خانواده STM32F7/H7) یا در صورت نبود اترنت داخلی، یک ماژول W5500 که از طریق SPI به میکروکنترلر وصل میشود.
- کابل شبکه (RJ45) و دسترسی به یک روتر یا سوییچ برای تست در همان شبکه محلی.
- یک LED یا رله برای اینکه نتیجه کار را ملموس ببینید؛ صرفاً دیدن یک صفحه HTML کافی نیست، باید چیزی روشن و خاموش شود تا حس موفقیت کامل شود.
- پروگرامر ST-Link (معمولاً روی بردهای Nucleo و Discovery داخلی است).
نرمافزار:
- STM32CubeIDE (شامل CubeMX برای پیکربندی گرافیکی پایهها و پریفرالها)
- کتابخانه LwIP که بهصورت پیشفرض در میانافزارهای STM32CubeMX در دسترس است.
اگر بورد شما اترنت داخلی ندارد، نگران نباشید؛ ماژولهای W5500 چون خودشان پشته TCP/IP سختافزاری دارند، حتی روی تراشههای ضعیفتر هم عملکرد قابلقبولی میدهند و از طرفی بار پردازشی کمتری روی هسته اصلی میگذارند.
گام اول: پیکربندی پروژه در CubeMX
اولین کاری که باید انجام بدهید، ساخت یک پروژه جدید در STM32CubeIDE و انتخاب بورد یا میکروکنترلر مورد نظرتان است. بعد از آن:
- در تب Pinout & Configuration، اگر از اترنت داخلی استفاده میکنید، وارد بخش Connectivity → ETH شوید و حالت RMII را فعال کنید (اکثر بردهای مدرن STM32 از RMII پشتیبانی میکنند چون تعداد پین کمتری مصرف میکند نسبت به MII).
- از بخش Middleware and Software Packs، گزینه LWIP را فعال کنید.
- در تنظیمات LwIP، بسته به نیاز پروژه میتوانید از DHCP برای گرفتن IP خودکار استفاده کنید یا یک Static IP ثابت تعریف کنید. برای پروژههای صنعتی که آدرس IP باید همیشه ثابت و قابل پیشبینی باشد، من همیشه Static IP را ترجیح میدهم.
- یک پین GPIO خروجی هم برای LED یا رلهای که میخواهید کنترل کنید تنظیم نمایید.
بعد از این مرحله، کد پایه (Generate Code) را بسازید تا ساختار پروژه با تمام فایلهای Middleware مربوط به LwIP آماده شود.
نکته تجربهمحور: یکی از رایجترین مشکلاتی که کاربران تازهکار با آن دستوپنجه نرم میکنند این است که پینگ به بورد جواب میدهد ولی صفحه وب باز نمیشود. در اکثر این موارد، مشکل از عدم فعال بودن گزینه
LWIP_HTTPDدر تنظیمات میانافزار است. حتماً از منوی Middleware → LWIP → HTTPD مطمئن شوید که سرویس HTTP سرور فعال است.
گام دوم: فعالسازی و پیکربندی HTTPD در LwIP
LwIP یک ماژول آماده به اسم httpd دارد که وظیفه پاسخدهی به درخواستهای HTTP را بر عهده میگیرد. این ماژول از یک فایلسیستم مجازی به نام fsdata استفاده میکند که در واقع محتوای صفحات HTML شما را بهصورت آرایهای از بایتها در حافظه فلش ذخیره میکند.
برای فعال کردن آن باید در فایل lwipopts.h مقدار زیر را تنظیم کنید:
#define LWIP_HTTPD_CGI 1
#define LWIP_HTTPD_SSI 1
#define HTTPD_USE_CUSTOM_FSDATA 0
سپس با استفاده از ابزار makefsdata (که همراه پروژههای نمونه LwIP ارائه میشود)، پوشهای شامل فایلهای HTML، CSS و جاوااسکریپت خود را به یک فایل C تبدیل میکنید که همان fsdata.c نام دارد. این فایل بعداً به پروژه اضافه میشود تا صفحات شما در حافظه فلش تراشه ذخیره شوند.
در تابع main، کافی است سرویس HTTP سرور را با یک خط کد راهاندازی کنید:
httpd_init();
از این به بعد، هر بار که مرورگر یک درخواست GET یا POST به سمت آدرس IP بورد بفرستد، این ماژول آن را میگیرد و صفحه HTML مربوطه را پس میفرستد.
گام سوم: طراحی صفحه HTML کنترل دستگاه
صفحه وب نیازی به پیچیدگی ندارد؛ در واقع سادگی در این پروژهها یک مزیت است چون حافظه فلش میکروکنترلر محدود است. یک نمونه ساده از صفحهای که دو دکمه برای روشن و خاموش کردن LED دارد به این شکل است:
<!DOCTYPE html>
<html>
<head><title>کنترل STM32</title></head>
<body style="text-align:center; font-family:sans-serif;">
<h2>پنل کنترل دستگاه</h2>
<a href="/led_on"><button style="padding:15px;">روشن کردن LED</button></a>
<a href="/led_off"><button style="padding:15px;">خاموش کردن LED</button></a>
</body>
</html>
نکته کلیدی اینجاست که هر دکمه در واقع کاربر را به یک URI مشخص هدایت میکند (مثل /led_on). اینجاست که مکانیزم CGI وارد بازی میشود.
گام چهارم: اتصال دکمهها به سختافزار با CGI
CGI یا Common Gateway Interface روشی است که به شما اجازه میدهد وقتی مرورگر درخواستی به یک آدرس مشخص میفرستد، یک تابع C در فریمور شما اجرا شود. به این ترتیب میتوانید مستقیماً پین GPIO را تغییر دهید.
نمونهای ساده از پیادهسازی این مکانیزم:
const char *cgi_led_on(int index, int numParams, char *pcParam[], char *pcValue[])
{
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);
return "/index.html";
}
const char *cgi_led_off(int index, int numParams, char *pcParam[], char *pcValue[])
{
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);
return "/index.html";
}
static const tCGI cgi_handlers[] = {
{"/led_on", cgi_led_on},
{"/led_off", cgi_led_off}
};
http_set_cgi_handlers(cgi_handlers, 2);
با این تنظیم، هر بار که کاربر روی دکمه “روشن کردن LED” کلیک کند، مرورگر درخواست /led_on را ارسال میکند، تابع مربوطه در STM32 اجرا میشود، پین GPIO تغییر حالت میدهد و در نهایت کاربر دوباره به صفحه اصلی هدایت میشود. این چرخه ساده اما بسیار قدرتمند است و اساس بسیاری از سیستمهای کنترل صنعتی مبتنی بر وب را تشکیل میدهد.
بهروزرسانی زنده صفحه با SSI
اگر بخواهید صفحه وب شما وضعیت لحظهای یک سنسور (مثل دما یا وضعیت رله) را نمایش دهد، بدون اینکه کاربر مجبور باشد صفحه را رفرش کند، باید سراغ SSI (Server Side Include) بروید. با SSI میتوانید در HTML خود تگهایی مانند <!--#temp--> بگذارید و در کد C مقدار واقعی را جایگزین کنید:
static const char *ssi_tags[] = {"temp"};
u16_t ssi_handler(int index, char *insert, int insertLen)
{
int len = 0;
if (index == 0) {
len = snprintf(insert, insertLen, "%.1f", read_temperature());
}
return len;
}
http_set_ssi_handler(ssi_handler, ssi_tags, 1);
ترکیب CGI برای دریافت فرمان از کاربر و SSI برای نمایش وضعیت لحظهای، دقیقاً همان الگویی است که در بسیاری از داشبوردهای صنعتی ساده استفاده میشود، پیش از آنکه پروژه به سمت راهحلهای سنگینتری مثل AJAX یا WebSocket برود.
آیا باید سراغ AJAX هم بروم؟
اگر پروژه شما نیاز به بهروزرسانی مداوم و بدون رفرش کامل صفحه دارد (مثلاً نمایش نمودار زنده یک سنسور)، استفاده از AJAX روی همین زیرساخت HTTP سرور LwIP هم امکانپذیر است. در این حالت جاوااسکریپت سمت مرورگر بهصورت دورهای یک درخواست کوچک به STM32 میفرستد (مثلاً /get_temp)، و کد فریمور فقط یک رشته متنی یا JSON کوچک برمیگرداند. این روش سبکتر از رفرش کامل صفحه است و تجربه کاربری روانتری میدهد، هرچند پیادهسازی آن کمی پیچیدهتر از CGI ساده است.
تست کردن وبسرور
بعد از فلش کردن برنامه روی بورد:
- کابل شبکه را به بورد و روتر وصل کنید و مطمئن شوید LED وضعیت اترنت روشن میشود.
- با دستور
pingدر ترمینال، آدرس IP بورد را تست کنید تا از اتصال شبکه مطمئن شوید. - آدرس IP را در مرورگر هر دستگاهی که در همان شبکه محلی است (لپتاپ، موبایل و …) وارد کنید.
- باید صفحه HTML طراحیشده را ببینید و با کلیک روی دکمهها، LED یا رله متصل به بورد باید بلافاصله واکنش نشان دهد.
اگر صفحه باز نمیشود ولی پینگ جواب میدهد، معمولاً مشکل از یکی از این موارد است: عدم فعال بودن httpd_init()، تنظیم نادرست فایل fsdata.c، یا فراموش کردن فراخوانی تابع MX_LWIP_Process در حلقه اصلی برنامه (در پروژههای بدون RTOS).
چند نکته که کمتر جایی نوشته میشود
در طول سالها کار با این پروژهها به چند نکته رسیدم که معمولاً در آموزشهای رسمی به آنها اشاره نمیشود:
- حافظه فلش محدود است. اگر بخواهید صفحات HTML پیچیده با کلی CSS و جاوااسکریپت بسازید، خیلی سریع به سقف حافظه بردهای ورودی مثل F1 یا F4 میرسید. برای صفحات سبک، از CSS Inline استفاده کنید و از فایلهای خارجی صرفنظر کنید.
- زمانبندی وظایف در حالت بدون RTOS اهمیت دارد. اگر در حلقه اصلی برنامه یک تأخیر طولانی (مثل
HAL_Delayبزرگ) بگذارید، پردازش بستههای شبکه معطل میماند و مرورگر با خطای Timeout مواجه میشود. ترجیحاً برای پروژههای واقعی از FreeRTOS استفاده کنید تا وظیفه شبکه از بقیه کارها مستقل باشد. - امنیت را دستکم نگیرید. این نمونهها هیچ لایه احراز هویتی ندارند؛ یعنی هر کسی در همان شبکه محلی میتواند به دستگاه شما فرمان بدهد. برای پروژههای واقعی حتماً حداقل یک مکانیزم ساده مثل رمز عبور در فرم ورودی یا محدودسازی دسترسی در سطح روتر اضافه کنید.
- اترنت پایدارتر از وایفای است. اگر پروژه شما در محیط صنعتی با نویز الکترومغناطیسی بالا قرار دارد، اتصال سیمی مثل W5500 معمولاً پایدارتر از هر راهحل بیسیمی است.
سوالات متداول
بله، با اتصال یک ماژول وایفای سریال مثل ESP8266 در حالت AT Command از طریق UART میتوان همین قابلیت را پیادهسازی کرد، هرچند پیچیدگی پردازش دستورات AT و مدیریت بافر سریال بیشتر از استفاده مستقیم از LwIP روی اترنت است.
معمولاً دلیل اصلی، حجم بالای فایل HTML یا تصاویر است. سعی کنید صفحات را تا حد امکان سبک نگه دارید و از تصاویر SVG کوچک بهجای فایلهای بزرگ استفاده کنید.
بله، اما هرچه تعداد سوکتهای همزمان بیشتر شود، باید حافظه RAM اختصاصیافته به LwIP (بهخصوص pbuf و tcp pcb) را افزایش دهید که این تنظیمات از طریق lwipopts.h قابل کنترل هستند.
بله، LwIP از پیادهسازی WebSocket هم پشتیبانی میکند، اما پیچیدگی و حجم کد بیشتری نسبت به HTTP سنتی دارد و بیشتر برای پروژههایی مناسب است که نیاز به ارتباط دوطرفه و بلادرنگ دارند.
جمعبندی
راهاندازی یک وبسرور روی STM32 در نگاه اول ممکن است ترسناک به نظر برسد، اما وقتی مراحل را قدم به قدم پیش بروید، متوجه میشوید که ترکیب CubeMX، LwIP و چند خط کد ساده کافی است تا یک میکروکنترلر معمولی به یک دستگاه قابل کنترل از راه دور تبدیل شود. این پروژه نهتنها یک تمرین آموزشی خوب برای یادگیری شبکه و embedded است، بلکه پایه بسیاری از سیستمهای صنعتی واقعی محسوب میشود که امروز در کارخانهها و خانههای هوشمند استفاده میشوند.
اگر این مقاله برایتان مفید بود، پیشنهاد میکنم در گام بعدی به سراغ افزودن HTTPS یا پیادهسازی MQTT روی STM32 بروید تا امنیت و مقیاسپذیری پروژه خود را ارتقا دهید. خوشحال میشوم تجربهها و مشکلاتی که در مسیر پیادهسازی این پروژه با آن مواجه شدید را در قسمت نظرات به اشتراک بگذارید.
اگر این مقاله آموزش راه اندازی وب سرور با میکروکنترلر STM32 ، کنترل دستگاه ها از طریق مرورگر برای شما مفید بود، آن را با دوستان خود به اشتراک بگذارید و برای مشاهده آموزشهای بیشتر به سایت ما سر بزنید.
مطلب پیشنهادی
آموزش پروتکل MQTT با میکروکنترلر STM32 برای پروژه های IoT
دیدگاههای محترمانه: لطفاً نظرات خود را با رعایت احترام به دیگران و به صورت محترمانه ارسال کنید. از بهکار بردن زبان توهینآمیز، تهدیدآمیز یا نژادپرستانه خودداری کنید.
حفظ حریم خصوصی: از درج اطلاعات شخصی خود یا دیگران مانند شماره تماس، آدرس و هرگونه اطلاعات حساس خودداری کنید.
محتوای تبلیغاتی: ارسال دیدگاههای تبلیغاتی، لینکهای خارجی یا هر نوع محتوای تجاری که مرتبط با موضوع نباشد، ممنوع است.
موافقت با قوانین: با ارسال دیدگاه خود، شما تأیید میکنید که قوانین فوق را خوانده و با آنها موافقید. تیم ما حق دارد نظرات غیرمجاز را حذف کند.
پروژه های پیشنهادی
پروژه ریموت کنترل کدلرن حرفه ای
مشاهده پروژهپروژه امپلی فایر صوتی استریو با TDA2030
مشاهده پروژهپروژه قفل دیجیتال با ماژول RFID RC522
مشاهده پروژه