Note

Hello, welcome to the SunFounder Raspberry Pi & Arduino & ESP32 Enthusiasts Community on Facebook! Dive deeper into Raspberry Pi, Arduino, and ESP32 with fellow enthusiasts.

Why Join?

  • Expert Support: Solve post-sale issues and technical challenges with help from our community and team.

  • Learn & Share: Exchange tips and tutorials to enhance your skills.

  • Exclusive Previews: Get early access to new product announcements and sneak peeks.

  • Special Discounts: Enjoy exclusive discounts on our newest products.

  • Festive Promotions and Giveaways: Take part in giveaways and holiday promotions.

👉 Ready to explore and create with us? Click [here] and join today!

7.4 Building a Passenger Counter

In this lesson, we’ll create a Passenger Counter using a Raspberry Pi Pico 2, a PIR (Passive Infrared) motion sensor, and a 4-digit 7-segment display. This device will count the number of times motion is detected by the PIR sensor and display the count on the 7-segment display. This simulates how such counters are used in public places to monitor foot traffic.

What You’ll Need

In this project, we need the following components.

It’s definitely convenient to buy a whole kit, here’s the link:

Name

ITEMS IN THIS KIT

LINK

Newton Lab Kit

450+

Newton Lab Kit

You can also buy them separately from the links below.

SN

COMPONENT

QUANTITY

LINK

1

Raspberry Pi Pico 2

1

BUY

2

Micro USB Cable

1

3

Breadboard

1

BUY

4

Jumper Wires

Several

BUY

5

Resistor

4(220Ω)

BUY

6

4-Digit 7-Segment Display

1

7

74HC595

1

BUY

8

PIR Motion Sensor Module

1

BUY

Understanding the Components

  • PIR Motion Sensor: Detects motion by measuring infrared (IR) light radiating from objects in its field of view. When motion is detected, it outputs a HIGH signal.

  • 4-Digit 7-Segment Display: Allows us to display numbers from 0000 to 9999. We’ll use shift registers to control the display using fewer GPIO pins.

  • 74HC595 Shift Register: This is a 8-bit serial-in, parallel-out shift register with output latche. It allows us to control multiple outputs using just a few GPIO pins.

Circuit Diagram

sch_passager_counter

  • This circuit is based on the 5.3 Creating a Time Counter with a 4-Digit 7-Segment Display with the addition of a PIR module.

  • The PIR will send a high signal of about 2.8s long when someone passes by.

  • The PIR module has two potentiometers: one adjusts sensitivity, the other adjusts detection distance. To make the PIR module work better, you need to turn both of them counterclockwise to the end.

    img_PIR_TTE

Wiring Diagram

wiring_passager_counter

Writing the Code

We’ll write a MicroPython script that:

  • Detects motion using the PIR sensor.

  • Increments a counter each time motion is detected.

  • Updates the 4-digit 7-segment display with the current count.

  • Uses multiplexing to control the display.

Note

  • Open the 7.4_passager_counter.py from newton-lab-kit/micropython or copy the code into Thonny, then click “Run” or press F5.

  • Ensure the correct interpreter is selected: MicroPython (Raspberry Pi Pico).COMxx.

from machine import Pin
import utime

# Define the PIR sensor pin
pir_sensor = Pin(16, Pin.IN)

# Initialize the counter
count = 0

# Define the binary codes for each digit (0-9)
SEGMENT_CODES = [
    0x3F,  # 0
    0x06,  # 1
    0x5B,  # 2
    0x4F,  # 3
    0x66,  # 4
    0x6D,  # 5
    0x7D,  # 6
    0x07,  # 7
    0x7F,  # 8
    0x6F   # 9
]

# Initialize the control pins for 74HC595
SDI = machine.Pin(18, machine.Pin.OUT)   # Serial Data Input (DS)
RCLK = machine.Pin(19, machine.Pin.OUT)  # Register Clock (STCP)
SRCLK = machine.Pin(20, machine.Pin.OUT) # Shift Register Clock (SHCP)

# Initialize digit select pins (common cathodes)
digit_pins = [
    machine.Pin(10, machine.Pin.OUT),  # Digit 1
    machine.Pin(11, machine.Pin.OUT),  # Digit 2
    machine.Pin(12, machine.Pin.OUT),  # Digit 3
    machine.Pin(13, machine.Pin.OUT)   # Digit 4
]

# Function to send data to 74HC595
def shift_out(data):
    RCLK.low()
    for bit in range(7, -1, -1):
        SRCLK.low()
        bit_val = (data >> bit) & 0x01
        SDI.value(bit_val)
        SRCLK.high()
    RCLK.high()

# Function to display a digit at a specific position
def display_digit(position, digit):
    # Turn off all digits
    for dp in digit_pins:
        dp.high()
    # Send segment data
    shift_out(SEGMENT_CODES[digit])
    # Activate the selected digit (common cathode is active low)
    digit_pins[position].low()
    # Small delay to allow the digit to be visible
    utime.sleep_ms(5)
    # Turn off the digit
    digit_pins[position].high()

