Button PLAY Click with UNI-DS v8

Published Mar 24, 2025

Click board™

Button PLAY Click
LightRanger 3 Click
Relay 3 Click
8x8 G Click

Dev. board

UNI-DS v8

Compiler

NECTO Studio

MCU

STM32F407ZG

Button-Triggered Distance Monitoring with Relay & Display Control

Precise distance monitoring, live display, and automated relay control in an interactive, button-triggered system

What you'll learn and build

Intro

The Button-Triggered Distance Monitoring with Relay & Display Control solution integrates Button Play Click, LightRanger 3 Click, Relay 3 Click, and 8x8 G Click to provide a comprehensive, interactive distance-sensing system with real-time visual feedback and automated relay control. Designed for smart interfaces, proximity-triggered automation, and safety systems, this solution continuously measures object distance while the button is held, displays the value on the LED matrix, and controls two relays based on the result. With distance-based logic (≤100mm to activate relays), button backlight transitions, and averaged sensor readings for improved accuracy, it delivers a user-friendly and responsive approach to distance monitoring and control.

mikroBUS 1

Button PLAY Click

Button PLAY Click is a very interesting interactive gadget on a Click board™. It is an integrated capacitive touch sensor display in the form of a button. By utilizing an advanced capacitive touch sensing technology, the CTHS15CIC05ARROW sensor can successfully replace the traditional mechanical button, allowing very simplified yet reliable user interfaces to be developed. Besides the touch detection, this sensor also features a green arrow icon with backlight, which makes the Click board™ very useful for building various stylized and visually appealing interfaces.

Button PLAY Click front-background image

mikroBUS 2

LightRanger 3 Click

LightRanger 3 Click is an accurate distance measurement Click board™ based on a ToF (Time of Flight) measurement principle. The Simblee™ enabled RFD77402 rangefinder module from RF Digital is a complete measurement stack on the chip. It is surprisingly easy to work with, as this highly integrated range finder module exposes the only I2C interface and INT pin to the host controller. It features the VCSEL, a Vertical Cavity Surface Emitting Laser, used to emit a narrow band of a harmless modulated light beam in the IR range (850 nm), and a receive sensor, which can detect the reflected light. It can measure distances up to 2000mm, with up to 10% accuracy. The device is rated Class 1 LASER product, operating in the IR (invisible) spectrum range.

LightRanger 3 Click front-background image

mikroBUS 3

Relay 3 Click

Relay 3 Click is a dual relay Click board, featuring two single-pole double-throw relays which can be operated by output pins of the host microcontroller (MCU). It offers an elegant and easy solution for controlling a wide range of power applications. Two SRD-5VDC-SL-C relays used on this Click board™ are hermetically sealed relays which require 5V across their coils while consuming about 0.4W while active. They allow up to 28VDC across the connected load, while conducting up to 7A. Relay 3 click can be used in various PLC-based systems, as a remote ON/OFF switch, and other similar applications.

Relay 3 Click front-background image

mikroBUS 4

8x8 G Click

8x8 G Click is a 64 LED matrix display Click board™, composed of SMD LEDs organized in 8 rows by 8 columns. It has a digital brightness control in 16 steps, it can control every LED in the display matrix independently, it blanks the display on power up to eliminate glitches and it requires a single resistor to control the current through all the LEDs at once, which simplifies the design. 8x8 G click uses a fast SPI communication protocol, allowing fast display response and no lag.

8x8 G Click front-background image

Features overview

Development board

UNI-DS v8 is a powerful development board for rapid embedded application development, supporting various MCUs (STM32, Kinetis, TIVA, PIC, AVR, etc.) and featuring the first embedded WiFi debugger/programmer. It integrates an advanced CODEGRIP module with JTAG, SWD, and SWO Trace support, a regulated power supply with multiple input options (USB-C, 12V, battery), and extensive connectivity (USB-UART, USB HOST/DEVICE, CAN, Ethernet). With mikroBUS™, SiBRAIN support, and dual display options, it seamlessly fits into the MIKROE ecosystem, offering compatibility with all Click boards™ for efficient and immersive prototyping.

UNI-DS v8 front image

Microcontroller Overview

MCU Card / MCU

default

Type

8th Generation

Architecture

ARM Cortex-M4

MCU Memory (KB)

1024

Silicon Vendor

STMicroelectronics

Pin count

144

RAM (Bytes)

196608

Step by step

Project assembly

Fusion for PIC v8 front image hardware assembly

Start by selecting your development board - UNI-DS v8

