مشروع تطبيقي: تصميم وبناء وحدة مراقبة صناعية من PCB إلى البرنامج
نظرة عامة: وحدة مراقبة صناعية كاملة
في هذا الدرس الختامي، نبني مشروعاً يجمع كل ما تعلمناه: وحدة مراقبة صناعية تقرأ مستشعرات متعددة، تتواصل عبر Modbus RTU مع نظام SCADA، وترسل البيانات للسحابة عبر WiFi/MQTT.
مواصفات المشروع
- قراءة 4 مستشعرات تناظرية (حرارة، تيار، ضغط، اهتزاز)
- قراءة 4 مدخلات رقمية (حساسات قرب، نهايات مشوار)
- التحكم بـ 4 مخرجات رقمية (مرحلات لمحركات وصمامات)
- اتصال Modbus RTU كـ Slave عبر RS-485
- إرسال بيانات عبر MQTT للمراقبة عن بعد
- شاشة OLED محلية لعرض الحالة
اختيار المتحكم
نستخدم STM32F407 كمتحكم رئيسي (قراءة مستشعرات + Modbus) مع ESP32 كوحدة اتصال WiFi/MQTT. الفصل بينهما يزيد الموثوقية: حتى لو فشل WiFi، يستمر التحكم المحلي.
تصميم المخطط الإلكتروني: STM32 + مستشعرات + Modbus
دائرة التغذية
- مدخل 24V DC صناعي (الجهد القياسي في المصانع)
- منظم DC-DC يحوّل إلى 5V (لتغذية المرحلات والحساسات)
- منظم LDO يحوّل 5V إلى 3.3V (لتغذية المتحكم)
- مكثفات فلترة على كل منظم (100uF + 100nF)
- حماية من عكس القطبية بديود أو MOSFET
دائرة المدخلات التناظرية
مستشعر 4-20mA ──── مقاومة 165Ω ──── ADC Pin
│
مكثف 100nF
│
GND
مقاومة 165 أوم تحوّل تيار 4-20mA إلى جهد 0.66-3.3V المناسب لـ ADC. المكثف يرشح التشويش عالي التردد.
دائرة RS-485
STM32 UART TX ──── MAX485 DI
STM32 UART RX ──── MAX485 RO
STM32 GPIO ──── MAX485 DE/RE (التحكم بالاتجاه)
MAX485 A/B ──── خط RS-485 الصناعي
تصميم لوحة PCB في KiCad
قواعد تصميم اللوحات الصناعية
- عرض المسارات: 0.5mm كحد أدنى لإشارات المنطق، 1mm+ لمسارات القدرة
- مستوى أرضي: طبقة أرضي كاملة تحت طبقة الإشارات لتقليل التشويش
- فصل التناظري والرقمي: مسارات ADC بعيدة عن مسارات PWM والاتصالات
- حماية ESD: ديودات TVS على جميع الموصلات الخارجية
- نقاط تثبيت: 4 ثقوب M3 في الزوايا للتثبيت في علبة DIN Rail
ملفات الإخراج
- Gerber: لتصنيع اللوحة
- BOM (قائمة المكونات): بتنسيق CSV لطلب القطع
- Pick-and-Place: لماكينة التجميع الآلي
كتابة البرنامج الثابت: قراءة ADC و UART و Modbus RTU
هيكل البرنامج
// main.c - الهيكل العام للبرنامج
#include "FreeRTOS.h"
#include "task.h"
// سجلات Modbus
#define MODBUS_ADDR 1
volatile uint16_t holding_regs[32]; // سجلات القراءة/الكتابة
volatile uint16_t input_regs[32]; // سجلات القراءة فقط
void sensor_task(void *p) {
(void)p;
MovingAverage filters[4];
for (int i = 0; i < 4; i++) filter_init(&filters[i]);
while (1) {
for (int ch = 0; ch < 4; ch++) {
uint16_t raw = filter_update(&filters[ch], read_adc_channel(ch));
input_regs[ch] = raw;
}
// تحويل القيم الخام لوحدات هندسية
input_regs[10] = (uint16_t)(ntc_to_celsius(input_regs[0]) * 10);
input_regs[11] = (uint16_t)(raw_to_current(input_regs[1]) * 100);
input_regs[12] = (uint16_t)(raw_to_pressure(input_regs[2]) * 10);
input_regs[13] = (uint16_t)(raw_to_vibration(input_regs[3]) * 10);
vTaskDelay(pdMS_TO_TICKS(50));
}
}
معالجة Modbus RTU
#define MODBUS_BUF_SIZE 256
void modbus_task(void *p) {
(void)p;
uint8_t rx_buf[MODBUS_BUF_SIZE];
while (1) {
int len = uart_receive_frame(rx_buf, MODBUS_BUF_SIZE, 50);
if (len < 4) continue;
if (rx_buf[0] != MODBUS_ADDR) continue;
if (!modbus_check_crc(rx_buf, len)) continue;
uint8_t tx_buf[MODBUS_BUF_SIZE];
int tx_len = 0;
switch (rx_buf[1]) {
case 0x03: // Read Holding Registers
tx_len = modbus_handle_read(rx_buf, tx_buf,
holding_regs, 32);
break;
case 0x04: // Read Input Registers
tx_len = modbus_handle_read(rx_buf, tx_buf,
input_regs, 32);
break;
case 0x06: // Write Single Register
tx_len = modbus_handle_write_single(rx_buf, tx_buf,
holding_regs, 32);
break;
}
if (tx_len > 0) {
rs485_set_tx_mode();
uart_send(tx_buf, tx_len);
rs485_set_rx_mode();
}
}
}
حساب CRC-16 لـ Modbus
uint16_t modbus_crc16(const uint8_t *data, uint16_t len) {
uint16_t crc = 0xFFFF;
for (uint16_t i = 0; i < len; i++) {
crc ^= data[i];
for (uint8_t j = 0; j < 8; j++) {
if (crc & 0x0001)
crc = (crc >> 1) ^ 0xA001;
else
crc >>= 1;
}
}
return crc;
}
الاختبار والمعايرة
اختبار المستشعرات
// دالة معايرة: قراءتان معروفتان لحساب المعادلة الخطية
typedef struct {
float slope;
float offset;
} Calibration;
Calibration calibrate_linear(float raw1, float eng1,
float raw2, float eng2) {
Calibration cal;
cal.slope = (eng2 - eng1) / (raw2 - raw1);
cal.offset = eng1 - cal.slope * raw1;
return cal;
}
float apply_calibration(Calibration *cal, float raw) {
return cal->slope * raw + cal->offset;
}
اختبار Modbus
استخدم برنامج Modbus Poll أو QModMaster على الحاسوب للتحقق من:
- القراءة الصحيحة لسجلات Input Registers
- الكتابة والقراءة لسجلات Holding Registers
- الاستجابة الصحيحة للعناوين والدوال
- التعامل مع الإطارات الخاطئة
اختبار التحمل
- تشغيل الوحدة 72 ساعة متواصلة ومراقبة استقرار القراءات
- اختبار انقطاع وعودة التغذية (Power Cycling)
- اختبار أسوأ حالة حرارية (60 درجة مئوية)
من النموذج الأولي إلى الإنتاج
خطوات التصنيع
- مراجعة التصميم: مراجعة المخطط و PCB مع مهندس آخر
- طلب نماذج PCB: من مصنع مثل JLCPCB أو PCBWay
- تجميع يدوي: لحام المكونات والاختبار الأولي
- اختبار وظيفي: تشغيل جميع الاختبارات البرمجية
- تصميم العلبة: علبة DIN Rail بلاستيكية أو معدنية
- التجميع الآلي: عند الإنتاج بكميات (PCBA)
شهادات ومعايير
- CE: إلزامي للبيع في أوروبا
- IEC 61131-2: معيار أجهزة التحكم المبرمجة
- EMC: اختبار التوافق الكهرومغناطيسي
مثال Rust: هيكل برنامج مدمج آمن
#![no_std]
#![no_main]
use cortex_m_rt::entry;
use stm32f4xx_hal::{pac, prelude::*, adc::Adc};
#[entry]
fn main() -> ! {
let dp = pac::Peripherals::take().unwrap();
let rcc = dp.RCC.constrain();
let clocks = rcc.cfgr.sysclk(168.MHz()).freeze();
let gpioa = dp.GPIOA.split();
let adc_pin = gpioa.pa0.into_analog();
let mut adc = Adc::adc1(dp.ADC1, true, Default::default());
loop {
let raw: u16 = adc.read(&adc_pin).unwrap();
let voltage = (raw as f32 / 4095.0) * 3.3;
// معالجة القراءة...
cortex_m::asm::delay(8_000_000);
}
}
الخلاصة والخطوات القادمة
في هذه السلسلة، تعلمنا أساسيات الأنظمة المدمجة من GPIO البسيط وحتى بناء وحدة مراقبة صناعية كاملة مع Modbus و MQTT. المفاهيم الأساسية التي غطيناها:
- معمارية المتحكمات الدقيقة وأنواع الذاكرة
- التعامل مع المدخلات والمخرجات الرقمية والتناظرية
- بروتوكولات الاتصال UART و SPI و I2C
- المؤقتات و PWM والتحكم PID
- المقاطعات و FreeRTOS لتعدد المهام
- ESP32 و WiFi و MQTT لإنترنت الأشياء الصناعي
- تصميم وبناء نظام صناعي متكامل
للتعمق أكثر
- Modbus TCP/IP: ربط وحدات المراقبة بشبكة Ethernet الصناعية
- OTA Updates: تحديث البرنامج الثابت عن بعد
- TinyML: تشغيل نماذج ذكاء اصطناعي على المتحكم للصيانة التنبؤية
- Rust المدمج: بناء أنظمة آمنة من أخطاء الذاكرة باستخدام embedded-hal
- تصميم PCB متقدم: لوحات متعددة الطبقات مع تحكم بالمعاوقة