# Function to display a number on the 4-digit display
def display_number(number):
    # Extract individual digits
    digits = [
        (number // 1000) % 10,
        (number // 100) % 10,
        (number // 10) % 10,
        number % 10
    ]
    # Display each digit rapidly
    for i in range(4):
        display_digit(i, digits[i])

# Interrupt handler for PIR sensor
def pir_handler(pin):
    global count
    count += 1
    if count > 9999:
        count = 0

# Set up PIR sensor interrupt
pir_sensor.irq(trigger=Pin.IRQ_RISING, handler=pir_handler)

# Main loop
while True:
    # Continuously refresh the display
    display_number(count)

When the code is running, the 7-segment display should initialize and show 0000. Move in front of the PIR sensor. The count displayed should increment by one each time motion is detected. If the count reaches 9999, it will reset to 0000.

Understanding the Code

  1. Imports and Pin Definitions:

    • machine.Pin: For controlling GPIO pins.

    • utime: For timing functions.

    • Define SDI, SRCLK, and RCLK pins for controlling the shift register.

    • Define pir_sensor on GP16 as an input pin for the PIR sensor.

  2. Segment Codes:

    • SEGMENT_CODES: A list containing the binary codes for displaying digits 0-9 on a 7-segment display. Each byte represents which segments should be lit.

    # 7-segment display segment codes for digits 0-9 (common cathode)
    SEGMENT_CODES = [
        0x3F,  # 0
        0x06,  # 1
        0x5B,  # 2
        0x4F,  # 3
        0x66,  # 4
        0x6D,  # 5
        0x7D,  # 6
        0x07,  # 7
        0x7F,  # 8
        0x6F   # 9
    ]
    
  3. Counter Initialization:

    • count: A global variable that keeps track of the number of times motion has been detected.

  4. Define the shift_out Function:

    • Sends 8 bits of data to the 74HC595.

    • Shifts out the data starting from the most significant bit (MSB).

    • Pulses the shift and register clocks appropriately.

    def shift_out(data):
        RCLK.low()
        for bit in range(7, -1, -1):
            SRCLK.low()
            bit_val = (data >> bit) & 0x01
            SDI.value(bit_val)
            SRCLK.high()
        RCLK.high()
    
  5. Define the display_digit Function:

    • Turns off all digits.

    • Sends the segment code for the digit.

    • Activates the specified digit by setting its pin low.

    • Adds a small delay to make the digit visible.

    • Turns off the digit after displaying.

    def display_digit(position, digit):
        for dp in digit_pins:
            dp.high()
        shift_out(SEGMENT_CODES[digit])
        digit_pins[position].low()
        utime.sleep_ms(5)
        digit_pins[position].high()
    
  6. Define the display_number Function:

    • Extracts each digit from the number.

    • Calls display_digit for each digit rapidly to create the multiplexing effect.

    def display_number(number):
        # Extract individual digits
        digits = [
            (number // 1000) % 10,
            (number // 100) % 10,
            (number // 10) % 10,
            number % 10
        ]
        # Display each digit rapidly
        for i in range(4):
            display_digit(i, digits[i])
    
  7. PIR Interrupt Handler:

    • pir_handler: This function is called automatically when the PIR sensor detects motion.

    • Increments the count variable.

    • Resets the count to 0 if it exceeds 9999.

    def pir_handler(pin):
        global count
        count += 1
        if count > 9999:
            count = 0
    
  8. PIR Sensor Interrupt Setup:

    pir_sensor.irq: Sets up an interrupt to call pir_handler on a rising edge signal from the PIR sensor (i.e., when motion is detected).

    pir_sensor.irq(trigger=Pin.IRQ_RISING, handler=pir_handler)
    
  9. Main Loop:

    Continuously calls display_number(count) to refresh the display with the current count.

    while True:
        display_number(count)
    

Troubleshooting

  • Display Issues:

    • If the display is not showing numbers correctly, verify the segment codes and wiring connections.

    • Ensure that the shift register is connected properly and that data is being shifted out in the correct order.

  • PIR Sensor Sensitivity:

    • The PIR sensor may have adjustable potentiometers for sensitivity and delay.

    • Adjust these to fine-tune motion detection for your environment.

    • Note that the PIR sensor may have a short delay after detecting motion before it can detect again.

  • Counting Accuracy:

    • In environments with a lot of movement, the counter may increment rapidly.

    • Consider adding logic to debounce the PIR sensor or limit counting frequency if necessary.

Extensions and Enhancements

  • Reset Button:

    Add a push button connected to another GPIO pin to reset the count to zero when pressed.

  • Bidirectional Counting:

    Use two PIR sensors placed strategically to detect the direction of movement (entering or exiting) and increment or decrement the count accordingly.

  • Data Logging:

    Extend the program to log counts over time, either by storing data on the Pico or sending it to a computer for analysis.

  • Display Improvements:

    Use an LCD display to show additional information such as timestamps, total counts, or messages.

  • Network Connectivity:

    Connect the Pico to a network (using Wi-Fi modules like ESP8266) to send data to a server or cloud service for remote monitoring.

Conclusion

In this lesson, you’ve learned how to create a practical Passenger Counter using the Raspberry Pi Pico 2, a PIR motion sensor, and a 4-digit 7-segment display. This project demonstrates how microcontrollers can interact with sensors and output devices to collect and display data in real-time.

Feel free to experiment with the code and hardware to add new features or improve functionality. This project can serve as a foundation for more complex systems involving data analysis, remote monitoring, or integration with other sensors and devices.