Arduino程序读取回混乱的数据
Arduino progmem reads back garbled data
我正在一个小型HTTP服务器上工作。我正在建造一个路由器,因为可能有很多路由,我想把它们放进闪存,这样我就不必使用有价值的SRAM。然而,要么我没有正确理解,要么发生了一些奇怪的事情,因为我似乎无法从闪存中读取存储的数据。
我有一个结构,它包含一个函数指针和一个字符指针。我想把这些结构的数组存储到flash中,然后读回来。然而,通过一个小的调试打印,我可以看到我无法正确地读回char指针。它将乱码打印到串行端口。
这里有一个小例子。
#include <avr/pgmspace.h>
typedef struct {
void (*func)();
const char *URI;
} Route;
void test1() {
Serial.println("Executed testfunc1");
}
void test2() {
Serial.println("Executed testfunc2");
}
const char route1URI[] PROGMEM = "/route1";
const Route route1 PROGMEM = {
test1,
route1URI
};
const char route2URI[] PROGMEM = "/route2";
const Route route2 PROGMEM = {
test2,
route2URI
};
const Route routingTable[] PROGMEM = {
route1,
route2
};
void (*getRoute(char *URI))() {
Route *r = (Route *)pgm_read_word(routingTable + 0);
char *f = (char *)pgm_read_word(r->URI);
Serial.println(f);
return r->func;
}
void setup() {
Serial.begin(9600);
while (!Serial) { }
Serial.println("started setup");
void (*fn)() = getRoute("sometest");
// will cause errors if called
//fn();
Serial.println("ended setup");
}
void loop() {
// put your main code here, to run repeatedly:
}
PROGMEM并不是那么容易使用。它可以稍微简化一点:
#include <avr/pgmspace.h>
struct Route {
void (*func)();
const char *URI;
};
void test1() {
Serial.println(F("Executed testfunc1")); // if you are using progmem, why not for string literals?
}
void test2() {
Serial.println(F("Executed testfunc2"));
}
const char route1URI[] PROGMEM = "/route1";
const char route2URI[] PROGMEM = "/route2";
const Route routingTable[] PROGMEM = {
{test1,route1URI},
{test2,route2URI}
};
void (*getRoute(char *URI))() {
Route r;
memcpy_P((void*)&r, routingTable, sizeof(r)); // read flash memory into the r space. (can be done by constructor too)
Serial.println((__FlashStringHelper*)r.URI); // it'll use progmem based print
// for comparing use: strcmp_P( URI, r.URI)
return r.func; // r.func is already pointer to the function
}
void setup() {
Serial.begin(57600);
while (!Serial) { }
Serial.println("started setup");
void (*fn)() = getRoute("sometest");
// will cause errors if called
//fn();
Serial.print((uint16_t)test1, HEX); Serial.print(' ');
Serial.print((uint16_t)test2, HEX); Serial.print(' ');
Serial.println((uint16_t)fn, HEX);
Serial.println("ended setup");
}
void loop() {
// put your main code here, to run repeatedly:
}
我想route1
和route2
可能会导致所有的问题,因为它是用来复制到routingTable
中的。如果像我一样初始化routingTable
的元素,它的工作效果会更好。CCD_ 5也有大量断裂。
无论如何,如果你有flash字符串,你也可以使用String str {(__FlashStringHelper*)r.URI};
,然后使用比较运算符:str == URI
:
#include <avr/pgmspace.h>
// get size of array[]
template<typename T, int size> int GetArrLength(T(&)[size]){return size;}
struct Route {
void (*func)();
const char *URI;
};
void test1() {
Serial.println(F("Executed testfunc1")); // if you are using progmem, why not for string literals?
}
void test2() {
Serial.println(F("Executed testfunc2"));
}
void test3() {
Serial.println(F("Executed testfunc3"));
}
const char route1URI[] PROGMEM = "/route1";
const char route2URI[] PROGMEM = "/route2";
const char route3URI[] PROGMEM = "/route3";
const Route routingTable[] PROGMEM = {
{test1,route1URI},
{test2,route2URI},
{test3,route3URI}
};
void (*getRoute(char *URI))() {
for (int8_t i = 0; i < GetArrLength(routingTable); ++i) {
Route r;
memcpy_P((void*)&r, routingTable+i, sizeof(r)); // read flash memory into the r space. (can be done by constructor too)
String uri {(__FlashStringHelper*)r.URI};
if (uri == URI) {
return r.func; // r.func is already pointer to the function
}
}
return nullptr;
}
void setup() {
Serial.begin(57600);
while (!Serial) { }
Serial.println("started setup");
void (*fn)() = getRoute("/route3");
// will cause errors if called
//fn();
Serial.print((uint16_t)test1, HEX); Serial.print(' ');
Serial.print((uint16_t)test2, HEX); Serial.print(' ');
Serial.print((uint16_t)test3, HEX); Serial.print(' ');
Serial.println((uint16_t)fn, HEX);
Serial.println("ended setup");
}
char *f = (char *)pgm_read_word(r->URI);
Serial.println(f);
f
是指向PROGMEM中的字符数组的指针,但Serial.println
不知道!它最终试图从RAM中读取字符串,而不是从RAM中。
Arduino Serial
库似乎不支持PROGMEM中的字符串。您需要在每次打印一个字符的字符串上循环,使用另一个库,或者将字符串存储在RAM中。
@KIIV指出,最好直接在routingTable
的声明中指定Route
。作为另一种解决方案,您可以将结构体Route
重新定义为
typedef struct {
void (*func)();
char URI[16]; //adjust the size to your need
} Route;
这样,从闪存读取URI
和function
地址可以通过对memcpy_P
的一次调用来完成。完整的代码:
typedef struct {
void (*func)();
char URI[16]; //adjust the size to your need
} Route;
void test1() {
Serial.println("Executed testfunc1");
}
void test2() {
Serial.println("Executed testfunc2");
}
const Route routingTable[] PROGMEM = {
{test1, "/route1"},
{test2, "/route2"}
};
void (*getRoute(char *URI, int idx))() {
Route r;
memcpy_P(&r, &routingTable[idx], sizeof(Route));
Serial.print(idx); Serial.println(". -----------------------------");
Serial.print("Route: "); Serial.println(r.URI);
Serial.print("fn address: "); Serial.println((uint16_t)r.func, HEX);
Serial.print("test1 address: "); Serial.println((uint16_t)test1, HEX);
Serial.print("test2 address: "); Serial.println((uint16_t)test2, HEX);
return r.func;
}
void setup() {
Serial.begin(9600);
while (!Serial) { }
Serial.println("started setup");
void (*fn)();
const int n = sizeof(routingTable) / sizeof(Route);
for (int i = 0; i < n; i++) {
fn = getRoute("sometest", i);
fn();
}
Serial.println("ended setup");
}
void loop() {
// put your main code here, to run repeatedly:
}
相关文章:
- 防止主数据类型C++的隐式转换
- 用于访问容器<T>数据成员的正确 API
- 嵌套在类中时无法设置成员数据
- 使用流处理接收到的数据
- 静态数据成员的问题-修复链接错误会导致编译器错误
- 处理小于cpu数据总线的数据类型.(c++转换为机器代码)
- 在cuda线程之间共享大量常量数据
- C++将文本文件中的数据读取到结构数组中
- 如何在C++中序列化结构数据
- 在C++中打印指向不同基元数据类型的指针的内存地址
- 通过套接字[TCP]传输数据 如何在C / C ++中打包多个整数并使用send() recv()传输数据
- 在c代码之间共享数据的最佳方式
- 链表,反向函数,数据结构
- 数据成员SFINAE的C++17测试:gcc vs clang
- C++浮点数据类型和字符串数据类型无法子到模板函数中
- 使用 C++ 从 Linux 串行端口读取会提供混乱的数据
- 堆数据混乱
- Arduino程序读取回混乱的数据
- 什么可能导致数据包的字节顺序部分混乱?
- wchar_t数据从非托管状态混乱到托管状态