Conveyor with PWM Speed and Item Counting

Published Jul 01, 2026
 168 hours to build
 Beginner

The system consists of two microcontroller boards, an Arduino Pro Mini and an STM8S103F3P6, each operating independently while complementing one another. The Arduino Pro Mini is responsible for controlling the conveyor motor, including its speed and rotation direction. Meanwhile, the STM8S103F3P6 functions as an automatic item-counting module, displaying the counting results locally on an I2C LCD.

display image

Components Used

STM8S103F3P6
Development Board
1
ST-Link/V2
Programmer Tools
1
FTDI USB
Serial Communication Tools
1
LDR Sensor Module (Light Intensity)
Sensor
1
KY-008: Laser Transmitter Module 5V
Sensor
1
LCD I2C
Display
1
Mini USB cable - USB type A
USB Cable for FTDI
1
Push button 12 x 12 mm
Switch
3
PCB Dot Matrix Single Layer 10cm x 22cm
Circuit Board
1
Arduino Pro Mini
Development Board
1
PL2303 USB
Programmer Tools
1
Gear Motor / Motor DC
Actuators
1
L298N
Motor Driver
1
Potentiometer
Variable Resistor
1
PVC Sheets 3 mm 10 x 50 cm
Chassis
5
Stainless Steel Concrete 30 cm
Shaft
1
EELIC PBB-KFL06P (6 mm)
Bearing Pillow Block
3
1/2 Inch Pipe 25 cm
Roller component
1
Oscar fabric 50 x 137 cm
Conveyor Belt
1
Wood stickers
Accessory
2
PVC Electrical insulation
Accessory
3
Sandpaper G-180 1 m
Roller Covering Material
1
Smart Car Rims
Drive Wheel
1
L Bracket
Conveyor Bracket
24
Hexagonal Spacer Female to Female M3 x 12
Mounting hardware
4
Hexagonal Spacer Female to Male M3 x 20
Mounting hardware
4
Bolts M3 x 8
Mounting hardware
8
Bolts M3 x 20
Mounting hardware
12
Bolts M3 x 30
Mounting hardware
2
Bolts M5 x 25
Mounting hardware
8
Bolts M5 x 20
Mounting hardware
32
Nuts M3
Mounting hardware
14
Nuts M5
Mounting hardware
40
Jumper Female to Female 30 cm
Cable
10
Jumper Female to Male 30 cm
Cable
2
Jumper Female to Male 20 cm
Cable
6
Jumper Female to Male 10 cm
Cable
2
Jumper Male to Male 20 cm
Cable
8
Jumper Male to Male 30 cm
Cable
2
Micro USB cable - 2 pin JST
Cable
1
Socket female jack DC
Socket
1
Header Pin Female Single Row 1x40
Socket
2
Header Pin Male Double Row 2x40
Socket
2
Header Pin Female Double Row 2x40
Socket
2
Adaptor DC 12V 2A
Power Supply
1
Adaptor DC 5V 2A
Power Supply
1
Description

Conveyor with PWM Speed and Item Counting

Helping Small Businesses Improve Production Efficiency

 

Many micro, small, and medium-sized enterprises (MSMEs) still rely on manual methods to transport and count products during production and packaging. As production volume increases, these repetitive tasks become more time-consuming, labor-intensive, and susceptible to human error, reducing operational efficiency and inventory accuracy.

Although industrial conveyor systems with automated counting capabilities are widely available, their cost and implementation complexity often make them inaccessible to educational institutions and small businesses.

As a solution, this project implements a low-cost automated conveyor system that helps improve production efficiency by automating the item counting process while remaining simple, affordable, and easy to build. The prototype demonstrates how practical automation can improve counting accuracy, reduce human error, and support small-scale manufacturing as well as educational applications.

 

What Makes This Conveyor Project Different?

Rather than functioning as a simple miniature conveyor, this prototype incorporates several automation features commonly found in industrial conveyor systems. Operators can manually adjust the conveyor speed using PWM control, change its direction, and rely on an integrated laser–LDR sensing system to count every passing item automatically.

