09 - Language Functions

# Arduino Language Learning: Functions ## **🎯 What is a Function?** A **Function** is a reusable block of code that performs a specific task. Think of it like a recipe - you write the recipe once, but you can use it many times to cook the same dish. Functions help you organize code, avoid repetition, and make your programs easier to understand and maintain. ### **🚦 Simple Analogy** Think of functions like tools in a toolbox: - **Hammer**: You can use it to nail things, but you don't need to rebuild the hammer each time - **Screwdriver**: You can use it to turn screws, and it works the same way every time - **Calculator**: You can use it to do math, and it gives you the same result for the same inputs ### **📝 Basic Concept** Functions help you: - **Avoid code repetition** by writing once, using many times - **Organize your code** into logical, manageable pieces - **Make code more readable** and easier to understand - **Test individual parts** of your program separately - **Reuse code** across different projects ## **🔧 Function Syntax** ### **Basic Function Structure** ```cpp returnType functionName(parameter1, parameter2, ...) { // Function body - the code that does the work // Statements here return value; // Optional - only if function returns something } ``` ### **Function Parts Explained** - **returnType**: What type of data the function gives back (void, int, String, etc.) - **functionName**: The name you give to your function (use descriptive names) - **parameters**: Data the function needs to work with (optional) - **function body**: The actual code that does the work - **return statement**: Sends data back to where the function was called (optional) ### **Simple Example** ```cpp void sayHello() { Serial.println("Hello, World!"); } void setup() { Serial.begin(9600); sayHello(); // Call the function } void loop() { // Empty loop } ``` ## **📊 Types of Functions** ### **1. Functions with No Parameters and No Return Value** ```cpp void printMenu() { Serial.println("=== MENU ==="); Serial.println("1. Start"); Serial.println("2. Settings"); Serial.println("3. Help"); Serial.println("4. Exit"); } void setup() { Serial.begin(9600); printMenu(); // Call the function } void loop() { // Empty loop } ``` ### **2. Functions with Parameters but No Return Value** ```cpp void printNumber(int number) { Serial.print("The number is: "); Serial.println(number); } void printMessage(String message) { Serial.println(message); } void setup() { Serial.begin(9600); printNumber(42); // Call with parameter printMessage("Hello!"); // Call with different parameter } void loop() { // Empty loop } ``` ### **3. Functions with Parameters and Return Value** ```cpp int addNumbers(int a, int b) { int result = a + b; return result; } String getGreeting(String name) { String greeting = "Hello, " + name + "!"; return greeting; } void setup() { Serial.begin(9600); int sum = addNumbers(5, 3); Serial.print("Sum: "); Serial.println(sum); String message = getGreeting("Alice"); Serial.println(message); } void loop() { // Empty loop } ``` ### **4. Functions with No Parameters but Return Value** ```cpp int getRandomNumber() { return random(1, 101); // Returns random number 1-100 } String getCurrentTime() { unsigned long time = millis(); return "Time: " + String(time) + " ms"; } void setup() { Serial.begin(9600); int randomNum = getRandomNumber(); Serial.print("Random number: "); Serial.println(randomNum); String timeStr = getCurrentTime(); Serial.println(timeStr); } void loop() { // Empty loop } ``` ## **💡 Basic Function Examples** ### **Example 1: Simple Calculator Functions** ```cpp int add(int a, int b) { return a + b; } int subtract(int a, int b) { return a - b; } int multiply(int a, int b) { return a * b; } float divide(float a, float b) { if (b != 0) { return a / b; } else { return 0; // Return 0 if division by zero } } void setup() { Serial.begin(9600); Serial.println("Calculator Functions"); int result1 = add(10, 5); Serial.print("10 + 5 = "); Serial.println(result1); int result2 = subtract(10, 5); Serial.print("10 - 5 = "); Serial.println(result2); int result3 = multiply(10, 5); Serial.print("10 * 5 = "); Serial.println(result3); float result4 = divide(10, 5); Serial.print("10 / 5 = "); Serial.println(result4); } void loop() { // Empty loop } ``` ### **Example 2: String Processing Functions** ```cpp String reverseString(String text) { String reversed = ""; for (int i = text.length() - 1; i >= 0; i--) { reversed += text.charAt(i); } return reversed; } String toUpperCase(String text) { String upper = ""; for (int i = 0; i < text.length(); i++) { char c = text.charAt(i); if (c >= 'a' && c <= 'z') { c = c - 32; // Convert to uppercase } upper += c; } return upper; } int countVowels(String text) { int count = 0; String vowels = "aeiouAEIOU"; for (int i = 0; i < text.length(); i++) { char c = text.charAt(i); if (vowels.indexOf(c) != -1) { count++; } } return count; } void setup() { Serial.begin(9600); Serial.println("String Processing Functions"); String original = "Hello World"; String reversed = reverseString(original); Serial.print("Original: "); Serial.println(original); Serial.print("Reversed: "); Serial.println(reversed); String upper = toUpperCase(original); Serial.print("Uppercase: "); Serial.println(upper); int vowelCount = countVowels(original); Serial.print("Vowel count: "); Serial.println(vowelCount); } void loop() { // Empty loop } ``` ### **Example 3: Array Processing Functions** ```cpp void printArray(int arr[], int size) { Serial.print("Array: ["); for (int i = 0; i < size; i++) { Serial.print(arr[i]); if (i < size - 1) { Serial.print(", "); } } Serial.println("]"); } int findMax(int arr[], int size) { int max = arr[0]; for (int i = 1; i < size; i++) { if (arr[i] > max) { max = arr[i]; } } return max; } int findMin(int arr[], int size) { int min = arr[0]; for (int i = 1; i < size; i++) { if (arr[i] < min) { min = arr[i]; } } return min; } int calculateSum(int arr[], int size) { int sum = 0; for (int i = 0; i < size; i++) { sum += arr[i]; } return sum; } float calculateAverage(int arr[], int size) { int sum = calculateSum(arr, size); return (float)sum / size; } void setup() { Serial.begin(9600); Serial.println("Array Processing Functions"); int numbers[] = {5, 2, 8, 1, 9, 3}; int size = 6; printArray(numbers, size); int max = findMax(numbers, size); Serial.print("Maximum: "); Serial.println(max); int min = findMin(numbers, size); Serial.print("Minimum: "); Serial.println(min); int sum = calculateSum(numbers, size); Serial.print("Sum: "); Serial.println(sum); float average = calculateAverage(numbers, size); Serial.print("Average: "); Serial.println(average); } void loop() { // Empty loop } ``` ## **🎮 Advanced Function Examples** ### **Example 1: Recursive Functions** ```cpp int factorial(int n) { if (n <= 1) { return 1; } else { return n * factorial(n - 1); } } int fibonacci(int n) { if (n <= 1) { return n; } else { return fibonacci(n - 1) + fibonacci(n - 2); } } void countdown(int n) { if (n <= 0) { Serial.println("Blast off!"); } else { Serial.println(n); delay(1000); countdown(n - 1); } } void setup() { Serial.begin(9600); Serial.println("Recursive Functions"); int fact5 = factorial(5); Serial.print("5! = "); Serial.println(fact5); int fib10 = fibonacci(10); Serial.print("Fibonacci(10) = "); Serial.println(fib10); Serial.println("Countdown:"); countdown(5); } void loop() { // Empty loop } ``` ### **Example 2: Function Overloading (Different Parameter Types)** ```cpp void printValue(int value) { Serial.print("Integer: "); Serial.println(value); } void printValue(float value) { Serial.print("Float: "); Serial.println(value); } void printValue(String value) { Serial.print("String: "); Serial.println(value); } void printValue(int value1, int value2) { Serial.print("Two integers: "); Serial.print(value1); Serial.print(" and "); Serial.println(value2); } void setup() { Serial.begin(9600); Serial.println("Function Overloading"); printValue(42); // Calls printValue(int) printValue(3.14); // Calls printValue(float) printValue("Hello"); // Calls printValue(String) printValue(10, 20); // Calls printValue(int, int) } void loop() { // Empty loop } ``` ### **Example 3: Functions with Multiple Return Values (Using References)** ```cpp void getMinMax(int arr[], int size, int& min, int& max) { min = arr[0]; max = arr[0]; for (int i = 1; i < size; i++) { if (arr[i] < min) { min = arr[i]; } if (arr[i] > max) { max = arr[i]; } } } void swap(int& a, int& b) { int temp = a; a = b; b = temp; } void setup() { Serial.begin(9600); Serial.println("Functions with References"); int numbers[] = {5, 2, 8, 1, 9, 3}; int size = 6; int min, max; getMinMax(numbers, size, min, max); Serial.print("Minimum: "); Serial.println(min); Serial.print("Maximum: "); Serial.println(max); int x = 10, y = 20; Serial.print("Before swap: x="); Serial.print(x); Serial.print(", y="); Serial.println(y); swap(x, y); Serial.print("After swap: x="); Serial.print(x); Serial.print(", y="); Serial.println(y); } void loop() { // Empty loop } ``` ### **Example 4: Functions with Default Parameters** ```cpp void printStars(int count = 5) { for (int i = 0; i < count; i++) { Serial.print("*"); } Serial.println(); } void printBox(int width = 10, int height = 5, char symbol = '*') { for (int row = 0; row < height; row++) { for (int col = 0; col < width; col++) { Serial.print(symbol); } Serial.println(); } } void setup() { Serial.begin(9600); Serial.println("Functions with Default Parameters"); printStars(); // Uses default (5 stars) printStars(3); // Uses 3 stars printStars(10); // Uses 10 stars Serial.println(); printBox(); // Uses defaults (10x5 with *) Serial.println(); printBox(5, 3); // 5x3 with * Serial.println(); printBox(4, 4, '#'); // 4x4 with # } void loop() { // Empty loop } ``` ## **🔧 Functions with Different Data Types** ### **Example 1: Working with Different Return Types** ```cpp int getInteger() { return 42; } float getFloat() { return 3.14159; } String getString() { return "Hello from function!"; } bool getBoolean() { return true; } char getCharacter() { return 'A'; } void setup() { Serial.begin(9600); Serial.println("Different Return Types"); int num = getInteger(); Serial.print("Integer: "); Serial.println(num); float pi = getFloat(); Serial.print("Float: "); Serial.println(pi); String text = getString(); Serial.print("String: "); Serial.println(text); bool flag = getBoolean(); Serial.print("Boolean: "); Serial.println(flag); char letter = getCharacter(); Serial.print("Character: "); Serial.println(letter); } void loop() { // Empty loop } ``` ### **Example 2: Functions with Arrays** ```cpp void fillArray(int arr[], int size, int value) { for (int i = 0; i < size; i++) { arr[i] = value; } } void reverseArray(int arr[], int size) { for (int i = 0; i < size / 2; i++) { int temp = arr[i]; arr[i] = arr[size - 1 - i]; arr[size - 1 - i] = temp; } } void sortArray(int arr[], int size) { for (int i = 0; i < size - 1; i++) { for (int j = 0; j < size - i - 1; j++) { if (arr[j] > arr[j + 1]) { int temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; } } } } void setup() { Serial.begin(9600); Serial.println("Array Functions"); int numbers[5]; fillArray(numbers, 5, 0); Serial.println("Filled with zeros:"); for (int i = 0; i < 5; i++) { Serial.print(numbers[i]); Serial.print(" "); } Serial.println(); numbers[0] = 5; numbers[1] = 2; numbers[2] = 8; numbers[3] = 1; numbers[4] = 9; Serial.println("Original array:"); for (int i = 0; i < 5; i++) { Serial.print(numbers[i]); Serial.print(" "); } Serial.println(); reverseArray(numbers, 5); Serial.println("Reversed array:"); for (int i = 0; i < 5; i++) { Serial.print(numbers[i]); Serial.print(" "); } Serial.println(); sortArray(numbers, 5); Serial.println("Sorted array:"); for (int i = 0; i < 5; i++) { Serial.print(numbers[i]); Serial.print(" "); } Serial.println(); } void loop() { // Empty loop } ``` ## **📊 Functions in Loops and Control Structures** ### **Example 1: Functions in Loops** ```cpp bool isEven(int number) { return number % 2 == 0; } bool isPrime(int number) { if (number < 2) return false; for (int i = 2; i <= number / 2; i++) { if (number % i == 0) return false; } return true; } void printNumberInfo(int number) { Serial.print(number); Serial.print(": "); if (isEven(number)) { Serial.print("Even"); } else { Serial.print("Odd"); } if (isPrime(number)) { Serial.print(", Prime"); } Serial.println(); } void setup() { Serial.begin(9600); Serial.println("Functions in Loops"); for (int i = 1; i <= 20; i++) { printNumberInfo(i); } } void loop() { // Empty loop } ``` ### **Example 2: Functions with Conditional Logic** ```cpp String getGrade(int score) { if (score >= 90) { return "A"; } else if (score >= 80) { return "B"; } else if (score >= 70) { return "C"; } else if (score >= 60) { return "D"; } else { return "F"; } } String getWeatherAdvice(int temperature) { if (temperature > 30) { return "It's hot! Stay hydrated."; } else if (temperature > 20) { return "Nice weather! Enjoy the day."; } else if (temperature > 10) { return "It's cool. Wear a jacket."; } else { return "It's cold! Bundle up."; } } void setup() { Serial.begin(9600); Serial.println("Functions with Conditionals"); int scores[] = {95, 87, 72, 55, 100}; int temperatures[] = {35, 25, 15, 5}; Serial.println("Grades:"); for (int i = 0; i < 5; i++) { Serial.print("Score "); Serial.print(scores[i]); Serial.print(": Grade "); Serial.println(getGrade(scores[i])); } Serial.println("\nWeather Advice:"); for (int i = 0; i < 4; i++) { Serial.print(temperatures[i]); Serial.print("°C: "); Serial.println(getWeatherAdvice(temperatures[i])); } } void loop() { // Empty loop } ``` ## **⚠️ Common Mistakes and Tips** ### **Mistake 1: Forgetting Return Statement** ```cpp // Wrong - function should return int but doesn't int addNumbers(int a, int b) { int result = a + b; // Missing return statement! } // Correct - with return statement int addNumbers(int a, int b) { int result = a + b; return result; } ``` ### **Mistake 2: Wrong Return Type** ```cpp // Wrong - function declares int but returns String int getMessage() { return "Hello"; // Error! Can't return String from int function } // Correct - match return type String getMessage() { return "Hello"; } ``` ### **Mistake 3: Not Using Function Return Value** ```cpp // Wrong - ignoring return value int result = addNumbers(5, 3); // result is calculated but never used // Better - use the return value int result = addNumbers(5, 3); Serial.print("Result: "); Serial.println(result); ``` ### **Mistake 4: Too Many Parameters** ```cpp // Wrong - too many parameters make function hard to use void printInfo(String name, int age, String city, String country, String phone, String email) { // Function body } // Better - use structures or objects struct Person { String name; int age; String city; String country; String phone; String email; }; void printInfo(Person person) { // Function body } ``` ### **Mistake 5: Functions That Do Too Much** ```cpp // Wrong - function does too many things void processData() { // Read data // Validate data // Transform data // Save data // Send notification // Update display // Log activity } // Better - break into smaller functions void readData() { /* ... */ } void validateData() { /* ... */ } void transformData() { /* ... */ } void saveData() { /* ... */ } void sendNotification() { /* ... */ } void updateDisplay() { /* ... */ } void logActivity() { /* ... */ } void processData() { readData(); validateData(); transformData(); saveData(); sendNotification(); updateDisplay(); logActivity(); } ``` ## **🎯 Best Practices** ### **1. Use Descriptive Function Names** ```cpp // Good - descriptive names int calculateTotalPrice(int price, int tax) { return price + (price * tax / 100); } void displayUserMenu() { // Function body } bool isValidEmail(String email) { // Function body } // Avoid - unclear names int calc(int a, int b) { return a + b; } void doStuff() { // Function body } ``` ### **2. Keep Functions Small and Focused** ```cpp // Good - small, focused function int add(int a, int b) { return a + b; } // Avoid - function that does too much int processEverything(int a, int b) { // 50 lines of code doing multiple things return result; } ``` ### **3. Use Consistent Parameter Order** ```cpp // Good - consistent parameter order void printInfo(String name, int age, String city) { // Function body } void updateUser(String name, int age, String city) { // Function body } // Avoid - inconsistent parameter order void printInfo(String name, int age, String city) { // Function body } void updateUser(int age, String city, String name) { // Function body } ``` ### **4. Document Your Functions** ```cpp // Good - documented function /* * Calculates the factorial of a number * @param n: The number to calculate factorial for * @return: The factorial of n */ int factorial(int n) { if (n <= 1) { return 1; } else { return n * factorial(n - 1); } } // Avoid - undocumented function int fact(int n) { if (n <= 1) return 1; return n * fact(n - 1); } ``` ### **5. Use Default Parameters Wisely** ```cpp // Good - sensible defaults void printStars(int count = 5) { for (int i = 0; i < count; i++) { Serial.print("*"); } Serial.println(); } // Avoid - confusing defaults void printStars(int count = 42) { // Why 42? // Function body } ``` ## **🚀 Advanced Function Techniques** ### **Example 1: Function Pointers** ```cpp int add(int a, int b) { return a + b; } int subtract(int a, int b) { return a - b; } int multiply(int a, int b) { return a * b; } void setup() { Serial.begin(9600); Serial.println("Function Pointers"); // Function pointer int (*operation)(int, int); operation = add; Serial.print("Add: "); Serial.println(operation(10, 5)); operation = subtract; Serial.print("Subtract: "); Serial.println(operation(10, 5)); operation = multiply; Serial.print("Multiply: "); Serial.println(operation(10, 5)); } void loop() { // Empty loop } ``` ### **Example 2: Inline Functions** ```cpp inline int square(int x) { return x * x; } inline int cube(int x) { return x * x * x; } void setup() { Serial.begin(9600); Serial.println("Inline Functions"); int num = 5; Serial.print("Square of "); Serial.print(num); Serial.print(": "); Serial.println(square(num)); Serial.print("Cube of "); Serial.print(num); Serial.print(": "); Serial.println(cube(num)); } void loop() { // Empty loop } ``` ### **Example 3: Template-like Functions with Different Types** ```cpp template<typename T> T getMax(T a, T b) { return (a > b) ? a : b; } void setup() { Serial.begin(9600); Serial.println("Template-like Functions"); int maxInt = getMax(10, 20); Serial.print("Max int: "); Serial.println(maxInt); float maxFloat = getMax(3.14, 2.71); Serial.print("Max float: "); Serial.println(maxFloat); } void loop() { // Empty loop } ``` ## **📚 Summary** ### **Key Points:** 1. **Functions** are reusable blocks of code that perform specific tasks 2. **Parameters** pass data into functions 3. **Return values** send data back from functions 4. **Function names** should be descriptive and clear 5. **Functions** help organize and modularize code ### **Function Types:** - **No parameters, no return**: `void functionName()` - **With parameters, no return**: `void functionName(int param)` - **With parameters and return**: `int functionName(int param)` - **No parameters, with return**: `int functionName()` ### **When to Use Functions:** - **Repeated code**: When you use the same code multiple times - **Complex logic**: When a task is complex and needs organization - **Testing**: When you want to test parts of your program separately - **Readability**: When you want to make code easier to understand - **Maintenance**: When you want to make code easier to modify ### **Benefits:** - **Code reuse**: Write once, use many times - **Organization**: Break complex programs into manageable pieces - **Readability**: Make code easier to understand - **Testing**: Test individual parts separately - **Maintenance**: Easier to modify and debug ### **Best Practices:** - **Descriptive names**: Use clear, meaningful function names - **Single responsibility**: Each function should do one thing well - **Small size**: Keep functions small and focused - **Documentation**: Comment your functions - **Consistent style**: Use consistent parameter order and naming ### **Next Steps:** - **Practice**: Create functions for common tasks in your projects - **Experiment**: Try different parameter types and return values - **Combine**: Use functions with loops, conditionals, and arrays - **Explore**: Learn about advanced techniques like recursion and function pointers **Functions are essential building blocks in Arduino programming. They help you write cleaner, more organized, and more maintainable code!** 🚀⚙️✨