通过通过类方法使用Wire.Onrequest

Using Wire.onRequest by passing a class method?

本文关键字:Wire Onrequest 类方法      更新时间:2023-10-16

我有一个Arduino草图,该草图将在Arduino Uno上工作,我正在尝试让Uno与Raspberry Pi通过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_listrongize。

所以我对如何处理这样的问题感到非常困惑?

你快到了。一般而言,您需要在C 中讲一个静态类方法以进行回调函数。

当您尝试访问类实例的成员 comm 时,您收到的错误是可以预期静态的。没有"此"的静态方法。

这是要考虑的众多技术之一,但是请使用C 类成员函数作为C回调函数阅读SO帖子。

无论如何,这里的方法是利用A 静态指针

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;

再次有很多方法可以解决这个问题,但上面是一个简单的问题,可能适合您的项目。如果您需要管理多个通信实例,则必须做一些完全不同的事情。

祝你好运!