The counting result is displayed instantly on a 16×2 LCD, eliminating repetitive manual counting and helping reduce human error. When a counting session is complete, the counter can be cleared to zero with a dedicated reset button, allowing the system to be reused immediately.

By integrating motor control, object detection, and real-time counting into a single prototype, this project demonstrates that practical industrial automation does not always require expensive equipment. It provides an affordable, easy-to-replicate platform for students, makers, and MSMEs to explore production automation and embedded control systems.

 

Why It Matters

  • Improves Productivity – Automates repetitive item counting during production.
  • Reduces Human Error – Minimizes mistakes caused by manual counting.
  • Affordable Automation – Demonstrates industrial automation using low-cost and widely available components.
  • Educational Platform – Helps students and makers understand motor control, sensors, and embedded systems through hands-on implementation.
  • Scalable Concept – The prototype can be expanded with IoT monitoring, quality inspection, barcode scanning, or sorting mechanisms for more advanced industrial applications.

 

Device Wiring

● Arduino Pro Mini (Motor Speed Control) :

 

● STM8S103F3P6 (Items Counting) :

 

Step 1 : Download & Install Arduino IDE

  1. Please click the following link to download the Arduino IDE : 

    https://bit.ly/ArduinoIDE_Installer

     

  2. Select Legacy IDE (1.8.19).

     

  3. Please select the OS (Operating System) ➜ Click Download.

     

  4. Open the Downloads folder ➜ Select arduino-1.8.19-windows ➜ Right-click ➜ Select Run as administrator.

     

  5. Arduino Setup: License Agreement ➜ Click I Agree.

     

  6. Arduino Setup: Installation Options ➜ Click Next.

     

  7. Arduino Setup: Installation Folder ➜ Click Install.

     

  8. Please wait for the installation to complete.

     

  9. Once the installation is complete ➜ Click Close.

 

Step 2 : Arduino IDE Configuration

  1. Open the Application (.EXE) :

    Arduino IDE

     

  2. Select FilePreferences.

     

  3. In addition to the Arduino board, you must manually fill in the Additional Board Manager URLs field in the Arduino IDE, as shown in the example below :

    https://raw.githubusercontent.com/tenbaht/sduino/master/package_sduino_stm8_index.json

     

     

  4. Select ToolsBoard ➜ Click Boards Manager.

     

  5. Make sure the Arduino AVR board is already installed. If not, you must install it.

     

  6. Then type stm8 ➜ Select Sduino STM8 plain C core (non-C++) by Michael Mayer ➜ Click Install.

     

  7. Wait until the installation is complete ➜ Click Close.

 

Step 3 : Download & Install PL2303 USB Driver

  1. Please click the following link to download the PL2303 USB Driver : 

    https://bit.ly/PL2303P_USBdriver

     

  2. Select PL2303 Prolific DriverInstaller.zip ➜ Click Download.

     

  3. Open the Downloads folder ➜ Right-click ➜ Select Extract Here.

     

  4. Open the folder containing the extracted files ➜ Select PL2303-Prolific_DriverInstaller_v1200 ➜ Right-click ➜ Select Run as administrator.

     

  5. To begin the installation ➜ click Next.

     

  6. Wait until the installation is complete ➜ Click Finish.

 

Step 4 : Download & Install ST-Link USB Driver

  1. Please click the following link to download the ST-Link USB Driver :

    https://bit.ly/STLink_USBdriver

     

  2. Select en.stsw-link009.zip ➜ Click Download.

     

  3. Open the Downloads folder ➜ Right-click ➜ Select Extract Here.

     

  4. Open the folder containing the extracted files ➜ Select dpinst_amd64 ➜ Right-click ➜ Select Run as administrator.

     

  5. To begin the installation ➜ click Next.

     

  6. Wait until the installation is complete ➜ Click Finish.

     

Step 5 : Download & Install FTDI USB Driver

  1. Please click the following link to download the FTDI USB Driver :

    https://bit.ly/CDM_FTDI_USBdriver

     

  2. Select CDM212364_Setup.zip ➜ Click Download.

     

  3. Open the Downloads folder ➜ Right-click ➜ Select Extract Here.

     

  4. Open the folder containing the extracted files ➜ Select CDM212364_Setup ➜ Right-click ➜ Select Run as administrator.

     

  5. To begin the installation ➜ click ExtractNext.

     

  6. License Agreement ➜ Make sure you have selected the option: I accept this agreement. Then click Next.

     

  7. Wait until the installation is complete ➜ Click Finish.

     

