Recipe-driven coffee roasting system with closed-loop temperature control and automated fan management — built on STM32F4.
- Features
- System Overview
- System Architecture
- Picture Demo
- Board Information
- Pin Mapping
- Recipe Profile
- Temperature Decode
- Fan Control
- Getting Started
- Toolchain Setup
- Known Issues / Future Work
- Closed-loop temperature control via Modbus RTU to an external PID controller
- 18-step roast profile — each step defines target temperature and hold time
- Automated PWM fan control across all system states (STANDBY → WARMUP → ROASTING → COOLING → COMPLETE)
- Thermal fail-safe — fan stays on at 70% in FAULT state
- RS-485 / MAX485 communication with no external Modbus libraries
- UART debug output at 115200 baud via ST-Link Virtual COM Port
The STM32 communicates with an external PID temperature controller over Modbus RTU (RS-485 / MAX485). An 18-step roast profile is stored on-device — each step defines a target temperature and hold time. The system automatically advances through steps when both time and temperature conditions are met, controls a PWM fan across all states, and defaults to fan-on in FAULT for thermal safety.
Left: Roasted beans | Center: Controls | Right: Heating pre-test with PID controller
| Property | Value |
|---|---|
| Board | NUCLEO-F4xx |
| MCU | STM32F4xx, ARM Cortex-M4 |
| Clock | 84 MHz (HSI PLL) |
| Flash / RAM | 512 KB Flash / 128 KB RAM |
| Power Source | USB 5V → onboard 3.3V regulator |
| Logic Voltage | 3.3V |
| Peripheral | MCU Pin | Function / Connection | Notes |
|---|---|---|---|
| USART1 TX | PA9 | Modbus RTU TX → MAX485 | 9600 baud, 8N1 |
| USART1 RX | PA10 | Modbus RTU RX ← MAX485 | Reads tempPV from PID |
| USART2 TX | PA2 | Debug UART TX | 115200 baud |
| USART2 RX | PA3 | Debug UART RX | |
| TIM3 CH1 | PA6 | PWM fan output | 0–999 CCR1 = 0–100% duty |
| TIM10 | — | 1s tick timer | Drives recipe step timing |
| LD2 (LED) | PA5 | GPIO Output | Status indicator |
| B1 (Button) | PC13 | GPIO Input (falling edge) |
The roast profile is defined as an 18-step lookup table steps_lookup[18][4]:
| Step | Status | Hold Time (s) | Target Temp (°C) |
|---|---|---|---|
| 0 | STANDBY | 30 | 0 |
| 1 | WARMUP | 31 | 20 |
| 2 | WARMUP | 33 | 30 |
| 3 | WARMUP | 60 | 40 |
| 4 | WARMUP | 120 | 50 |
| 5 | WARMUP | 90 | 60 |
| 6 | WARMUP | 180 | 70 |
| 7 | WARMUP | 130 | 80 |
| 8 | WARMUP | 184 | 90 |
| 9 | WARMUP | 98 | 100 |
| 10 | WARMUP | 220 | 110 |
| 11 | WARMUP | 60 | 120 |
| 12 | WARMUP | 180 | 130 |
| 13 | WARMUP | 90 | 140 |
| 14 | WARMUP | 90 | 150 |
| 15 | ROASTING | 180 | 160 |
| 16 | COOLING | 60 | 20 |
| 17 | COMPLETE | 60 | 20 |
⚠️ A 2°C hysteresis offset (TEMP_OFFSET) is applied when checking step advancement to compensate for slow PID thermal response.
The PID controller returns temperature over Modbus as a raw 2-byte hex value. Decoded manually with no external libraries — each byte is split into high and low nibbles, each nibble is weighted (×4096, ×256, ×16, ×1), summed and divided by 10 to produce degrees Celsius.
PWM duty cycle is linearised as 0–100% mapped to CCR1 values 0–999 (TIM3 period = 999):
| State | CCR1 | Duty |
|---|---|---|
| STANDBY | 0 | 0% |
| WARMUP | 999 | 100% |
| ROASTING | 999 | 100% |
| COOLING | 700 | 70% |
| COMPLETE | 0 | 0% |
| STOP | 0 | 0% |
| FAULT | 700 | 70% |
🔒 FAULT state keeps the fan running as a thermal fail-safe.
- STM32CubeIDE installed
arm-none-eabi-gcctoolchain- NUCLEO-F4xx board
- ST-Link V2 (on-board)
# Clone the repo
git clone https://github.com/gitFrank77/Coffee-Roaster.git
# Open in STM32CubeIDE
# File → Import → Existing Projects into Workspace
# Build: Project → Build All (Ctrl+B)
# Flash: Run → Debug (F11)Connect via ST-Link Virtual COM Port at 115200 baud to see runtime state and temperature readings.
| Interface | Details |
|---|---|
| Power Input | USB 5V |
| Programmer | ST-Link V2 (on-board NUCLEO) |
| Debug UART | USART2 @ 115200 baud, Virtual COM Port |
| Component | Version / Tool |
|---|---|
| Compiler | arm-none-eabi-gcc |
| IDE | STM32CubeIDE |
| HAL | STM32F4xx HAL |
| Protocol | Modbus RTU over RS-485 |
| Jumper | Setting |
|---|---|
| BOOT0 | 0 — Normal boot from Flash |
| JP1 | Closed — 5V via USB |
-
timer_restartflag not yet toggled by TIM10 IRQ callback — step timing reset needs wiring up - Recipe profiles are hardcoded — future: load from external storage (SD card / EEPROM)
- Set up proper enclosure
- Use modbus lib for RTU communication between PID controller and MCU.
This project is licensed under the MIT License.



