【问题标题】:Arduino IDE learning to create a custom class objectArduino IDE 学习创建自定义类对象
【发布时间】:2021-04-14 06:06:20
【问题描述】:

我在 Arduino 上使用 GSM 模块 SIM800,并想学习如何为它创建自己的自定义库。我一直在使用 TinyGSM 库并尝试从中学习。我觉得这个库对于我的项目需求来说是 10 倍的杀伤力,而且很难遵循,因为它有很多嵌套函数,不断地调用另一个函数,这使得几乎不可能遵循这段代码(至少对于像我这样的初学者程序员来说) )。

我想创建一个类构造函数,它允许我创建 GSM 模块对象,然后我可以使用这个对象来使用我在类中声明的任何函数。

从 tinyGSM 库中,我认为对象构造函数定义为:

public:
  explicit TinyGsmSim800(Stream& stream) : stream(stream) {
    memset(sockets, 0, sizeof(sockets));
  }

但是,我无法完全理解为什么以这种方式声明它?

  1. 为什么选择流而不是串行?
  2. 这些套接字是什么?为什么要使用 memset?

这将是我要编写的第一个自定义库,我没有太多的课程经验,希望你们能帮助我。

我创建了一个 cpp 文件,我将在其中声明我的构造函数。我还想创建一个 send_AT_command 函数,我将在其中传递要发送到我的 GSM 调制解调器的 AT 命令字符串。有人可以帮助我了解如何正确构建构造函数以及如何在我的其他函数中进一步使用它吗?


#include "custom_modem.h"
#include "Arduino.h"


custom_modem :: custom_modem(Serial serial)
{

}

custom_modem :: send_AT_command(String command){

}

更新2

我已经取得了一些进展。我发现了另一个线程: Arduino: Calling serial.begin() on a Stream object

我已经根据我的需要进一步简化了它。

我的头文件:


#ifndef custom_modem_h
#define custom_modem_h

#include <Arduino.h>
#include <Stream.h>
#include <HardwareSerial.h>


#define MODEM_TX             27
#define MODEM_RX             26

 class custom_modem
 {
   public:
      custom_modem(HardwareSerial* serial);
      void start_modem();
      void send_AT_command(String command);

   private:
      Stream * _port;
       
//Stream& _serial;
 };


 #endif

我的源文件:

#include "custom_modem.h"
#include "Arduino.h"


custom_modem::custom_modem(HardwareSerial* serial)
{
    _port = serial;
}

void custom_modem::start_modem(){
    static_cast<HardwareSerial*>(_port)->begin(115200, SERIAL_8N1, MODEM_RX, MODEM_TX);
}

我现在可以创建一个类对象并且程序没有返回任何错误:

custom_modem modem(&SerialAT);

但是,这段代码给我带来了很多问题:

1.从源文件可以看出,我通过了 HardwareSerial* 串行,然后我将此变量分配给

_port = serial

但在我的头文件中,_port 被声明为 Stream* 变量。这是如何工作的?

2。为什么我需要这样使用指针: 在我的源文件中:

custom_modem::custom_modem(HardwareSerial* serial)

在我的头文件中:

custom_modem(HardwareSerial* serial);

通过引用传递不是更好吗?使用 HardwareSerial& ? 有什么不同?指针正在杀死我,我不太了解它们

3。为什么我需要使用这个烦人的演员表?

    static_cast<HardwareSerial*>(_port)->begin(115200, SERIAL_8N1, MODEM_RX, MODEM_TX);

如果我简单地写:

 _port.begin(115200, SERIAL_8N1, MODEM_RX, MODEM_TX);

它会给我一个错误。

如果您能帮我回答这些问题,我将不胜感激!谢谢

UPDATE3

我为我的班级开发了一种发送 AT 命令并返回答案的方法:

String custom_modem::send_AT_command()
{
    String return_message; // Crate a string to store a return message
    static_cast<HardwareSerial*>(_port)->write("AT"); // Write an "AT" message to serial device. Expecting to receive "OK"
    delay(1);
     while( static_cast<HardwareSerial*>(_port)->available())
       {
          char c = static_cast<HardwareSerial*>(_port)->read(); // Read character at a time
          return_message.concat(c); // append a string with the character
       }
    return return_message;
}

但是,当我在我的 arduino 代码中调用它时:

String answer;
void loop() {
  answer = modem.send_AT_command();
  Serial.print("answer=");
  Serial.println(answer);
  delay(2000);
  // put your main code here, to run repeatedly:

}

它似乎没有返回任何东西: Serial monitor image

我认为这可能是我实现 send_AT_command 函数的方式的问题?

UPDATE4

通过添加行终止符 /n/r 解决了 AT 命令问题。现在工作正常。

尝试通过引用 HardwareSerial 来初始化类时,我仍然遇到问题:

我的 cpp:

#include "Arduino.h"
#include "String.h"


custom_modem::custom_modem(HardwareSerial* serial)
{
    _port = serial;
}

void custom_modem::start_modem(){
    _port->begin(115200, SERIAL_8N1, MODEM_RX, MODEM_TX);
}