Step 6 : Wiring ST-Link/V2 to the STM8S103F3P6

 

Notes :

  1. The single wire interface module or SWIM is basically used to communicate with the STM8 board.

     

  2. You can see the wiring between the ST-Link/V2 and the STM8S103F3P6 board in detail in the picture above.

     

  3. Based on personal experience, the STM8 can only be programmed with ST-Link.

 

Step 7 : Removing write protection on STM8S103F3P6

The write protection on the STM8S103F3P6 board can be removed through several steps, among others :

 

  1. Connect the STM8S103F3P6 board to the ST-Link/V2, then connect the ST-Link/V2 to a PC or laptop.

     

  2. Open CMD (Command Prompt).

     

  3. Enter into the directory :

    C:\Users\[Computer Name]\AppData\Local\Arduino15\packages\sduino\tools\STM8Tools\2019.02.05\win

     

  4. Input the command :

    stm8flash -cstlinkv2 -pstm8s103?3 -u

     

  5. Press Enter, then you can see the result as the picture below.

 

Step 8 : STM8 (Sduino) I2C Address Scanner

/*
  =====================================================
  I2C Scanner for STM8S103F3P6
  by: Devan Cakra Mudra Wijaya, S.Kom.
  =====================================================

  Functions:
  - Detects all connected I2C devices
  - Displays device addresses in HEX format
  - Displays the total number of detected devices


  =====================================================
  SDA and SCL Pins for STM8S103F3P6
  =====================================================
  SDA -> PB5
  SCL -> PB4
*/

// Include the I2C library for I2C communication
#include "I2C.h"

// Constant that defines the delay between scans (5000 ms = 5 seconds)
const uint16_t SCAN_INTERVAL = 5000;


// The setup() function runs once when the board is powered on or reset
// It is used to initialize hardware, serial communication, sensors, modules, and the program's initial configuration
void setup() {

  // Start Serial communication at 9600 baud rate
  Serial_begin(9600);

  // Wait for 5 seconds before starting the program
  delay(5000);

  // Display program header
  Serial_println_s("====================================");
  Serial_println_s("         I2C DEVICE SCANNER         ");
  Serial_println_s("by: Devan Cakra Mudra Wijaya, S.Kom.");
  Serial_println_s("====================================");

  // Print an empty line
  Serial_println_s("");

  // Initialize I2C communication
  I2C_begin();
}


// The loop() function runs continuously after setup() has finished
// The main program logic is typically placed inside this function
void loop() {

  // Variable to store the error code returned from I2C communication
  uint8_t error;

  // Variable to store the I2C address currently being checked
  uint8_t address;

  // Counter variable for the number of detected devices
  uint8_t deviceCount = 0;

  // Display information indicating that the scan process has started
  Serial_println_s("------------------------------------");
  Serial_println_s("Scanning I2C bus...");
  Serial_println_s("------------------------------------");

  // Loop through addresses from 1 to 126
  // Valid I2C addresses range from 0x01 to 0x7E
  for (address = 1; address < 127; address++) {

    // Perform I2C write transaction (STM8 I2C driver)
    // Used to test ACK response from device
    // Error code depends on I2C driver implementation
    error = I2C_write(address, 0x00);

    // If no error occurs:
    if (error == 0) {

      // Display information that a device was found
      Serial_print_s("[FOUND] Device at address 0x");

      // If the address is less than 16:
      // Add a leading zero to keep HEX formatting aligned
      if (address < 16) {
        Serial_print_s("0");
      }

      // Display the address in HEX format
      Serial_print_ub(address, HEX);
      Serial_println_s("");

      // Increment the detected device count
      deviceCount++;
    }

    // If an unknown error occurs:
    else if (error == 4) {

      // Display an error message
      Serial_print_s("[ERROR] Unknown error at address 0x");

      // If the address is less than 16:
      // Add a leading zero to keep HEX formatting aligned
      if (address < 16) {
        Serial_print_s("0");
      }

      // Display the problematic address in HEX format
      Serial_print_ub(address, HEX);
      Serial_println_s("");
    }

    // If the error is neither 0 nor 4:
    // Ignore it, as this usually means no device exists at that address
  }

  // Print an empty line
  Serial_println_s("");

  // If no devices were found:
  if (deviceCount == 0) {

    // Display a message indicating that no devices were found
    Serial_println_s("No I2C devices found.");
  }
  else { // If at least one device was found:

    // Display the total number of detected devices
    Serial_print_s("Total devices found: ");

    // Display the value of deviceCount
    Serial_print_ub(deviceCount, DEC);
    Serial_println_s("");
  }

  // Display information about the next scan
  Serial_print_s("Next scan in ");

  // Convert milliseconds to seconds
  Serial_print_ub(SCAN_INTERVAL / 1000, DEC);

  // Display the unit in seconds
  Serial_println_s(" seconds.");

  // Empty line
  Serial_println_s("\n");

  // Wait 5 seconds before performing the next scan
  delay(SCAN_INTERVAL);
}

 

