Skip to main content

Arduino Return Values

Introduction

When you're writing Arduino programs, functions are your best friends. They help you organize code, make it reusable, and break down complex tasks into manageable pieces. One of the most powerful features of functions is their ability to return values - sending data back to wherever the function was called from.

In this tutorial, we'll explore how return values work in Arduino programming, why they're essential, and how to use them effectively in your projects.

What Are Return Values?

A return value is data that a function sends back after it completes its task. Think of it like asking a friend to check the temperature outside - they go check (the function runs), and then tell you "It's 72 degrees" (the return value).

Here's a basic illustration of how return values work:

Basic Syntax for Return Values

To create a function that returns a value, you need to:

  1. Specify the data type the function will return (instead of void)
  2. Include a return statement in the function body

Here's the basic structure:

cpp
dataType functionName(parameters) {
// Function code...
return valueToReturn;
}

Simple Return Value Example

Let's start with a simple example - a function that adds two numbers and returns the result:

cpp
int sum(int a, int b) {
int result = a + b;
return result;
}

void setup() {
Serial.begin(9600);
int total = sum(5, 3); // The returned value (8) is stored in 'total'
Serial.print("The sum is: ");
Serial.println(total); // Outputs: The sum is: 8
}

void loop() {
// Empty loop
}

In this example:

  • The function sum has a return type of int
  • It takes two parameters and returns their sum
  • In setup(), we call the function and store its result in the variable total

Understanding Different Return Types

Arduino functions can return various data types:

Return TypeDescriptionExample Use Case
intInteger valuesCounting, whole number calculations
floatDecimal valuesSensor readings, precise measurements
boolBoolean (true/false)Function success, condition checking
charSingle characterMenu selection, simple input
StringText stringFormatted messages, text processing

Example with Different Return Types

cpp
// Returns floating-point temperature
float getCelsius(int sensorValue) {
float voltage = sensorValue * (5.0 / 1023.0);
float temperatureC = (voltage - 0.5) * 100;
return temperatureC;
}

// Returns boolean success indicator
bool activateRelay(int pinNumber) {
if (pinNumber >= 0 && pinNumber <= 13) {
digitalWrite(pinNumber, HIGH);
return true; // Operation successful
} else {
return false; // Invalid pin number
}
}

void setup() {
Serial.begin(9600);

// Using float return value
float temperature = getCelsius(analogRead(A0));
Serial.print("Temperature: ");
Serial.print(temperature);
Serial.println(" °C");

// Using boolean return value
if (activateRelay(7)) {
Serial.println("Relay activated successfully");
} else {
Serial.println("Failed to activate relay");
}
}

void loop() {
// Empty loop
}

Practical Applications

1. Sensor Reading and Processing

Return values are perfect for sensor reading functions that process raw data into meaningful values:

cpp
float readDistanceCm() {
// HC-SR04 ultrasonic sensor
digitalWrite(TRIGGER_PIN, LOW);
delayMicroseconds(2);
digitalWrite(TRIGGER_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIGGER_PIN, LOW);

long duration = pulseIn(ECHO_PIN, HIGH);
float distance = duration * 0.034 / 2; // Calculate distance in cm

return distance;
}

