【发布时间】: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));
}
但是,我无法完全理解为什么以这种方式声明它?
- 为什么选择流而不是串行?
- 这些套接字是什么?为什么要使用 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