Step 9 : Items Counting (auto_counter.ino)

// library initialization for controlling the 16x2 I2C LCD module
#include <LiquidCrystal_I2C.h>

// global variable initialization
#define ldrPin PD2       // PD2 pin to LDR sensor
#define laserPin PD3     // PD3 pin to laser module
#define pbPin PD4        // PD4 pin to push button
#define LCD_ADDR 0x27    // I2C address of the LCD module

int counter = 0;         // initialize the item counter into integer data type
int currentState = 0;    // initialize the current state of the LDR sensor
int previousState = 0;   // initialize the previous state of the LDR sensor
int ldr = 0;             // initialize the digital reading of the LDR sensor
bool pushbutton = false; // initialize the status of the push button into boolean data type

LiquidCrystal_I2C(lcd, 0x27, 16, 2); // initialize the 16x2 I2C LCD module

// Method: setup
void setup() {
  Serial_begin(9600);    // initialize serial communication at 9600 baud rate
  device_init();         // calling the device initialization method
}

// Method: loop
void loop() {
  sensor();              // calling the sensor method
  reset();               // calling the reset method
  display();             // calling the display method
}

// Method: device_init
void device_init() {
  pinMode(pbPin,INPUT);           // PD4 pin is used as an input
  pinMode(ldrPin,INPUT);          // PD2 pin is used as an input
  pinMode(laserPin,OUTPUT);       // PD3 pin is used as an output
  digitalWrite(laserPin,HIGH);    // turn on the laser module
  lcd_begin();                    // initialize the LCD module
  lcd_backlight();                // enable the LCD backlight
}

// Method: sensor
void sensor() { 
  ldr = digitalRead(ldrPin);      // digital readout of the LDR sensor
  if (ldr == LOW) {               // if the laser beam is detected then:
    currentState = 0;             // set the current sensor state to LOW
  }
  if (ldr == HIGH) {              // if the laser beam is interrupted then:
    currentState = 1;             // set the current sensor state to HIGH
  }  
  Serial_print_s("\nTotal items\t: "); // display the item count label on the serial monitor
  if (currentState == 1 && currentState != previousState) { // if a new object is detected then:
    counter = counter + 1;        // increment the item counter
    Serial_print_i(counter-1);    // display the current item count
  }
  else { // if no new object is detected then:
    Serial_print_i(counter-1);    // display the previous item count
  }
  delay(1000);                    // delay -> 1 second
}

// Method: reset
void reset() {
  pushbutton = digitalRead(pbPin); // digital readout of the push button
  if (previousState != 0 && pushbutton == HIGH) { // if the reset button is pressed then:
    counter = 1;                  // reset the counter value
    pushbutton == true;           // keep the push button status
  }
}

// Method: display
void display() {
  lcd_setCursor(2, 0);            // set the cursor position on the first row
  lcd_print_s("Total items:");    // display the title on the LCD
  lcd_setCursor(7, 1);            // set the cursor position on the second row
  lcd_print_i(counter);           // display the current item count
}

 