Fusion for PIC v8 front image hardware assembly
LTE IoT 5 Click front-background image hardware assembly
Calypso Click front-background image hardware assembly
Thermo 21 Click front-background image hardware assembly
Button PLAY Click top side image hardware assembly
SiBRAIN for PIC32MZ1024EFK144 front image hardware assembly
Board mapper by product8 hardware assembly
Necto image step 2 hardware assembly
Necto image step 3 hardware assembly
Necto image step 4 hardware assembly
NECTO Compiler Selection Step Image hardware assembly
NECTO Output Selection Step Image hardware assembly
Necto image step 6 hardware assembly
Necto image step 7 hardware assembly
Necto image step 8 hardware assembly
Necto image step 9 hardware assembly
Necto image step 10 hardware assembly
Necto PreFlash Image hardware assembly

Track your results in real time

Application Output

1. Application Output - In Debug mode, the 'Application Output' window enables real-time data monitoring, offering direct insight into execution results. Ensure proper data display by configuring the environment correctly using the provided tutorial.

2. UART Terminal - Use the UART Terminal to monitor data transmission via a USB to UART converter, allowing direct communication between the Click board™ and your development system. Configure the baud rate and other serial settings according to your project's requirements to ensure proper functionality. For step-by-step setup instructions, refer to the provided tutorial.

3. Plot Output - The Plot feature offers a powerful way to visualize real-time sensor data, enabling trend analysis, debugging, and comparison of multiple data points. To set it up correctly, follow the provided tutorial, which includes a step-by-step example of using the Plot feature to display Click board™ readings. To use the Plot feature in your code, use the function: plot(*insert_graph_name*, variable_name);. This is a general format, and it is up to the user to replace 'insert_graph_name' with the actual graph name and 'variable_name' with the parameter to be displayed.

Software Support

Library Description

Button-Triggered Distance Monitoring with Relay & Display Control is developed using the NECTO Studio, ensuring compatibility with mikroSDK's open-source libraries and tools. Designed for plug-and-play implementation and testing, this solution is fully compatible with all development, starter, and mikromedia boards featuring a mikroBUS™ socket.

Example Description
The Button-Triggered Distance Monitoring with Relay & Display Control integrates the Button Play Click, LightRanger 3 Click, Relay 3 Click, and 8x8 G Click to measure the distance to an object WHEN A BUTTON IS PRESSED. The system continuously measures the distance while the button is held down, displays the distance on the 8x8 G Click, and controls two relays based on the average distance. The button's backlight smoothly fades in on press and fades out on release, providing visual feedback. Distance measurements are averaged across multiple readings to reduce sensor noise, and the results are logged via UART.

Key functions:

  • initialize_button_play - Initializes the Button Play Click, configures PWM for LED backlight control, and starts the PWM signal. Logs an error and halts execution if initialization fails.

  • initialize_light_ranger - Initializes the LightRanger 3 Click and configures the sensor. Logs an error and halts execution if the sensor initialization fails.

  • initialize_relay_3 - Initializes the Relay 3 Click, configuring it to control external devices based on the distance measurement. Logs an error and halts execution if initialization fails.

  • initialize_8x8_g - Initializes the 8x8 G Click for distance display or status messaging. Logs an error and halts execution if initialization fails.

  • update_button_backlight - Smoothly fades the button backlight LED in or out, depending on the button state. Brightens the LED when pressed and dims it on release.

  • measure_and_log_distance - Takes a single distance measurement using the LightRanger 3 Click, averages multiple readings, and logs the average value via UART.

  • display_distance_on_8x8_g - Converts the measured distance to a string and displays it on the 8x8 G Click in millimeters (e.g., "123mm").

  • show_button_released_message - Clears the display and shows a message when the button is released.

  • case_both_relays - Controls the relays based on the average distance. If the average distance is 100mm or less, both relays are turned ON; otherwise, they are turned OFF.

Application Init
The initialization sequence sets up UART logging, configures all Click boards, and verifies hardware readiness. If an error occurs during initialization, an error message is logged, and execution halts.

Application Task
The main application loop continuously performs the following tasks:

1. Detects button press and triggers distance measurement.

2. Takes multiple distance readings, averages them, and logs the result via UART.

3. Smoothly fades the button backlight in on press and out on release.

4. Updates the 8x8 G Click display with the measured distance or shows a release message.

5. Controls relays based on the average distance: turns both relays ON if the average distance is 100mm or less; turns both relays OFF if the average distance goes above 100mm.

