函数具有 return 类型的结构 return 每次调用时什么都没有
Function having return type of struct return nothing every second time its called
我正在编写一个程序,通过 ESP32(Arduino 框架)中的蓝牙接收 SSID 和密码。函数 BTSerialRcvBuffer() 等待蓝牙,当它接收到一个字符串时,它 returns 通过结构 Buffer_return 类型的变量获取字符串的基址和大小。函数 returns SSID 但不是密码。我不知道为什么?我是否必须为 Var.rtn_addr 分配内存或为变量 buff1 和 buff2 分配足够的内存?
#include <Arduino.h>
#include <stdlib.h>
#include <BluetoothSerial.h>
#include <WiFi.h>
#define btrcv_buffer_size 256
BluetoothSerial SerialBT;
typedef struct
{
char *rtn_addr;
int buff_len;
} Buffer_return;
Buffer_return* BTSerialRcvBuffer() {
static int i = 0;
static char rcv_buffer[ btrcv_buffer_size ];
static Buffer_return Var;
memset(rcv_buffer,0, btrcv_buffer_size);
while (!SerialBT.available());
delayMicroseconds(500);
while(SerialBT.available()) {
rcv_buffer[i] = SerialBT.read();
i++;
}
rcv_buffer[i-1] = '[=12=]';
rcv_buffer[i-2] = '[=12=]';
SerialBT.flush();
Var.rtn_addr = rcv_buffer; //<------------Do I have to allocate memory for Var.rtn_addr?
Var.buff_len = i-1;
return &Var;
}
void WiFiConfig() {
//WiFi.printDiag(Serial);
Serial.println("Enter SSID");
Buffer_return *buff1 = BTSerialRcvBuffer();
char *ssid = (char*) malloc((buff1->buff_len) * sizeof(char));
strcpy(ssid,buff1->rtn_addr);
Serial.println(ssid);
Serial.println("Enter Password");
Buffer_return *buff2 = BTSerialRcvBuffer();
char *pass = (char*) malloc((buff2->buff_len) * sizeof(char));
strcpy(pass,buff2->rtn_addr);
Serial.println(pass);
//Serial.println(buff2->buff_len);
free(ssid)
free(pass);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Establishing connection to WiFi..");
Serial.printf("Connection status: %d\n", WiFi.status());
}
}
void setup() {
Serial.begin(115200);
//WiFi.disconnect(true);
SerialBT.begin("ESP32_INO"); //Bluetooth device name
WiFi.mode(WIFI_STA);
Serial.println("The device started, now you can pair it with bluetooth!");
WiFiConfig();
Serial.println("Connected to network");
Serial.println(WiFi.macAddress());
Serial.println(WiFi.localIP());
}
void loop() {
}
输出:
Enter SSID
Airtel_5G <----- prints fine!
Enter Password
<----- Problem!
Establishing connection to WiFi..
Connection status: 6
Establishing connection to WiFi..
Connection status: 6
Establishing connection to WiFi..
Connection status: 6
代码使用以下序列将输入数据复制到缓冲区。
Buffer_return *buff1 = BTSerialRcvBuffer();
char *ssid = (char*) malloc((buff1->buff_len) * sizeof(char));
strcpy(ssid,buff1->rtn_addr);
回想一下,字符串以 NUL 结尾,因此分配必须包括额外的字节!。对 malloc 调用的简单更新:
char *ssid = (char*) malloc((buff1->buff_len+1) * sizeof(char));
根据@lundin 的输入,Arduino 不推荐使用 malloc。最好使用自动分配。
char ssid[buff2->buff_len+1] ;
strcpy(ssid, buff2->rtn_addr) ;
更新 1:BTSerialRcvBuffer 出错
BTSerialRcvBuffer
对许多变量使用静态,包括 i
。回想一下,静态变量只初始化一次(在程序启动时)。建议从 i
中删除 'static' - 以修复初始化,因为无需将其设为静态。
另外,不清楚为什么 rcv_buffer
的最后 2 个位置重置为零?
您的代码中有很多不良做法和缓慢的函数调用。请记住,这是一个 8 位 MCU,因此速度非常慢。一些需要解决的问题:
- 不必每次都将 rx 缓冲区清零。只需跟踪其中包含有效数据的部分大小即可。
memset
调用 256 字节非常昂贵。
- 通常的做法是双缓冲 rx 缓冲区,这样一个缓冲区可以同时用于接收,另一个用于解码。您不使用中断,所以这可能不是什么大问题。无论如何,256 字节是很多 RAM,因此如果您需要存储那么多数据,双缓冲可能需要更好的 MCU。无论如何,我将在下面使用双缓冲区示例来展示它是如何完成的。
-
delayMicroseconds(500);
除了挂起你的程序 500 毫秒之外没有任何意义。删除那个。
- 错误:您没有在接收期间检查缓冲区溢出。
#define BT_RXBUF_SIZE 256
const char* BTSerialReceive (size_t* size_rec)
{
static char buf1 [BT_RXBUF_SIZE];
static char buf2 [BT_RXBUF_SIZE];
static char* buf = buf1;
buf = (buf == buf1) ? buf2 : buf1; // swap rx buffers
while (!SerialBT.available())
;
size_t i=0;
for(; SerialBT.available() && i<BT_RXBUF_SIZE; i++)
{
buf[i] = SerialBT.read();
}
buf[i] = '[=10=]';
SerialBT.flush();
*size_rec = i;
return buf;
}
双缓冲区的指针交换消除了对 memcpy
/strcpy
的需要,后者既慢又昂贵。如果您使用 UART 中断,出于重入原因,您将不得不使用这样的设计。
你必须绝对避免的另一件事是malloc
。它缓慢且毫无意义,see this。使用嵌入式系统时,您必须始终使用固定长度的缓冲区和确定的内存量。摆脱掉 malloc
意味着您可以摆脱链接器脚本中的整个堆段,这将释放大量宝贵的 RAM。
我正在编写一个程序,通过 ESP32(Arduino 框架)中的蓝牙接收 SSID 和密码。函数 BTSerialRcvBuffer() 等待蓝牙,当它接收到一个字符串时,它 returns 通过结构 Buffer_return 类型的变量获取字符串的基址和大小。函数 returns SSID 但不是密码。我不知道为什么?我是否必须为 Var.rtn_addr 分配内存或为变量 buff1 和 buff2 分配足够的内存?
#include <Arduino.h>
#include <stdlib.h>
#include <BluetoothSerial.h>
#include <WiFi.h>
#define btrcv_buffer_size 256
BluetoothSerial SerialBT;
typedef struct
{
char *rtn_addr;
int buff_len;
} Buffer_return;
Buffer_return* BTSerialRcvBuffer() {
static int i = 0;
static char rcv_buffer[ btrcv_buffer_size ];
static Buffer_return Var;
memset(rcv_buffer,0, btrcv_buffer_size);
while (!SerialBT.available());
delayMicroseconds(500);
while(SerialBT.available()) {
rcv_buffer[i] = SerialBT.read();
i++;
}
rcv_buffer[i-1] = '[=12=]';
rcv_buffer[i-2] = '[=12=]';
SerialBT.flush();
Var.rtn_addr = rcv_buffer; //<------------Do I have to allocate memory for Var.rtn_addr?
Var.buff_len = i-1;
return &Var;
}
void WiFiConfig() {
//WiFi.printDiag(Serial);
Serial.println("Enter SSID");
Buffer_return *buff1 = BTSerialRcvBuffer();
char *ssid = (char*) malloc((buff1->buff_len) * sizeof(char));
strcpy(ssid,buff1->rtn_addr);
Serial.println(ssid);
Serial.println("Enter Password");
Buffer_return *buff2 = BTSerialRcvBuffer();
char *pass = (char*) malloc((buff2->buff_len) * sizeof(char));
strcpy(pass,buff2->rtn_addr);
Serial.println(pass);
//Serial.println(buff2->buff_len);
free(ssid)
free(pass);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Establishing connection to WiFi..");
Serial.printf("Connection status: %d\n", WiFi.status());
}
}
void setup() {
Serial.begin(115200);
//WiFi.disconnect(true);
SerialBT.begin("ESP32_INO"); //Bluetooth device name
WiFi.mode(WIFI_STA);
Serial.println("The device started, now you can pair it with bluetooth!");
WiFiConfig();
Serial.println("Connected to network");
Serial.println(WiFi.macAddress());
Serial.println(WiFi.localIP());
}
void loop() {
}
输出:
Enter SSID
Airtel_5G <----- prints fine!
Enter Password
<----- Problem!
Establishing connection to WiFi..
Connection status: 6
Establishing connection to WiFi..
Connection status: 6
Establishing connection to WiFi..
Connection status: 6
代码使用以下序列将输入数据复制到缓冲区。
Buffer_return *buff1 = BTSerialRcvBuffer();
char *ssid = (char*) malloc((buff1->buff_len) * sizeof(char));
strcpy(ssid,buff1->rtn_addr);
回想一下,字符串以 NUL 结尾,因此分配必须包括额外的字节!。对 malloc 调用的简单更新:
char *ssid = (char*) malloc((buff1->buff_len+1) * sizeof(char));
根据@lundin 的输入,Arduino 不推荐使用 malloc。最好使用自动分配。
char ssid[buff2->buff_len+1] ;
strcpy(ssid, buff2->rtn_addr) ;
更新 1:BTSerialRcvBuffer 出错
BTSerialRcvBuffer
对许多变量使用静态,包括 i
。回想一下,静态变量只初始化一次(在程序启动时)。建议从 i
中删除 'static' - 以修复初始化,因为无需将其设为静态。
另外,不清楚为什么 rcv_buffer
的最后 2 个位置重置为零?
您的代码中有很多不良做法和缓慢的函数调用。请记住,这是一个 8 位 MCU,因此速度非常慢。一些需要解决的问题:
- 不必每次都将 rx 缓冲区清零。只需跟踪其中包含有效数据的部分大小即可。
memset
调用 256 字节非常昂贵。 - 通常的做法是双缓冲 rx 缓冲区,这样一个缓冲区可以同时用于接收,另一个用于解码。您不使用中断,所以这可能不是什么大问题。无论如何,256 字节是很多 RAM,因此如果您需要存储那么多数据,双缓冲可能需要更好的 MCU。无论如何,我将在下面使用双缓冲区示例来展示它是如何完成的。
-
delayMicroseconds(500);
除了挂起你的程序 500 毫秒之外没有任何意义。删除那个。 - 错误:您没有在接收期间检查缓冲区溢出。
#define BT_RXBUF_SIZE 256
const char* BTSerialReceive (size_t* size_rec)
{
static char buf1 [BT_RXBUF_SIZE];
static char buf2 [BT_RXBUF_SIZE];
static char* buf = buf1;
buf = (buf == buf1) ? buf2 : buf1; // swap rx buffers
while (!SerialBT.available())
;
size_t i=0;
for(; SerialBT.available() && i<BT_RXBUF_SIZE; i++)
{
buf[i] = SerialBT.read();
}
buf[i] = '[=10=]';
SerialBT.flush();
*size_rec = i;
return buf;
}
双缓冲区的指针交换消除了对 memcpy
/strcpy
的需要,后者既慢又昂贵。如果您使用 UART 中断,出于重入原因,您将不得不使用这样的设计。
你必须绝对避免的另一件事是malloc
。它缓慢且毫无意义,see this。使用嵌入式系统时,您必须始终使用固定长度的缓冲区和确定的内存量。摆脱掉 malloc
意味着您可以摆脱链接器脚本中的整个堆段,这将释放大量宝贵的 RAM。