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:
- Specify the data type the function will return (instead of
void
) - Include a
return
statement in the function body
Here's the basic structure:
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:
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 ofint
- It takes two parameters and returns their sum
- In
setup()
, we call the function and store its result in the variabletotal
Understanding Different Return Types
Arduino functions can return various data types:
Return Type | Description | Example Use Case |
---|---|---|
int | Integer values | Counting, whole number calculations |
float | Decimal values | Sensor readings, precise measurements |
bool | Boolean (true/false) | Function success, condition checking |
char | Single character | Menu selection, simple input |
String | Text string | Formatted messages, text processing |
Example with Different Return Types
// 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:
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:
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:
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
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:
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:
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
// 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
// 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
// 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
- Be Consistent: Use return values consistently for similar functions.
- Check Return Values: Always check return values that indicate success/failure.
- Document Your Return Values: Comment what different return values mean.
- Use Meaningful Return Types: Choose appropriate data types for what you're returning.
- 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
- Write a function that takes a temperature in Celsius and returns
true
if it's above a certain threshold, otherwisefalse
. - Create a function that reads an analog sensor, maps the value to a range of 0-100, and returns the processed value.
- Make a function that simulates a dice roll and returns a random number between 1 and 6.
- Write a struct-based function that returns both the minimum and maximum values found in an array of integers.
- 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! :)