6. Logs button press/release events, distance measurements, and relay states.

Open Source

Code example

The complete application code and a ready-to-use project are available through the NECTO Studio Package Manager for direct installation in the NECTO Studio. The application code can also be found on the MIKROE GitHub account.

/*
 * Solution Name: Button-Triggered Distance Monitoring with Relay & Display Control
 *
 * Description:
 * This embedded application uses Button Play Click, LightRanger 3 Click, 
 * Relay 3 Click, and 8x8 G Click to measure the distance to an object WHEN 
 * A BUTTON IS PRESSED. The system continuously measures the distance while 
 * the button is held down, displays the distance on the 8x8 G Click, and 
 * controls two relays based on the average distance.
 * 
 * - If the average distance is ? 100 mm: Both relays turn ON.
 * - If the average distance is > 100 mm: Both relays turn OFF.
 * 
 * The button's backlight fades in on press and fades out on release, providing 
 * visual feedback. Distance measurements are averaged over multiple readings 
 * to reduce sensor noise and improve accuracy.
 *
 * The system utilizes the following Click boards:
 *   - Button Play Click: Captures button press/release events and controls 
 *     LED backlight.
 *   - LightRanger 3 Click: Measures the distance to a nearby object using 
 *     a laser sensor.
 *   - Relay 3 Click: Controls external devices based on distance thresholds.
 *   - 8x8 G Click: Displays the measured distance or a message on button release.
 *
 * The `application_init` function initializes the logger and all Click boards, 
 * ensuring proper startup conditions. Any initialization failure is logged, 
 * and the system halts.
 *
 * The `application_task` function monitors the button state, triggers distance 
 * measurements, calculates the average distance, updates the display, and toggles 
 * the relays based on the distance threshold.
 *
 * Hardware Setup:
 *   - MIKROBUS_1: Button Play Click
 *   - MIKROBUS_2: 8x8 G Click
 *   - MIKROBUS_3: Relay 3 Click
 *   - MIKROBUS_4: LightRanger 3 Click
 *
 * Key Features:
 *   - Button-controlled distance monitoring with real-time relay control.
 *   - Multi-sample averaging to reduce sensor reading noise.
 *   - Smooth LED fade-in/out on button press/release.
 *   - Distance display with automatic message on button release.
 *   - UART logging for measurement data and system events.
 *   - Automatic relay switching based on distance threshold.
 *
 * Development Environment:
 *   - [NECTO Studio](https://www.mikroe.com/necto)
 *   - [mikroSDK v2.0](https://www.mikroe.com/mikrosdk) framework
 *   - MIKROE [Click boards](https://www.mikroe.com/click-boards) Add-ons
 *
 * Author: Branko Jaksic
 * Date: 2025
 */

// ------------------------------------------------------------------- INCLUDES
#include "log.h"
#include "board.h"
#include "c8x8g.h"
#include "relay3.h"
#include "buttonplay.h"
#include "lightranger3.h"
#include "conversions.h"

// ------------------------------------------------------------------ VARIABLES
static log_t logger;
static c8x8g_t c8x8g;
static relay3_t relay3;
static buttonplay_t buttonplay;
static lightranger3_t lightranger3;

static int case_both_relays_switch = 0;

// ---------------------------------------------- PRIVATE FUNCTION DECLARATIONS
/**
 * @brief Toggle Both Relays On/Off
 * 
 * This function toggles the state of both relays connected to the Relay 3 Click board. 
 * It uses a state switch (`case_both_relays_switch`) to alternate between turning both 
 * relays ON and OFF. 
 * 
 * - When `case_both_relays_switch` is `0`, both relays are turned ON, and a message is 
 *   logged via UART.
 * - When `case_both_relays_switch` is `1`, both relays are turned OFF, and a corresponding 
 *   message is logged.
 * 
 * The function updates the `case_both_relays_switch` variable to track the current state, 
 * flipping its value between `0` and `1` on each call.
 * 
 * This function can be used in scenarios where relays need to be toggled at regular intervals 
 * or based on specific conditions (e.g., distance threshold crossing).
 * 
 * @note The function relies on a global variable `case_both_relays_switch` to manage state.
 */
static void case_both_relays ( );

// ----------------------------------------------- PUBLIC FUNCTION DECLARATIONS

/**
 * @brief Initializes the Button Play Click board.
 *
 * Configures the Button Play Click board, sets up the PWM for LED
 * backlight control, and starts the PWM signal. If initialization fails,
 * the function logs an error and halts execution.
 *
 * @note The Button Play Click is connected to MIKROBUS_1.
 */