void setup() {
Serial.begin(9600);
pinMode(TRIGGER_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
}

void loop() {
float distance = readDistanceCm();

Serial.print("Distance: ");
Serial.print(distance);
Serial.println(" cm");

delay(1000);
}

2. Error Handling with Return Values

Return values can indicate success, failure, or error types:

cpp
int connectToWiFi(const char* ssid, const char* password) {
// Attempt to connect to WiFi
WiFi.begin(ssid, password);

int attempts = 0;
while (WiFi.status() != WL_CONNECTED && attempts < 20) {
delay(500);
attempts++;
}

if (WiFi.status() == WL_CONNECTED) {
return 1; // Success
} else if (WiFi.status() == WL_NO_SSID_AVAIL) {
return -1; // SSID not found
} else {
return 0; // General connection failure
}
}

void setup() {
Serial.begin(9600);

int connectionResult = connectToWiFi("MyNetwork", "password123");

switch (connectionResult) {
case 1:
Serial.println("Successfully connected to WiFi!");
break;
case -1:
Serial.println("Error: Network not found");
break;
case 0:
Serial.println("Error: Failed to connect");
break;
}
}

void loop() {
// Empty loop
}

3. Conversion Utility Functions

Create utility functions that convert between different units:

cpp
float fahrenheitToCelsius(float tempF) {
return (tempF - 32) * 5.0 / 9.0;
}

float celsiusToFahrenheit(float tempC) {
return tempC * 9.0 / 5.0 + 32;
}

void setup() {
Serial.begin(9600);

float roomTempF = 72.0;
float roomTempC = fahrenheitToCelsius(roomTempF);

Serial.print(roomTempF);
Serial.print("°F is equal to ");
Serial.print(roomTempC);
Serial.println("°C");

float boilingC = 100.0;
float boilingF = celsiusToFahrenheit(boilingC);

Serial.print(boilingC);
Serial.print("°C is equal to ");
Serial.print(boilingF);
Serial.println("°F");
}

void loop() {
// Empty loop
}

Advanced Techniques with Return Values

Returning Multiple Values

Arduino functions can only return a single value directly, but there are ways to return multiple values:

1. Using a struct

cpp
struct SensorData {
float temperature;
float humidity;
float pressure;
};

SensorData readEnvironmentData() {
SensorData data;

// Read from sensors (simulated here)
data.temperature = 24.5;
data.humidity = 65.3;
data.pressure = 1013.2;

return data;
}

void setup() {
Serial.begin(9600);

SensorData environment = readEnvironmentData();

Serial.print("Temperature: ");
Serial.print(environment.temperature);
Serial.println("°C");

Serial.print("Humidity: ");
Serial.print(environment.humidity);
Serial.println("%");

Serial.print("Pressure: ");
Serial.print(environment.pressure);
Serial.println(" hPa");
}

void loop() {
// Empty loop
}

2. Using reference parameters

Instead of returning values, pass variables by reference to be modified:

cpp
void getAccelerometerData(float &x, float &y, float &z) {
// Read accelerometer (simulated here)
x = 0.05;
y = 1.02;
z = 9.81;
}

void setup() {
Serial.begin(9600);

float xAccel, yAccel, zAccel;
getAccelerometerData(xAccel, yAccel, zAccel);

Serial.print("X acceleration: ");
Serial.println(xAccel);
Serial.print("Y acceleration: ");
Serial.println(yAccel);
Serial.print("Z acceleration: ");
Serial.println(zAccel);
}

void loop() {
// Empty loop
}

Chaining Function Calls

You can use the return value from one function as an input to another:

cpp
float readAnalogVoltage(int pin) {
int sensorValue = analogRead(pin);
return sensorValue * (5.0 / 1023.0);
}

float voltageToCelsius(float voltage) {
return (voltage - 0.5) * 100.0;
}

void setup() {
Serial.begin(9600);

// Chain functions: result of readAnalogVoltage becomes input to voltageToCelsius
float temperature = voltageToCelsius(readAnalogVoltage(A0));

Serial.print("Temperature: ");
Serial.print(temperature);
Serial.println("°C");
}

void loop() {
// Empty loop
}

Common Mistakes with Return Values

1. Forgetting to Use the Return Value

cpp
// INCORRECT: Return value ignored
void setup() {
Serial.begin(9600);

sum(5, 3); // The result is calculated but never used!

Serial.println("Calculation complete");
}

// CORRECT: Capture and use the return value
void setup() {
Serial.begin(9600);

int result = sum(5, 3);

Serial.print("The sum is: ");
Serial.println(result);
}

2. Return Type Mismatch

cpp
// INCORRECT: Returning float when int is expected
int getCelsius() {
float temp = 25.7;
return temp; // Data loss: 25.7 becomes 25
}

// CORRECT: Return type matches the actual value
float getCelsius() {
float temp = 25.7;
return temp;
}

3. Missing Return Statement

cpp
// INCORRECT: Not all paths return a value
int checkSensor(int value) {
if (value > 500) {
return 1;
}
// Missing return for when value <= 500!
}

// CORRECT: All paths return a value
int checkSensor(int value) {
if (value > 500) {
return 1;
} else {
return 0;
}
}

Best Practices for Return Values

  1. Be Consistent: Use return values consistently for similar functions.
  2. Check Return Values: Always check return values that indicate success/failure.
  3. Document Your Return Values: Comment what different return values mean.
  4. Use Meaningful Return Types: Choose appropriate data types for what you're returning.
  5. Consider Error Handling: Use special return values to indicate errors.

Summary

Return values are a fundamental concept in Arduino programming that allow functions to communicate results back to the calling code. They help make your code:

  • More modular and reusable
  • Easier to debug and maintain
  • More powerful and flexible

By mastering return values, you can create more sophisticated Arduino projects with cleaner, more efficient code.

Exercises

  1. Write a function that takes a temperature in Celsius and returns true if it's above a certain threshold, otherwise false.
  2. Create a function that reads an analog sensor, maps the value to a range of 0-100, and returns the processed value.
  3. Make a function that simulates a dice roll and returns a random number between 1 and 6.
  4. Write a struct-based function that returns both the minimum and maximum values found in an array of integers.
  5. Create a function that validates user input from the Serial monitor and returns different codes based on the validity.


If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)