Calling void function arduino - arduino

I have written the following code:
void dice (int &x) {
for (int i = 0;i<7;i++){
delay (35);
int kocka;
kocka = random (1,7);
randomSeed (analogRead (A7));
delay(5);
}
}
void setup() {
Serial.begin(9600);
}
void loop() {
Serial.println(dice(int x));
};
However when I try to compile it, I get this error:
expected primary-expression before 'int'

You can call a void function, but for the argument you pass you don't put "int". You know this if you think about it, when you write a digitalWrite do you put "int" in front of the pin number? You only need the int when you are writing the function prototype.
You also don't have any variable x defined to pass to that function, so your next error is "x not declared in this scope" since in the loop function there is no x variable.
You have another problem lurking next. Your function is defined to return void. That means it returns nothing. And sure enough, there is no return statement. So when you remove the "int" in the Serial.print line, and define a variable x, you will get a "void value not ignored" error. You can't print the return value from a function that has no return value.
It isn't really clear what you want that to print out. Edit your question to say what you want to happen and maybe someone can help you figure out how to do it.

Related

Unexplainable behavior of .push_back for a vector<char> in functions

I am quite new to C++ and during solving a Codewars Kata I faced following problem.
I want to define a Variable of type std::vector with the name tmp2 in a function.
Add a char via push_back and return the value.
When I set a breakpoint at return(tmp2) and debug the code (MSVS2022), the debugger shows tmp2 as empty.
If I do the same operation in a void function the debugger shows tmp with 'c' as content
Here is my code:
#include <vector>
//turn on debugger
//set a breakpoint at return(tmp2) in function test2() and inspect tmp2
void test()
{
std::vector<char> tmp;
tmp.push_back('c'); //tmp holds 'c'
}
std::vector<char> test2()
{
std::vector<char> tmp2;
tmp2.push_back('c');
return(tmp2);//tmp2 does not contain 'c'
}
int main()
{
test();
std::vector<char> x = test2();
}
Could someone please tell me, where I am wrong?
Thanks in advance.
Regs
Marcus
I have tried to clean my project.
But I cannot find out where I am wrong.
An explanation would be very helpful.

How to use Arduino's Serial.print with char* and const char* types

I require to build a simple Arduino function that returns either "char*" or "const char*" type and then I need to print that value.
However, I'm facing a problem: when I try to print the function's return value, actually nothing gets printed.
char *getID()
{
char ID[15]{"123456789ABCDE"};
// The actual value for ID is returned from another
// function as a String type, so, for simplicity's sake
// I'm just using a random string instead of posting here that function
String str{"EDCBA987654321"};
// Write the String returned value into the ID buffer
str.toCharArray(ID,str.length());
// The following piece of code actually prints the value: EDCBA987654321
//Serial.println("print ID from inside the function: ");
//Serial.println(ID);
return ID;
}
void setup() {
Serial.begin(9600);
while(!Serial);
}
void loop() {
/**
* Nothing gets printed when using the return value from the function
*/
Serial.println("print id as the value returned by the \"getID\" function:");
Serial.println(getID());
delay(2000);
}
This is the output on the serial monitor:
If I uncomment the lines inside the "getID" function, then the "ID" value gets printed:
I don't know what am I missing over here.
Thanks in advance and happy holidays.
There are two solutions for this, it all related to the fundamental understanding of string literal and array in C++, not specific to Arduino.
This will work:
char *getID()
{
char *ID{"123456789ABCDE"};
return ID;
}
In C++, a string literal has global scope, a pointer to a string literal which has global scope is of course point to the correct string literal in the memory. This is equivalent to directly using a global declared const char *ID{"123456789ABCDE"};.
or alternative this will also work:
char *getID()
{
static char ID[15]{"123456789ABCDE"};
return ID;
}
The problem with your original code is that ID[15] is an array which has local scope within the function, it is not a string literal, but merely an array of ID[15]{"1", "2", "3"... "E"};. Another problem is that you are returning a pointer to an array which immediately out of the scope when return. Therefore you need the modifier static to keep the array in memory even after returning from the function.

Overloading function handling char and String

I'm making a function to handle a message, then print the message using Serial.println(). I have it working, but ran into an issue I can't explain. The first sample code below works, the second (swapping the order of my function declaration) will compile and load, but causes the Teensy 4.1 to crash. I'm using PlatformIO on VSCode.
Can anyone tell me what is wrong with the second code, and why it will compile without error, but not run?
This works:
#include <Arduino.h>
void LogMsg(const char *msg){
Serial.println(msg);
}
void LogMsg(String s){ LogMsg(s.c_str()); }
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
Serial.println("reset");
}
void loop() {
// put your main code here, to run repeatedly:
String str3 = "testing string cat ";
uint32_t var = 12345;
LogMsg(str3 + var);
delay(500);
}
This compiles, loads, but crashes, causing continuous resets:
#include <Arduino.h>
void LogMsg(String s){ LogMsg(s.c_str()); } // <-- swapped order
void LogMsg(const char *msg){ // <-- swapped order
Serial.println(msg);
}
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
Serial.println("reset");
}
void loop() {
// put your main code here, to run repeatedly:
String str3 = "testing string cat ";
uint32_t var = 12345;
LogMsg(str3 + var);
delay(500);
}
Edit: The definition of void LogMsg(String s) was changed to reflect error in original and the simplification suggested by #hcheung. Behavior remains the same. The first instance works, the second crashes.
C strings are terminated with '\0'. So toCharArray() will append a null character to your Ardunio String. Otherwise you would have to provide a length with the char pointer everytime you want to use that string.
Your char array must be big enough to fit this extra character or you will cause an access violation if toCharArray does not throw an exception first.