Step 10 : Upload Firmware to the STM8S103F3P6

  1. Open the Arduino IDE first, then open this project by clicking File -> Open :

    auto_counter.ino

     

  2. Board Setup in Arduino IDE

    Click Tools -> Board -> STM8S Boards -> STM8S103F3 Breakout Board

     

  3. Change Programmer in Arduino IDE

    Click Tools -> Programmer -> ST-Link/V2

     

  4. Before uploading the program please click: Verify.

     

  5. If there is no error in the program code, the next step is to use the STM8 programming tool according to the procedure. Then click: Upload.

     

  6. If there is still a problem when uploading the program, then try checking the driver / port / programmer tool / others section.

 

Step 11 : Wiring FTDI to the STM8S103F3P6

 

Notes :

  1. Serial communication on this STM8S103F3P6 board is very possible, especially for Serial Monitor and Serial Plotter purposes. Tools that can be used for serial communication include: CP2102 USB, CH340 USB, FTDI USB, or with PL2303 USB.

     

  2. You can see the wiring between the FTDI USB and the STM8S103F3P6 board in detail in the picture above.

 

Step 12 : Wiring PL2303 to the Arduino Pro Mini

 

Notes :

  1. This Arduino Pro Mini is not equipped with a USB port, so you need an additional device in the form of a USB to TTL Serial to connect to a laptop or PC. USB to TTL Serial like the PL2303 USB is commonly used as an intermediate medium for uploading programs.

     

  2. You can see the wiring between the PL2303 USB and the Arduino Pro Mini board in the picture above.

     

  3. To upload a program, in addition to using the PL2303 USB, you can also use other programming tools such as: CP2102 USB, CH340 USB, or with FTDI USB. Based on experience, I admit that using FTDI USB or CP2102 USB is much better than PL2303 USB and CH340 USB. I recommend this alternative method because I have frequently experienced upload failures when using a PL2303 USB. This usually happens when the manual reset is not timed correctly with the upload process. An example of the error is shown below.

 

Step 13 : Wiring FTDI to the Arduino Pro Mini (Alternative Method)

 

Notes :

  1. You can see the wiring between the FTDI USB and the Arduino Pro Mini board in the picture above.

     

  2. Uploading a program using an FTDI USB is generally easier and more reliable because it can automatically reset the Arduino Pro Mini through the DTR pin. This means you no longer need to press the Reset button manually every time you upload a program.

     

  3. If you do not have an FTDI USB, you can use a CP2102 USB instead, as the setup is nearly identical.

 

Step 14 : Motor Speed Control (pwm_conveyor.ino)

// global variable initialization
#define PB1_PIN PD4 // PD2 pin to push button 1
#define ENA_PIN PD3 // PD3 pin to enable motor A
#define PB2_PIN PD2 // PD4 pin to push button 2
#define IN1_PIN PD5 // PD5 pin to rotate the motor backward
#define IN2_PIN PD6 // PD6 pin to rotate the motor forward
#define PTM_PIN PC0 // PC0 pin to potentiometer

// initialize the status of digital readings on push buttons 1 and 2 into boolean data type
boolean state1 = false, state2 = false;

// initialize the analog reading on potentiometer into integer data type
int pot = 0;

// Method: setup
void setup() {
  pinMode(PB1_PIN, INPUT_PULLUP);     // PD2 pin is used as an input
  pinMode(ENA_PIN, OUTPUT);           // PD3 pin is used as an output
  pinMode(PB2_PIN, INPUT_PULLUP);     // PD4 pin is used as an input
  pinMode(IN1_PIN, OUTPUT);           // PD5 pin is used as an output
  pinMode(IN2_PIN, OUTPUT);           // PD6 pin is used as an output
  Serial.begin(9600);                 // start serial communication at a baud rate of 9600
}

// Method: loop
void loop() {

  // motor speed control with PWM
  pot = map(analogRead(PTM_PIN), 0, 1023, 0, 255);
  analogWrite(ENA_PIN, pot);

  // displaying the PWM value of a potentiometer on the serial monitor
  Serial.println("-----------------------------------");
  Serial.print("\nPot PWM : ");
  Serial.println(pot);
  Serial.println();

  forward();    // calling the forward method
  reverse();    // calling the reverse method
  delay(1000);  // delay -> 1 second
}

