如何解决Arduino IDE 学习创建自定义类对象
我在 Arduino 上使用 GSM 模块 SIM800,想学习如何为它创建我自己的自定义库。我一直在使用 TinyGSM 库并试图从中学习。我觉得这个库对于我的项目需求来说是 10 倍的矫枉过正,而且很难遵循,因为它有很多嵌套函数,这些函数不断地一遍又一遍地调用另一个函数,这使得几乎不可能遵循这段代码(至少对于像我这样的初学者程序员来说) ).
我想创建一个类构造函数,它允许我创建 GSM 模块对象,然后我可以使用这个对象来使用我在类中声明的任何函数。
从tinyGSM库中,我认为对象构造函数定义为:
public:
explicit TinyGsmSim800(Stream& stream) : stream(stream) {
memset(sockets,sizeof(sockets));
}
但是,我无法完全理解为什么以这种方式声明它?
- 为什么是流而不是串行?
- 那些套接字是什么,为什么要使用 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* serial 然后我将此变量分配给
_port = serial
但是在我的头文件中,_port 被声明为 Stream* 变量。这是如何工作的?
2.为什么我需要这样使用指针: 在我的源文件中:
custom_modem::custom_modem(HardwareSerial* serial)
在我的头文件中:
custom_modem(HardwareSerial* serial);
通过引用传递不是更好吗?使用 HardwareSerial& ? 有什么区别?指针正在杀死我,我不太了解它们
3.为什么我需要使用这个烦人的演员表?
static_cast<HardwareSerial*>(_port)->begin(115200,MODEM_TX);
如果我只是写:
_port.begin(115200,MODEM_TX);
如果您能帮我回答这些问题,我将不胜感激!谢谢
更新3
我为我的班级开发了一种发送 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;
}
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,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;
初始化它的正确方法是什么?
解决方法
首先,我建议您选择一个不错的 C++ 教程。这将对您有很大帮助,因为您目前正在为基本的语言概念(例如指针、引用、继承)而苦苦挣扎,并且如果不了解这些概念,您就无法真正做任何重要的事情。不能说我可以推荐任何最近的材料,但 Bruce Eckel 的免费“Thinking in C++”让我觉得是一本适合新手的书。它有点过时,因为它没有涵盖最新的标准 - C++11/14/17/20 - 但它很好地涵盖了语言基础。
-
如果您查看 code,HardwareSerial 继承自 Stream。这使得隐式(即编译器将在没有被告知的情况下执行此操作)将指向子类的指针转换为指向父类的指针成为可能。请注意,这会产生后果:未声明为 virtual 的函数将从父类调用,而不是从子类调用。
至于为什么 TinyGSM 使用 Stream 而不是 Serial - 它更通用。 GSM 模块可能还有其他通信通道——可能是软件模拟的 UART、USB 串行接口、SPI 总线或其他完全不同的东西。如果他们坚持更抽象的接口,他们将很容易地调整库代码以支持所有这些。
请注意,您不必这样做。使用HardwareSerial,会更容易。 -
学习指针,你不能没有 C 或 C++ 编程。我不解释,这是一个更长的故事。实际上,reference almost 是一个指针,只是使用起来稍微友好一些。随意在你的代码中使用引用,我当然会。请注意,初始化类的引用成员的方式不同:
custom_modem::custom_modem(HardwareSerial& serial)
: _port(serial)
{ }
- 需要强制转换,因为您通过指向父类的指针访问子类。正如我之前提到的,您还没有准备好解决这个问题,所以只需在您的类中使用 HardwareSerial 而不是 Stream。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。