Home Wiki Electricity & Electrons Capstone Project: Designing and Building an Industrial Monitor From PCB to Firmware
Electricity & Electrons

Capstone Project: Designing and Building an Industrial Monitor From PCB to Firmware

Overview: A Complete Industrial Monitoring Unit

This final lesson builds a standalone industrial monitoring unit that reads analog sensors, communicates over Modbus RTU, and reports data to a supervisory system. The specifications:

  • MCU: STM32F407 (Cortex-M4, 168 MHz, 1 MB Flash, 192 KB SRAM)
  • Sensors: 2x NTC thermistors (bearing temp), 1x ACS712 (motor current), 1x vibration sensor
  • Communication: Modbus RTU over RS-485 (slave device)
  • Power: 24V DC industrial supply with onboard 3.3V regulator

The device acts as a Modbus slave polled by a PLC or SCADA system using standard function codes — compatible with existing factory infrastructure without WiFi or cloud dependency.

Schematic Design: STM32 + Sensors + Modbus

The schematic splits into functional blocks: an LM2596 step-down converter (24V to 5V) and AMS1117-3.3 regulator for power; the STM32F407 with 8 MHz crystal and decoupling capacitors; sensor inputs with TVS diode protection and RC low-pass filters; and a MAX485 RS-485 transceiver for Modbus.

STM32 USART1_TX  -->  MAX485 DI
STM32 USART1_RX  <--  MAX485 RO
STM32 PA8 (GPIO) -->  MAX485 DE + RE (direction control)

Each analog input has ESD protection and a 1K + 100 nF RC filter (cutoff ~1.6 kHz). Voltage dividers scale any sensor output exceeding 3.3V. The RS-485 bus uses 120 ohm termination resistors at both ends to prevent signal reflections on long cable runs.

PCB Design in KiCad

KiCad is the industry-standard open-source PCB tool. Key design rules: separate analog and digital ground planes joined at one point near the ADC; keep analog traces away from switching power supply; use ground pours on both layers; place decoupling caps close to MCU power pins.

Board specs: 80 x 60 mm (DIN rail enclosure), 2-layer, 0.25 mm signal traces, 0.5 mm power traces, screw terminals for field wiring. DFM considerations include single-side SMD placement, fiducial markers, test points on critical signals, and mounting holes matching the enclosure.

Writing the Firmware: ADC, UART, and Modbus RTU

The firmware uses a super loop with timer-driven sampling and interrupt-driven Modbus communication. The ADC runs in DMA scan mode, reading all four channels continuously in the background.

#define NUM_ADC_CHANNELS  4
#define MODBUS_SLAVE_ADDR 0x01

static uint16_t adc_raw[NUM_ADC_CHANNELS];
static MovingAverage filters[NUM_ADC_CHANNELS];

typedef struct {
    float bearing_temp_1, bearing_temp_2;
    float motor_current, vibration_rms;
} SensorReadings;

SensorReadings process_sensors(void) {
    SensorReadings r;
    r.bearing_temp_1 = ntc_to_celsius(ma_update(&filters[0], adc_raw[0]));
    r.bearing_temp_2 = ntc_to_celsius(ma_update(&filters[1], adc_raw[1]));
    r.motor_current  = acs712_to_amps(ma_update(&filters[2], adc_raw[2]));
    r.vibration_rms  = adc_to_vibration(ma_update(&filters[3], adc_raw[3]));
    return r;
}

// Modbus holding registers mapped to sensor values (fixed-point)
static uint16_t holding_registers[10];

void update_registers(SensorReadings *r) {
    holding_registers[0] = (uint16_t)(r->bearing_temp_1 * 10.0f);
    holding_registers[1] = (uint16_t)(r->bearing_temp_2 * 10.0f);
    holding_registers[2] = (uint16_t)(r->motor_current * 100.0f);
    holding_registers[3] = (uint16_t)(r->vibration_rms * 100.0f);
}

void modbus_process_frame(uint8_t *frame, uint16_t len) {
    if (frame[0] != MODBUS_SLAVE_ADDR) return;
    if (!modbus_check_crc(frame, len)) return;

    if (frame[1] == 0x03) {  // Read Holding Registers
        uint16_t start = (frame[2] << 8) | frame[3];
        uint16_t count = (frame[4] << 8) | frame[5];
        modbus_send_registers(start, count);
    }
}

// Main application loop
int main(void) {
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_DMA_Init();
    MX_ADC1_Init();
    MX_USART1_UART_Init();  // RS-485 Modbus at 9600 baud

    HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_raw, NUM_ADC_CHANNELS);
    for (int i = 0; i < NUM_ADC_CHANNELS; i++) ma_init(&filters[i]);

    while (1) {
        SensorReadings readings = process_sensors();
        update_registers(&readings);
        HAL_Delay(50);  // 20 Hz update rate
    }
}

Testing and Calibration

Test each subsystem independently before connecting to real equipment:

  1. ADC verification: Apply known voltages with a precision source and compare readings against expected values. Record offset and gain errors.
  2. Modbus validation: Use a PC Modbus master (QModMaster) to poll the device, verify register mapping, and confirm CRC calculations.
  3. Stress testing: Run continuously for 48 hours at 85 degrees Celsius, monitoring for data drift or firmware lockups.

Each analog channel needs two-point calibration stored in EEPROM so values survive firmware updates:

typedef struct { float offset, gain; } Calibration;

float apply_calibration(float raw, Calibration *cal) {
    return raw * cal->gain + cal->offset;
}

From Prototype to Production

Moving from prototype to manufactured product requires several steps:

  • BOM optimization: Replace through-hole with SMD, source from multiple suppliers, choose automotive-grade components for harsh environments
  • Certification: CE marking (EMC directive EN 61000-6-2/6-4), UL listing (UL 61010-1), IP65 minimum enclosure rating
  • Manufacturing flow: PCB fabrication, SMT pick-and-place assembly, firmware flashing via SWD production jig, automated functional testing of all channels, DIN rail enclosure assembly with laser-etched labels

Summary and Next Steps

This project demonstrated the full lifecycle of an industrial embedded product: schematic design, PCB layout, firmware with ADC and Modbus, testing, calibration, and production. The monitoring unit reads four sensors, applies filtering, and serves data as Modbus registers to any standard industrial controller.

To continue beyond this series: study CAN bus and EtherCAT for high-speed networking, learn FOC motor control algorithms, explore IEC 61508 functional safety standards, investigate Rust embedded with the embassy async framework, and build edge computing nodes combining ESP32 wireless with STM32 real-time control. The combination of firmware skills with industrial domain knowledge is what separates hobbyist projects from production equipment that runs factories.

project STM32 PCB-design Modbus firmware industrial-monitor مشروع تطبيقي تصميم اللوحة البرنامج الثابت المراقبة الصناعية موديس المتحكم