void initialize_button_play( void );

/**
 * @brief Initializes the LightRanger 3 Click board.
 *
 * Configures the LightRanger 3 Click board and performs device initialization. 
 * If the sensor fails to initialize, the function logs an error and halts
 * execution.
 *
 * @note The LightRanger 3 Click is connected to MIKROBUS_4.
 */
void initialize_light_ranger( void );

/**
 * @brief Initializes the Relay 3 Click board.
 *
 * Configures the Relay 3 Click board and performs device initialization. 
 * If the Relay fails to initialize, the function logs an error and halts
 * execution.
 *
 * @note The Relay 3 Click is connected to MIKROBUS_3.
 */
void initialize_relay_3( void );

/**
 * @brief Initializes the 8x8 G Click board.
 *
 * Configures the 8x8 G Click board and performs device initialization. 
 * If the 8x8 G Click fails to initialize, the function logs an error and halts
 * execution.
 *
 * @note The 8x8 G Click is connected to MIKROBUS_2.
 */
void initialize_8x8_g( void );

/**
 * @brief Display Distance on 8x8 G Click.
 *
 * Converts the measured distance to a string and displays it on the 8x8 G Click board.
 * The distance is shown in millimeters (e.g., "123mm").
 * 
 * @param[in] distance  The measured distance value in millimeters.
 */
void display_distance_on_8x8_g( uint16_t distance );

/**
 * @brief Show Button Released Message on 8x8 G Click.
 *
 * Clears the display and shows a message when the button is released.
 */
void show_button_released_message( void );

/**
 * @brief Updates the button backlight brightness.
 *
 * Smoothly fades the button's backlight LED in or out, depending on the
 * button state. When the button is pressed, the backlight gradually brightens.
 * When released, the backlight gradually dims.
 *
 * @param[in] is_pressed  Boolean indicating the button state:
 *                        - `true`: Fade in the backlight.
 *                        - `false`: Fade out the backlight.
 */
void update_button_backlight( bool is_pressed );

/**
 * @brief Measures and logs the distance using the LightRanger 3 Click.
 *
 * Takes a single distance measurement, retrieves the distance value,
 * and logs it via UART. This function is useful for quick,
 * real-time distance readings.
 */
void measure_and_log_distance( void );

// ------------------------------------------------------ APPLICATION FUNCTIONS
static void case_both_relays ( )
{
    if ( case_both_relays_switch == 0 )
    {
        relay3_relay_on( &relay3, RELAY3_BOTH_RELAYS );
        log_printf( &logger, "   Both relays ON.   \r\n" );

        case_both_relays_switch++;
    }
    else if ( case_both_relays_switch == 1 )
    {
        relay3_relay_off( &relay3, RELAY3_BOTH_RELAYS );
        log_printf( &logger, "   Both relays OFF.   \r\n" );

        case_both_relays_switch--;
    }
}

void application_init( void ) 
{
    log_cfg_t log_cfg;

    // Logger initialization
    LOG_MAP_USB_UART( log_cfg );
    log_init( &logger, &log_cfg );
    log_info( &logger, "Application Init" );

    initialize_button_play();
    initialize_light_ranger();
    initialize_relay_3();
    initialize_8x8_g();

    log_info( &logger, "Initialization Complete, Starting Application Task" );
}

void initialize_button_play( void )
{
    buttonplay_cfg_t buttonplay_cfg;

    buttonplay_cfg_setup( &buttonplay_cfg );
    BUTTONPLAY_MAP_MIKROBUS( buttonplay_cfg, MIKROBUS_1 );

    if ( buttonplay_init( &buttonplay, &buttonplay_cfg ) == PWM_ERROR ) 
    {
        log_error( &logger, "Button Play Click initialization failed!" );
        for ( ; ; );  // Halt execution
    }

    buttonplay_set_duty_cycle( &buttonplay, 0.0 );
    buttonplay_pwm_start( &buttonplay );
    log_info( &logger, "Button Play Click initialized successfully." );
}

void initialize_light_ranger( void )
{
    lightranger3_cfg_t lightranger3_cfg;

    lightranger3_cfg_setup( &lightranger3_cfg );
    LIGHTRANGER3_MAP_MIKROBUS( lightranger3_cfg, MIKROBUS_4 );
    lightranger3_init( &lightranger3, &lightranger3_cfg );

    if ( lightranger3_device_init( &lightranger3 ) != 0 ) 
    {
        log_error( &logger, "LightRanger Click initialization failed!" );
        for ( ; ; );  // Halt execution
    }

    log_info( &logger, "LightRanger Click initialized successfully." );
}