using an integer function return value to return a pointer

I am writing a serial command interpreter. The user will send a text string to the interpreter and it will do stuff and return an integer (either data or a code depending on what the user requested). But I want to expand the interpreter and allow the user to get an array of data or other structure in response to their query.
Can I use the integer return value to return a pointer to EEPROM (or global variable) address? And have the user follow the pointer to the memory location? Based on the query they sent, they would know if the return value is a pointer or data integer.
for example if I want to return
struct curve_t {
int type; // (2 bytes) calibration type indicator
int ref[2]; // (4 bytes) calibration reference point2
float param[11]; // (11*4 bytes) curve fitting parameters
} theCurve;
can I use a function like this?
int serialResponse(char * command) {
// interpret command here
return &theCurve;
}
Can you send a memory address through serial interface?
YES
Can your user access EEPROM through serial interface, using that address?
Not directly. Your MCU has to relay the data between your user and the EEPROM.
I wrote a small test program and confirmed that it is possible. I can pass the address from the function as an integer and then re-cast it in my calling function. It needs to address a global variable or at least on that is available in the calling function.
char res[10];
void loop {
b = function();
Serial.println((char *)b);
}
int function() {
return int(&res[0]);
}
I would not recommend casting a pointer into an integer because it won't work on computer architectures where an int has fewer bits than a pointer.
Lexical Parsers - like what you're writing - often arrange to return a token type, and place the token value in a union that the caller can access. The nice thing about structuring your code in that way is that it's extensible to whatever data types you want, and it will work no matter what C++ platform you're running on.
Here's an example of a token parser that can parse integers and your curve_t:
struct curve_t {
int type; // (2 bytes) calibration type indicator
int ref[2]; // (4 bytes) calibration reference point2
float param[11]; // (11*4 bytes) curve fitting parameters
};
union TokenValue {
int i; // type = TOKEN_TYPE_INT
struct curve_t *pCurve; // type = TOKEN_TYPE_P_CURVE
};
enum TokenType {
TOKEN_TYPE_UNKNOWN = 0,
TOKEN_TYPE_INT,
TOKEN_TYPE_P_CURVE
};
curve_t theCurve;
TokenValue tokenValue;
/*
* Parses the given command,
* setting the parsed value in tokenValue,
* returning the type of value (a TOKEN_TYPE_*).
*/
TokenType serialResponse(char * command) {
if (command[0] == 'a') { // TO DO: your code will test something else.
// We want to return an integer
tokenValue.i = 1234; // TO DO: in your code, instead set the integer value from command
return TOKEN_TYPE_INT;
}
if (command[0] == 'b') { // TO DO: your code will test something else.
// We want to return a pointer to theCurve.
// TO DO: Fill in the values of theCurve, for example theCurve.param[0]
tokenValue.pCurve = &theCurve;
return TOKEN_TYPE_P_CURVE;
}
// Else
return TOKEN_TYPE_UNKNOWN;
}
void setup() {
//TO DO: move this code to where it belongs in your Sketch
//TO DO: parse a command
char command[10] = "and so...";
// TO DO: read the command.
// Process the command
enum TokenType t;
t = serialResponse(command);
if (t == TOKEN_TYPE_INT) {
// The command result is an integer
int i = tokenValue.i;
// TO DO: process the integer.
} else if (t == TOKEN_TYPE_P_CURVE) {
// The command result is a curve
curve_t *pCurve = tokenValue.pCurve;
// TO DO: process the Curve.
} else {
// unrecognized command. TO DO: handle the error.
}
}
void loop() {
// put your main code here, to run repeatedly:
}
If you insist on using the cast of an int to a pointer (which I admit is a lot simpler), you could add a test for int size problems to your setup():
void setup() {
Serial.begin(9600);
if (sizeof(int) < sizeof(curve_t *)) {
Serial.println("cast won't work");
for (;;) {} // hang here forever.
}
}

Can't use attachInterrupt in a library

