Go في الأنظمة المدمجة: كتابة البرامج الثابتة بلغة لا تفجر المكدس

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

Go والأجهزة: لماذا ليست مزحة؟

\n

عندما تسمع عبارة "تطوير الأنظمة المدمجة"، عادة ما تتخيل لغة C، ولغة التجميع، وتصحيح الأخطاء المؤلم عبر مصباح LED. لكن العالم لا يقف ساكنًا. اليوم، Go (أو Golang) تطرق باب عالم المتحكمات الدقيقة بثقة متزايدة. وهي لا تطرق عبثًا، بل مع goroutines، وجامع القمامة، والواجهات المدمجة.

\n

في هذه المقالة، سنفهم كيف يبدو تطوير الأنظمة المدمجة باستخدام Go، وسنكتب كودًا حقيقيًا لمتحكم دقيق افتراضي، وسنعرف ما إذا كان الأمر يستحق العناء. تلميح: نعم، إذا كنت قد سئمت من تسرب الذاكرة وتحب الكود القابل للقراءة.

\n\n

لماذا Go وليس C؟ ثلاثة أركان

\n

الأنظمة المدمجة التقليدية هي C. لكن Go تمتلك ثلاث ميزات قاتلة تجعل المهندسين يعيدون النظر في عاداتهم:

\n
    \n
  • أمان الذاكرة: لا مؤشرات جامحة يمكن أن تطير إلى الفضاء. مترجم Go أكثر صرامة من مترجم C.
  • \n
  • Goroutines: خيوط خفيفة الوزن تتناسب تمامًا مع البنية الموجهة بالأحداث للمتحكمات الدقيقة.
  • \n
  • التوافق عبر المنصات: تكتب الكود على Mac، وتجمعه لـ ARM Cortex-M. بدون طقوس معقدة.
  • \n
\n

بالطبع، هناك فارق بسيط: Go الأصلي (gc) لا يمكنه التجميع لوحدات MCU الصغيرة. لكن هناك مشروع TinyGo — مترجم يكيّف Go للأجهزة ذات الكيلوبايتات من الذاكرة. عليه سنركز.

\n\n

إعداد البيئة: TinyGo ولوحتك

\n

قبل كتابة الكود، دعنا نجهز مساحة العمل. لـ تطوير الأنظمة المدمجة باستخدام Go ستحتاج:

\n
    \n
  1. تثبيت TinyGo: brew install tinygo (أو التحميل من الموقع الرسمي).
  2. \n
  3. تثبيت سلسلة الأدوات للوحتك (مثل ARM GCC لـ STM32).
  4. \n
  5. توصيل اللوحة عبر USB.
  6. \n
\n

نتحقق من أن كل شيء يعمل:

\n
tinygo version\ntinygo: 0.31.0 (linux/amd64)\n
\n

الآن يمكنك تجميع الكود لأي لوحة مدعومة: tinygo build -target=arduino-nano -o firmware.hex main.go.

\n\n

أول وميض: LED على Go

\n

كلاسيكيات المجال. نتصل بالدبوس، نحرك القدم. هكذا يبدو برمجة المتحكمات الدقيقة باستخدام Go:

\n
package main\n\nimport (\n    "machine"\n    "time"\n)\n\nfunc main() {\n    // LED المدمج عادة على الدبوس 13 (أو LED_BUILTIN)\n    led := machine.LED\n    led.Configure(machine.PinConfig{Mode: machine.PinOutput})\n\n    for {\n        led.High()\n        time.Sleep(500 * time.Millisecond)\n        led.Low()\n        time.Sleep(500 * time.Millisecond)\n    }\n}\n
\n

نجمعه ونحمله على اللوحة:

\n
tinygo flash -target=arduino-nano -port=/dev/ttyUSB0 main.go\n
\n

ها هي ذا! الـ LED يومض. لاحظ: نستخدم حزمة machine — وهي طبقة تجريد الأجهزة في TinyGo. تخفي وراءها العمل مع السجلات، لكنها تعطي واجهة Go نظيفة.

\n\n

العمل مع GPIO والمقاطعات

\n

في المشاريع الحقيقية، مجرد الوميض لا يكفي. تحتاج لقراءة الأزرار، وأجهزة الاستشعار، والاستجابة للأحداث. في Go للأنظمة المضمنة، تُنفذ المقاطعات عبر القنوات و goroutines. مثال: نعلق معالجًا لضغطة زر.

\n
package main\n\nimport (\n    "machine"\n    "fmt"\n)\n\nfunc main() {\n    button := machine.D2\n    button.Configure(machine.PinConfig{Mode: machine.PinInputPullup})\n\n    // ننتظر الضغط (pin == LOW، بسبب السحب إلى مصدر الطاقة)\n    for {\n        if !button.Get() {\n            fmt.Println("تم الضغط على الزر!")\n        }\n    }\n}\n
\n

لكن هذه حلقة انتظار مشغولة. تريد كفاءة أعلى؟ استخدم مقاطعة عبر قناة:

\n
func main() {\n    button := machine.D2\n    button.Configure(machine.PinConfig{Mode: machine.PinInputPullup})\n\n    // قناة للأحداث\n    ch := make(chan bool, 1)\n    button.SetInterrupt(machine.PinFalling,                

المدونات

توصيات الكتب