void initialize_relay_3( void ) {
    relay3_cfg_t relay3_cfg;

    relay3_cfg_setup( &relay3_cfg );
    RELAY3_MAP_MIKROBUS( relay3_cfg, MIKROBUS_3 );
    relay3_init( &relay3, &relay3_cfg );
}

void initialize_8x8_g( void ) {
    c8x8g_cfg_t c8x8g_cfg;

    c8x8g_cfg_setup( &c8x8g_cfg );
    C8X8G_MAP_MIKROBUS( c8x8g_cfg, MIKROBUS_2 );
    err_t init_flag  = c8x8g_init( &c8x8g, &c8x8g_cfg );
    if ( init_flag == SPI_MASTER_ERROR ) {
        log_info( &logger, " Application Init Error. " );
        log_info( &logger, " Please, run program again... " );

        for ( ; ; );
    }

    c8x8g_default_cfg ( &c8x8g );
}

void display_distance_on_8x8_g( uint16_t distance )
{
    char distance_str[ 5 ];
    uint16_to_str(distance, distance_str);

    // Show distance in mm (up to 9999 mm)
    c8x8g_display_string( &c8x8g, distance_str );
}

void show_button_released_message( void )
{
    c8x8g_display_byte( &c8x8g, ' ' );
}

void application_task( void )
{
    static uint8_t button_state_old = 0;
    uint8_t button_state = buttonplay_get_button_state( &buttonplay );

    if ( button_state != button_state_old ) 
    {
        if ( button_state ) 
        {
            log_printf( &logger, " <-- Button Pressed --> \r\n" );
            update_button_backlight( true );
        } 
        else 
        {
            log_printf( &logger, " <-- Button Released --> \r\n" );
            update_button_backlight( false );

            // Turn off relays when button is released
            if ( case_both_relays_switch == 1 )
            {
                case_both_relays();
            }
        }

        button_state_old = button_state;
    }

    if ( button_state ) 
    {
        // Continuously measure distance while button is pressed
        uint32_t distance_sum = 0;
        uint8_t num_measurements = 5;

        for ( uint8_t i = 0; i < num_measurements; i++ ) 
        {
            lightranger3_take_single_measurement( &lightranger3 );
            distance_sum += lightranger3_get_distance( &lightranger3 );
            Delay_ms( 100 ); // Small delay between measurements
        }

        uint16_t average_distance = ( uint16_t )( distance_sum / num_measurements );
        log_printf( &logger, "Average Distance: %u mm\r\n", average_distance );

        // Display the distance on 8x8 G Click
        display_distance_on_8x8_g( average_distance );

        // Control relays based on distance threshold
        if ( average_distance <= 100 && case_both_relays_switch == 0 ) 
        {
            log_printf( &logger, "Distance <= 100 mm! Turning both relays ON.\r\n" );
            case_both_relays();
        } 
        else if ( average_distance > 100 && case_both_relays_switch == 1 ) 
        {
            log_printf( &logger, "Distance > 100 mm! Turning both relays OFF.\r\n" );
            case_both_relays();
        }
        else {
            // Show message when button is released
            show_button_released_message();
        }
    }
}

void update_button_backlight( bool is_pressed )
{
    float duty_cycle;

    if ( is_pressed ) 
    {
        for ( uint8_t n = 1; n <= 100; n++ ) 
        {
            buttonplay_set_duty_cycle( &buttonplay, (float)n / 100 );
            Delay_ms( 10 );
        }
    } 
    else 
    {
        for ( uint8_t n = 100; n > 0; n-- ) 
        {
            buttonplay_set_duty_cycle( &buttonplay, (float)n / 100 );
            Delay_ms( 10 );
        }
    }
}

void measure_and_log_distance( void )
{
    lightranger3_take_single_measurement( &lightranger3 );
    uint16_t distance = lightranger3_get_distance( &lightranger3 );

    log_printf( &logger, "Distance: %u mm\r\n", distance );
}

int main( void ) 
{
    #ifdef PREINIT_SUPPORTED
    preinit();
    #endif

    application_init();

    while ( 1 ) 
    {
        application_task();
    }

    return 0;
}

Additional Support

Resources

Love this project?

'Buy This Kit' button takes you directly to the shopping cart where you can easily add or remove products.