I'm writing a simple library for an ultrasonic distance sensor and thought i'd try using interrupts.
However i can't set my functions in the attachCallback method properly.
I want HCSR04Interrupt::echoHigh() and HCSR04Interrupt::echoLow() called when the pin goes high and low respectively.
I've Googled this to no avail. The Ardiuno IDE says the following:
./Arduino/libraries/HCSR04/HCSR04Interrupt.cpp: In member function 'void HCSR04Interrupt::getDistance()':
./Arduino/libraries/HCSR04/HCSR04Interrupt.cpp:31: error: argument of type 'void (HCSR04Interrupt::)()' does not match 'void (*)()'
./Arduino/libraries/HCSR04/HCSR04Interrupt.cpp: In member function 'void HCSR04Interrupt::echoHigh()':
./Arduino/libraries/HCSR04/HCSR04Interrupt.cpp:47: error: argument of type 'void (HCSR04Interrupt::)()' does not match 'void (*)()'
Here is my header:
#ifndef _HCSR04Interrupt_
#define _HCSR04Interrupt_
#include "Arduino.h"
#define HCSR04_CM_FACTOR 58.0
#define HCSR04_IN_FACTOR 148.0
#define HCSR04_CM_MODE 0
#define HCSR04_IN_MODE 1
class HCSR04Interrupt {
public:
double distance;
HCSR04Interrupt(int trigger_pin, int echo_pin, void (*callback)());
void setUnits(int units);
void getDistance();
private:
int _trigger_pin;
int _echo_pin;
int _units;
unsigned long _micros_start;
void (*_callback)();
void initialize();
void echoHigh();
void echoLow();
};
#endif
And my implementation (not complete since i cant get past the attachInterrupt step):
#include "Arduino.h"
#include "HCSR04Interrupt.h"
HCSR04Interrupt::HCSR04Interrupt(int trigger_pin, int echo_pin, void (*callback)()) {
_trigger_pin = trigger_pin;
_echo_pin = echo_pin;
_callback = callback;
initialize();
}
void HCSR04Interrupt::setUnits(int units) {
_units = units;
}
void HCSR04Interrupt::initialize() {
pinMode(_trigger_pin, OUTPUT);
pinMode(_echo_pin, INPUT);
digitalWrite(_trigger_pin, LOW);
}
void HCSR04Interrupt::getDistance() {
//Listen for the RISING interrupt
attachInterrupt(_echo_pin - 2, echoHigh, RISING);
//The trigger pin should be pulled high,
digitalWrite(_trigger_pin, HIGH);
//for 10 us.
delayMicroseconds(20);
//Then reset it.
digitalWrite(_trigger_pin, LOW);
}
void HCSR04Interrupt::echoHigh() {
_micros_start = micros();
detachInterrupt(_echo_pin - 2);
attachInterrupt(_echo_pin - 2, echoLow, FALLING);
}
void HCSR04Interrupt::echoLow() {
detachInterrupt(_echo_pin - 2);
unsigned long us = micros() - _micros_start;
distance = us;
(*_callback)();
}
So the compiler (not the IDE) tells you exactly what's wrong:
argument of type 'void (HCSR04Interrupt::)()' does not match 'void (*)()
So, while attachInterrupt() takes a function pointer of type void (*)(), you're trying to pass it a non-static member function, which you can't. You can try making the member function static and casting:
static void echoHigh();
// ...
attachInterrupt(_echo_pin - 2, reinterpret_cast<void (*)()>(&echoHigh), RISING);
Arduino interrupt handlers can only be functions. You are trying make method of an object an interrupt handler. Hence the compiler complains.
To be more precise about it, object methods are like functions, but it is as if they take a "hidden" parameter, which specifies the object instance. Therefore, they actually have different type signatures from plain functions. This disallows one to pass a method pointer when what a function is looking for is a plain function pointer.
The solution is to move your echoHigh() and echoLow() out of the HCSR04Interrupt class, and make them plain functions.
As I stumbled upon this question and it hasn't had an accepted answer, I write what I found, which worked for me:
The interrupt has to be called by a global wrapper. This wrapper needs to call a handleInterupt function of the class. Therefore it has to know the class. This can be done by storing it in a global variable. If multiple instances of the class should be used, multiple such global variables have to be used. But as the interrupt pins are just a few you can write a global variable and function for every pin:
MyClass theInstance_pin3 = NULL;
MyClass theInstance_pin7 = NULL;
// Somewhere, fill in an initialized copy of MyClass,
// and set theInstance_pin3 or theInstance_pin7 to it
void ISR_3()
{
if (theInstance_pin3)
theInstance_pin3->handleInterrupt();
}
void ISR_7()
{
if (theInstance_pin7)
theInstance_pin7->handleInterrupt();
}
as a reference see: http://forum.arduino.cc/index.php?topic=41713.0
or http://forum.arduino.cc/index.php?topic=160101.0
I got around this by making a singleton base class which represents the hardware as a whole (which kinda makes sense in this situation anyway).
Any function pointers can then be passed to the sub-component class, and handled by the singleton, whose member variables and methods are all static.
Example headers (untested):
// Sub-component
class LampButton {
public:
LampButton(int pin, void(*pushHandler)());
}
// Sub-component
class LampLed {
public:
LampLed(int pin);
void toggle();
}
// Singleton represents the hardware in it's entirety
class Lamp {
public:
// Call this instead of a constructor
static void initialize(int buttonPin, int ledPin);
// Function implemented inline for clarity - don't do this
static void handleButtonPush() {
led.toggle();
}
private:
static LampButton button;
static LampLed led;
}

Resources