具有结构返回类型的函数每第二次不返回

我正在编写一个程序来在ESP32(Arduino框架)中通过蓝牙接收SSID和密码。函数BTSerialRcvBuffer()等待蓝牙,当它接收到一个字符串时,它将通过struct Buffer_return类型的变量返回该字符串的基址和大小。该函数返回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,btrcv_buffer_size);

  while (!SerialBT.available());
  delaymicroseconds(500);

  while(SerialBT.available()) {
    rcv_buffer[i] = SerialBT.read();
    i++;
  }
  rcv_buffer[i-1] = '\0';
  rcv_buffer[i-2] = '\0';
  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
sunshengxia 回答:具有结构返回类型的函数每第二次不返回

代码使用以下顺序将输入数据复制到缓冲区。

  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的每个输入,不建议将malloc用于Arduino。最好使用自动分配。

另请参阅:https://arduino.stackexchange.com/questions/682/is-using-malloc-and-free-a-really-bad-idea-on-arduino

  char ssid[buff2->buff_len+1] ;
  strcpy(ssid,buff2->rtn_addr) ;

更新1:BTSerialRcvBuffer错误

BTSerialRcvBuffer对许多变量(包括i)使用静态变量。回想一下,静态变量一次初始化(在程序启动时)。建议从i中删除'static'-修复初始化,因为不需要使其变为静态。

还不清楚为什么rcv_buffer的最后2个位置重置为零?

,

您的代码中存在许多不良习惯和缓慢的函数调用。请记住,这是一个8位MCU,因此速度非常慢。一些要解决的问题:

  • 不必每次都将rx缓冲区归零。只需跟踪包含有效数据的部分大小即可。 256字节的memset调用非常昂贵。
  • 通常的做法是对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] = '\0';

  SerialBT.flush();

  *size_rec = i;
  return buf;
} 

具有双缓冲区的指针交换消除了对memcpy / strcpy的需求,它们既缓慢又昂贵。如果您使用UART中断,出于重新进入的原因,您将必须使用这样的设计。

您必须绝对避免的另一件事是mallocsee this缓慢而毫无意义。使用嵌入式系统时,必须始终使用固定长度的缓冲区和确定的内存量。摆脱malloc意味着您可以摆脱链接脚本中的整个堆段,这将释放大量宝贵的RAM。

本文链接:https://www.f2er.com/3126318.html

大家都在问