String custom_modem::send_AT_command()
{
    String return_message; // Crate a string to store a return message
    _port->write("AT\n\r"); // Write an "AT" message to serial device. Expecting to receive "OK"
    delay(1);
     while(_port->available())
       {
          char c = _port->read(); // Read character at a time
          return_message.concat(c); // append a string with the character
       }
    return return_message;
}

和标题:

#ifndef custom_modem_h
#define custom_modem_h

#include <Arduino.h>
#include <HardwareSerial.h>

#define MODEM_TX             27
#define MODEM_RX             26

 class custom_modem
 {
   public:
      custom_modem(HardwareSerial* serial);
      void start_modem();
      String send_AT_command();

   private:
      HardwareSerial* _port;
 };


 #endif

当我将类对象初始化为时,上面的代码有效:

#define SerialAT  Serial1
custom_modem modem(&SerialAT);

如果我想通过引用来使用 HardwareSerial,您能否说明我必须如何更改代码才能使其工作:

如果我同时更改 .cpp 和头文件:

HardwareSerial* serial

HardwareSerial& serial

它给了我一个错误。我相信这可能与我的头文件中的变量_port有关。:

 private:
      HardwareSerial* _port;

初始化它的正确方法是什么?

【问题讨论】:

  • Stream 是一个 Arduino API 基类,用于读取/解析和写入/打印类。 sockets 是一个数组,memset 立即将其初始化为零。你为什么不直接使用那个库?
  • 因为我无法理解其中的大部分内容,而且很难理解。可悲的是,图书馆社区不是很活跃,因此他们无法帮助我解决一些问题。我想我最好为 GSM 模块开发自己的小类,并准确地发送我想要的 AT 命令和我想要的命令。此外,这是学习如何编写自己的类库的绝佳机会
  • TinyGSM 库遵循 Arduino 网络 API。它的工作方式与 Arduino 以太网和 WiFi 库 EthernetClient/WiFiClient 相同。学习 Arduino 网络 API 绝对是值得的,而不是重新发明轮子
  • 令我沮丧的是,为了设置调制解调器,它必须通过 10 个不同的嵌套函数,而不是简单地调用 1。一个函数调用另一个函数,而另一个函数调用另一个函数并且它继续运行.我几乎觉得他们这样做只是为了一个目的,所以其他人将无法遵循代码或重用它。我不是经验丰富的程序员,但肯定不是最有效的方法
  • 它是一个高质量的 Arduino 库。它支持多种调制解调器类型,编译结果很小,因为编译器可以针对使用的调制解调器进行优化

标签: class constructor arduino gsm esp32


【解决方案1】:

首先,我建议您学习一本不错的 C++ 教程。这将对您有很大帮助,因为您目前正在为基本的语言概念(例如指针、引用、继承)而苦苦挣扎,如果不理解这些,您将无法真正做任何重要的事情。不能说我可以推荐任何最近的材料,但 Bruce Eckel 的免费“Thinking in C++”让我印象深刻,是一本适合新手的书。它有点过时了,因为它没有涵盖最新的标准 - C++11/14/17/20 - 但它很好地涵盖了语言基础知识。

  1. 如果您查看code,HardwareSerial 继承自 Stream。这使得隐式(即编译器会在不被告知的情况下执行此操作)将指向子类的指针转换为指向父类的指针成为可能。请注意,这会产生后果:未声明为 virtual 的函数将从父类调用,而不是从子类调用。
    至于为什么 TinyGSM 使用 Stream 而不是 Serial - 它更通用。 GSM 模块可以有其他通信通道——可能是软件模拟的 UART、USB 串行接口、SPI 总线或其他完全的东西。如果他们坚持更抽象的接口,他们将轻松调整库代码以支持所有这些。
    请注意,您不必这样做。使用HardwareSerial,会更简单。

  2. 学习指针,没有 C 或 C++ 就无法编程。我不会解释,这是一个更长的故事。实际上,参考 几乎 是一个指针,它使用起来稍微友好一些。随意在您的代码中使用引用,我当然会。请注意,初始化类的引用成员的方式不同:

custom_modem::custom_modem(HardwareSerial& serial)
: _port(serial)
{ }
  1. 需要强制转换,因为您通过指向父类的指针访问子类。正如我之前提到的,您还没有准备好解决这个问题,所以只需在您的课程中使用 HardwareSerial 而不是 Stream。

【讨论】:

  • 感谢您的回答。我已经更新了我的问题。请您从我最初的问题中检查 UPDATE4 吗?我在那里提出了一些关于初始化参考成员类的额外问题
  • 看我回答中的代码。这就是您必须初始化引用的类成员的方式。
  • 所以在这种情况下,我必须去掉头文件 Private: 中的 _port 变量声明。 private: HardwareSerial* _port;
  • 不,为什么?保持原样。只需更新构造函数定义。
  • 好的,当我删除 * 符号时,我能够毫无错误地编译代码:private: HardwareSerial _port;,而且,我将``` _port->write()`` 更改为port.write()
猜你喜欢
  • 1970-01-01
  • 2021-02-14
  • 2018-07-21
  • 2018-01-25
  • 2018-04-19
  • 1970-01-01
  • 1970-01-01
  • 2016-10-25
  • 1970-01-01
相关资源
最近更新 更多