【问题标题】:Arduino 1 not reading correctly the string from Serial MonitorArduino 1 未正确读取串行监视器中的字符串
【发布时间】:2016-03-12 14:48:10
【问题描述】:

我在使用 Arduino Uno 上的串行监视器时遇到问题。

基本上我想在串口监视器上写一些命令,读取字符串并根据字符串做一些事情。

问题如下:假设我在串行监视器中键入命令“读取 4”,有时字符串读取正确,有时读取为:“读取 4”,缺少第一个字符。 我什至在串行监视器的两个读数之间设置了延迟。有人解释一下吗?

为了完整起见,我发布了我的代码(基本上它从/向 EEPROM 读取/写入:例如,'read 5' 将读取 EEPROM 的 5 块,'write 4 5' 会将值 5 写入第 4 个块记忆)。

#define MAX_STRING_LENGTH 14
#include <ctype.h>
#include <EEPROM.h>


//The function initializes the string to spaces
void initString(char* mystr, char strLength);

//The function returns true if it is a read operation, false otherwise
boolean isReadEEPROM(char *myStr, char strLength);

//The function returns true if it is a write operation, false otherwise
boolean isWriteEEPROM(char *myStr, char strLength);

//The function returns the EEPROM address from the string
unsigned int findAddress(char *myStr, char strLength);

char findValue(char *myStr, char strLength);

//Check the address range
boolean isAddressOk(unsigned int address);



void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);


}

void loop() {

  char pos = 0; 
  bool newDataFound = false;
  char serialStr[MAX_STRING_LENGTH];
  unsigned int address = 0;
  char val = 0;
  while(Serial.available()){
    val = Serial.read();

  }
  val = 0;
  initString(&serialStr[0], (char) MAX_STRING_LENGTH);
  while(Serial.available() && pos < MAX_STRING_LENGTH){
    serialStr[pos] = Serial.read();
    pos ++;
    newDataFound = true;
    delay(200);
  }
  if (newDataFound){
    Serial.print("New Command found: ");
    Serial.println(serialStr);
    address = 0;
    address = findAddress(&serialStr[0], MAX_STRING_LENGTH);

    if (isReadEEPROM(&serialStr[0], MAX_STRING_LENGTH) && isAddressOk(address)){
      Serial.println("Reading from EEPROM");
      Serial.print("Address is ");
      Serial.println(address);
      val = EEPROM.read(address);
      Serial.print("Value is: ");
      Serial.println( (uint8_t) val );
      Serial.println(" ");

    }
    else if (isWriteEEPROM(&serialStr[0], MAX_STRING_LENGTH) && isAddressOk(address)){
      Serial.println("Writing to EEPROM");
      Serial.print("Address is ");
      Serial.println(address);
      Serial.println(" ");

      val = findValue(&serialStr[0], MAX_STRING_LENGTH);
      EEPROM.write(address, val);

    }
    else{
      if (!isAddressOk(address)){
        Serial.write(address);
        Serial.println("Address out of range");
        Serial.println("");
      }
      Serial.println("Not recognized operation\n");
    }

   delay(2000);
    }
}

void initString(char* mystr, char strLength){
  for(char ii=0; ii<strLength; ii++){
    (*mystr) = ' ';
    mystr++;
  } 
}

//The function returns true if it is a read operation, false otherwise
boolean isReadEEPROM(char *myStr, char strLength){
  //The string should contain first the 'read' operation
  char expected[] = "read";

  int ii =0;

  while (ii<4){
    if ( *(myStr + ii) !=  expected[ii]){
      return false;
      Serial.println("Not a Read Operation\n");
    }
    ii++;
  }
  return true;
  Serial.println("Read Operation");
}

//The function returns true if it is a write operation, false otherwise
boolean isWriteEEPROM(char *myStr, char strLength){
  //The string should contain first the 'read' operation
  char expected[] = "write";
  int ii =0;

  while (ii<5){
    if ( *(myStr + ii) !=  expected[ii]){
      return false;
    }
    ii++;
  }
  return true;
}

