You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Arduino中DS1307读取的uint8_t数组转unsigned long失败问题

问题原因分析

核心问题在于C语言字符串函数(包括strtoul)要求输入必须是以空字符'\0'结尾的合法C风格字符串,而你的两个数组在这一点上有本质区别:

  • 对于手动定义的savedData[10] = "123456789":字符串字面量"123456789"包含9个字符,编译器会自动在数组末尾补充一个'\0'作为终止符,刚好填满10个元素的数组,所以strtoul能正确识别并转换。
  • 对于从DS1307读取的readData[9]:你读取了9个字符"123456789",数组已经被完全填满,没有多余空间存储'\0'。当strtoul处理这个数组时,会一直向后内存查找终止符,而后续的内存内容是不确定的(大概率是非数字字符),导致函数直接返回0。

串口打印看起来正常是因为你手动循环打印了9个字符就停止了,但strtoul的行为是直到遇到'\0'才会停止解析。

解决方案

这里提供几种可行的解决办法,你可以根据需求选择:

方法1:扩大数组并手动添加终止符

修改readData的数组大小,预留一个位置存储'\0',读取完成后手动添加终止符:

uint8_t readData[10] = "0"; // 从9改为10,预留终止符位置
// ...
rtc.readnvram(readData,9,2); // 仍然读取9个字符到索引0-8
readData[9] = '\0'; // 手动添加字符串终止符
convertedL1 = strtoul((char *)&readData[0], NULL, 10); // 现在可以正常转换

方法2:自定义转换函数(无需依赖字符串终止符)

既然你已经明确知道读取的是9位数字,完全可以自己实现一个转换函数,不需要依赖strtoul对终止符的要求,更安全高效:

unsigned long convertDigitsToULong(uint8_t* digitArray, int length) {
  unsigned long result = 0;
  for (int i = 0; i < length; i++) {
    // 确保是合法数字字符
    if (digitArray[i] >= '0' && digitArray[i] <= '9') {
      result = result * 10 + (digitArray[i] - '0');
    } else {
      // 遇到非法字符可以选择返回0或抛出错误
      Serial.println("Invalid digit found!");
      return 0;
    }
  }
  return result;
}

// 在setup中调用
convertedL1 = convertDigitsToULong(readData, 9);

方法3:使用临时缓冲区

如果不想修改原数组大小,可以在转换前创建一个临时的带终止符的缓冲区:

char tempBuffer[10]; // 9位数字+1位终止符
memcpy(tempBuffer, readData, 9);
tempBuffer[9] = '\0';
convertedL1 = strtoul(tempBuffer, NULL, 10);
验证建议

你可以通过打印数组的每个元素的ASCII值来确认终止符的存在:

Serial.println("readData elements (ASCII):");
for (int i = 0; i < 10; i++) { // 注意这里循环到10,看第9位的内容
  Serial.print((int)readData[i]);
  Serial.print(" ");
}
Serial.println();

对于savedData,你会看到最后一位是0(即'\0'的ASCII值),而修改前的readData第9位是随机的垃圾值。

内容的提问来源于stack exchange,提问作者khanG

火山引擎 最新活动