我有一个可以在Arduino UNO上工作的Arduino草图,我正试图让Uno通过i2c连接与树莓派进行通信。
问题是使用 wire.h 库,其中的方法Wire.onRequest
在我这样使用时可以正常工作。
#include <Wire.h>
#define COMM_DELAY 50
#define SLAVE_ADDRESS 0x04
int current_rule = 0;
void initI2c() {
// initialize i2c as slave
Wire.begin(SLAVE_ADDRESS);
// define callbacks for i2c communication
Wire.onReceive(receiveData);
}
// callback for received data
void receiveData(int byteCount) {
while (Wire.available()) {
current_rule = Wire.read();
}
}
但是当我尝试使用类方法获得此确切结果时,出现错误:
invalid use of non-static member function
(将Wire.onRequest(this->receiveData)
行标记为红色)
就像这样:
void (*funptr)();
typedef void (*Callback)(byte);
class Comm{
public:
int callback_list_size = 0;
bool option_debug;
byte option_address;
int option_comm_delay;
void(*callback_list[256]);
byte *rules;
// function for receiving data. raspberry -> arduino
// Whenever the master sends new data, this method will call the appropriate callback.
void receiveData()
{
byte data;
Serial.println("[INFO] Received new data from master");
while (Wire.available())
{
data = Wire.read();
}
for (int i = 0; i < callback_list_size; i++)
{
if (rules[i] == data){
funptr = callback_list[i];
funptr();
}
}
}
// function for sending data. Called when raspberry request data. arduino -> raspberry
// Whenever the master requests data, this method will be called. For now we don't need this but anyway.
void sendData(int s)
{
if (option_debug)
Serial.println("[INFO] Master requests data!");
}
/* Constructor that takes 3 parameters at max. Only the adress is mandatory others are optional and will be filled with default values
:address - adress of slave(arduino) - Example 0x04
:delay - a delay is needed because I2C clock is quite slow compared to the CPU clock - 50
:debug - for debug purposes if true debug info will be sent to Serial interface - true/false
*/
Comm(byte address, int delay = 50, bool debug = false)
{
option_address = address;
option_comm_delay = delay;
option_debug = debug;
if (debug)
Serial.println("[INFO] Comm Object Created!");
}
// Function needs to be called to initialize the communication channel.
void initI2c()
{
Wire.begin(option_address);
Wire.onReceive(this->sendData);
Wire.onRequest(this->receiveData);
if (option_debug)
Serial.println("[INFO] I2C channel initialized");
}
// Function to add new callback for a rule.
// This function returns id of passed callback
int addCallback(Callback func, byte rule)
{
callback_list_size++;
// Enlarge rules array to keep 1 more byte
byte *temp = new byte[callback_list_size]; // create new bigger array.
for (int i = 0; i + 1 < callback_list_size; i++) // reason fo i+1 is if callback_list_size is 1 than this is the first initializition so we don't need any copying.
{
temp[i] = rules[i]; // copy rules to newer array.
}
delete[] rules; // free old array memory.
rules = temp; // now rules points to new array.
callback_list[callback_list_size - 1] = &func;
rules[callback_list_size - 1] = rule;
return callback_list_size;
}
};
Comm *i2c_comm;
void loop()
{
}
void setup()
{
Serial.begin(9600);
initI2C();
}
void initI2C()
{
i2c_comm = new Comm(0x04, 50, true);
i2c_comm->initI2c();
//Callback Definitions
i2c_comm->addCallback(&rule_1, 0x01);
i2c_comm->addCallback(&rule_2, 0x02);
i2c_comm->addCallback(&rule_3, 0x03);
i2c_comm->addCallback(&rule_4, 0x04);
}
我还尝试将receiveData
方法设为静态。
但是在这种情况下,我会出现如下错误:
invalid use of member Com::callback_list_size in static member function
这对我来说很有意义,因为静态方法不会知道我在说哪个callback_list_size。
所以我对如何处理这样的问题感到很困惑?
答案 0 :(得分:0)
您快到了。一般来说,在C ++中,您需要为回调函数传递静态类方法。
将方法更改为静态后收到的错误是预期的,因为您正在尝试访问 Comm 类的实例的成员,而该操作无法在一种没有“ this”的静态方法。
这里是要考虑的许多技术之一,但是请阅读SO帖子Using a C++ class member function as a C callback function。
无论如何,这里的方法是利用指向实例的静态指针。
class Comm {
private:
static Comm* pSingletonInstance;
static void OnReceiveHandler() {
if (pSingletonInstance)
pSingletonInstance->receiveData();
}
static void OnSendHandler(int s) {
if (pSingletonInstance)
pSingletonInstance->sendData(s);
}
void initI2c() {
Comm::pSingletonInstance = this; // Assign the static singleton used in the static handlers.
Wire.onReceive(Comm::OnSendHandler);
Wire.onRequest(Comm::OnReceiveHandler);
Wire.begin(option_address);
}
}
// static initializer for the static member.
Comm* Comm::pSingletonInstance = 0;
同样有许多方法可以解决此问题,但以上方法很简单,很可能适合您的项目。如果需要管理Comm的多个实例,则必须做一些完全不同的事情。
祝你好运!