// Method: forward
void forward(){

  // digital readout of button 1
  state1 = digitalRead(PB1_PIN);

  // displaying the status of push button 1 on the serial monitor
  Serial.println("-----------------------------------");
  Serial.print("\nPB1 : ");
  Serial.println(state1 == LOW ? "PRESSED" : "RELEASED");

  // displaying the current logic state of IN2 pin on the serial monitor
  Serial.print("IN2 State : ");
  Serial.println(digitalRead(IN2_PIN));
  Serial.println();

  // if button 1 is pressed when the motor is off then:
  if (digitalRead(IN2_PIN) == LOW && state1 == LOW){

    // displaying the motor direction (forward) on the serial monitor
    Serial.println("Status ==> FORWARD\n");

    // motor rotation will be clockwise
    digitalWrite(IN1_PIN, LOW);
    digitalWrite(IN2_PIN, HIGH);
    state1 = true;
  }

  // if button 1 is pressed while the motor is running then:
  else if (digitalRead(IN2_PIN) == HIGH && state1 == LOW){

    // displaying the stop command after forward operation
    Serial.println("Status ==> STOP FROM FORWARD\n");

    // the motor will be shut down as soon as possible
    digitalWrite(IN1_PIN, LOW);
    digitalWrite(IN2_PIN, LOW);
    state1 = true;
  }
}

// Method: reverse
void reverse(){

  // digital readout of button 2
  state2 = digitalRead(PB2_PIN);

  // displaying the status of push button 2 on the serial monitor
  Serial.println("-----------------------------------");
  Serial.print("\nPB2 : ");
  Serial.println(state2 == LOW ? "PRESSED" : "RELEASED");

  // displaying the current logic state of IN1 pin on the serial monitor
  Serial.print("IN1 State : ");
  Serial.println(digitalRead(IN1_PIN));
  Serial.println();

  // if button 2 is pressed when the motor is off then:
  if (digitalRead(IN1_PIN) == LOW && state2 == LOW) {

    // displaying the motor direction (reverse) on the serial monitor
    Serial.println("Status ==> REVERSE\n");
 
    // motor rotation will be counterclockwise
    digitalWrite(IN1_PIN, HIGH);
    digitalWrite(IN2_PIN, LOW);
    state2 = true;
  }

  // if button 2 is pressed while the motor is running then:
  else if (digitalRead(IN1_PIN) == HIGH && state2 == LOW){

    // displaying the stop command after reverse operation
    Serial.println("Status ==> STOP FROM REVERSE\n");

    // the motor will be shut down as soon as possible
    digitalWrite(IN1_PIN, LOW);
    digitalWrite(IN2_PIN, LOW);
    state2 = true;
  }
}

 

Step 15 : Upload Firmware to the Arduino Pro Mini

  1. Open the Arduino IDE first, then open this project by clicking File -> Open :

    pwm_conveyor.ino

     

  2. Board Setup in Arduino IDE

    Click Tools -> Board -> Arduino AVR Boards -> Arduino Pro or Pro Mini

     

  3. Change Processor in Arduino IDE

    Click Tools -> Processor -> ATmega328P (5V, 16 MHz)

     

  4. Port Setup in Arduino IDE

    ➤  Click Port.

    ➤  Choose according to your device port (you can see in device manager).

     

  5. Before uploading the program please click : Verify.

     

  6. If there is no error in the program code, then please click : Upload.

     

  7. Some things you need to do when using the Arduino Pro Mini board with PL2303 USB :

    ➤  Arduino IDE information :

          Uploading... -> immediately press the RESET button and release it.

     

    ➤  Wait until the message appears :

          Done Uploading -> The program is directly operated.

     

  8. If there is still a problem when uploading the program, then try checking the driver / port / others section.
Codes

Downloads

Pictorial Diagram - STM8S103F3P6 Download
Pictorial Diagram - Arduino Pro Mini Download
Block Diagram - STM8S103F3P6 Download
Block Diagram - Arduino Pro Mini Download

Institute / Organization

Universitas Pembangunan Nasional Veteran Jawa Timur
Comments
Ad