//The function returns the EEPROM address from the string
unsigned int findAddress(char *myStr, char strLength){
    unsigned int address;
    char tmpStr[strLength];
    char strAddress[] = "    ";
    int ii = 0;
  while(ii< strLength){
   tmpStr[ii] = *(myStr+ii);
   ii++;
  }
  Serial.print("The address found is: ");
  Serial.println(strAddress);
  ii= 0;

  if (isReadEEPROM(myStr, strLength)){
      while (ii<=4){
          if (isdigit(*(myStr + 5 + ii))){
            strAddress[ii] = *(myStr + 5 + ii);
          }
          else{
            break;
          }
          ii++;
      }
      address = atoi(strAddress);
  }

else if(isWriteEEPROM(myStr, strLength)){
        while (ii<=4){
          if (isdigit(*(myStr + 6 + ii))){
            strAddress[ii] = *(myStr + 6 + ii);
          }
          else{
            break;
          }
          ii++;
        }
        address = atoi(strAddress);
}

else{
  address = 0;
  //Serial.println("Address not available in function 'findAddress'");
}
 return address;
}

//The function returns the value to be written to the EEPROM from the string
char findValue(char *myStr, char strLength){
  char val;
  char tmpStr[strLength];
  char strVal[] = "   ";
  int ii, idx = 0;
  while(ii< strLength){
   tmpStr[ii] = *(myStr+ii);
   ii++;
  }
  ii= 0;
 // first found the first digits corresponding to the address
  while (ii<=4){
      if (isdigit(*(myStr + 6 + ii))){
        ;//strAddress[ii] = *(myStr + 6 + ii);
      }
      else{
        ii++;
        break;
      }
      ii++;
  }
  // now find the value
  while (ii<=4+3){
      Serial.println(*(myStr + 6 + ii));

      if (isdigit(*(myStr + 6 + ii))){
        strVal[idx] = *(myStr + 6 + ii);
      }
      else{
        break;
      }
      ii++;
      idx++;
  }          
 Serial.print("original string: ");
 Serial.println(tmpStr);
 Serial.print("Value found: ");
 Serial.println(strVal);
 val = (char)atoi(strVal);
 return val;
}

boolean isAddressOk(unsigned int address){
  if (address < 1024 && address >= 0){
    return true;
  }
  else{
    return false;
  }
}

【问题讨论】:

    标签: arduino serial-port arduino-uno arduino-ide


    【解决方案1】:

    这个sn-p:

    char val=0;
    while(Serial.available()){
      val = Serial.read();
    }
    val = 0;
    

    只是消耗输入缓冲区中可能留下的任何字符。你也可以这样做:

    while (Serial.avaialble())
      Serial.read();
    

    下一个 while 循环不会等待整个命令。有时,它得到'r',然后没有及时得到'ead...'。他们将在下次执行loop 时出现,因此看起来缺少“r”。刚刚在之前的loop消费了。

    通过 USB 发送的内容(从串行监视器窗口)可能会有奇怪的延迟。

    要收集完整行,您应该保存字符直到收到'\n':

    for (;;) {
      if (Serial.available()) {
        char c = Serial.read();
        if (c == '\n')
          break;
        if (pos < MAX_LINE_LENGTH) {
          serialStr[pos] = c;
          pos ++;
        }
        newDataFound = true;
      }
    }
    

    delay 调用是完全没有必要的,因为for 循环会一直等到接收到“\n”字符(确保在串行监视器下拉菜单中选择“新行”或“NL 和 CR ' 被选中)。然后你就知道你已经阅读了该行中的所有字符。

    【讨论】:

    • 感谢您的回答。我有一个问题:我放了第一个循环来清理串行:有用吗?我尝试了你的解决方案:它似乎永远不会退出 for 循环:你确定 '\n' 是字符串的最后一个字符吗?
    • 这取决于您在“串行监视器”窗口中选择的内容。有一个下拉菜单可让您选择“无行尾”、“换行”、“回车”或“CR & LF”。 '\n' 字符是通用的“换行符”字符,是 Arduino 上的换行符。因此,您必须选择第二个或第四个选项,以便在“发送”行中输入的内容末尾发送一个“\n”。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多