Arduino通过串口发送结构体

    Arduino的串口有两类发送的函数Serial.print()类和Serial.write()类,前者以Ascii码的形式将要发送的内容编码发送,所以我们最后接收并看到的是一个一个的ASCII码组合而成的数据,本质上成了字符串;后者则以字节形式直接发送原始数据,所以我们在串口接收工具看到的数据是乱码,它们在计算机中就是这样存储的。

    有些时候,我们可能会自己定义数据结构,比如结构体类型的数据。结构体由一些基本的数据类型组合而成,用户可以自由添加和安排其内容,但是在自己实验和查阅资料了解到,在单片机中和在电脑中定义的结构体有一些区别。我们以下面的结构体为例。

typedef struct sdata
{
    char  c;
    int16_t  i;
    float   f;
}sdata;

    如果按照Arduino的数据类型大小来算,为1+2+4=7,通过sizeof(sdata)验证后也为7;而如果这个结构体定义在linux操作系统下,用sizeof(sdata)算出来的结果为8,这涉及到计算机地址对齐的问题,具体请参考文章:http://blog.sina.com.cn/s/blog_5f77c7270100dnoy.html。知道了上面的问题,我们设计结构体就要注意,不同的数据类型顺序可能会导致不同的结构体大小,而我们在单片机如Arduino设计结构体时也要考虑对齐问题,比如将上面例子的char定义为二维数组char c[2],或者把char放到最后,这样即使我们接收时弄错了结构体大小,接到的数据也能够准确的放到结构体中。

    在Arduino中,print函数和write函数都无法直接发送结构体数据,因为结构体是用户自己的定义的,无法像其他数据那样有固定的格式或大小。所以我们必须将结构体转为字节数组,这样就可以通过write函数发送了,下面提供两种方法实现转换。

        方法一:使用memcpy函数,将结构体中的数据拷贝到一个字节数组中                   

sdata s;

......

byte b[sizeof(sdata)];
memcpy(b,&s,sizeof(sdata));
Serial.write(b,sizeof(sdata));

        方法二:用一个字节类型的指针强制指向结构体首地址
              

sdata s;

......

byte *tobyte=(byte*)&s;
Serial.write(tobyte,sizeof(sdata));

        两种方法在Arduino都测试过,都能成功发送。

        接收到这些数据时都是字节流,一般存储在缓冲字节数组中,如果想转换成原始的结构体,我们同样可以用memcpy,用法同上,只是源和目标换了位置。

        最后再说一点,如果结构体很大,数据很多,那么结构体没有赋值前数据是不确定的,为了避免不确定数带来的问题,我们该怎么初始化这个结构体呢?一条一条赋值可以,但是很麻烦。如果要求不高,把结构体内的数据全部置零也算是一种初始化吧,用memset函数可以将目标地址内的数据全部置为指定的数据。不知道还有没有其他更好的方法,如果有知道的希望能交流交流。

   

  • 7
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
以下是ESP32用Arduino语言将数据结构体存入Flash的示例代码: ```c++ #include <Preferences.h> // 定义一个数据结构体 struct DataStruct { int value1; float value2; char value3[20]; }; // 定义一个数据结构体实例 DataStruct myData; // 定义Preferences实例 Preferences preferences; // 存储数据到Flash中 void storeData() { preferences.begin("my-app", false); // 打开“my-app”命名空间 preferences.putBytes("data", &myData, sizeof(myData)); // 存储数据到Flash中 preferences.end(); // 关闭Preferences实例 } // 从Flash中读取数据 void loadData() { preferences.begin("my-app", true); // 打开“my-app”命名空间 size_t size = preferences.getBytesLength("data"); // 获取数据长度 preferences.getBytes("data", &myData, size); // 从Flash中读取数据 preferences.end(); // 关闭Preferences实例 } void setup() { // 初始化串口 Serial.begin(9600); // 将数据存储到Flash中 myData.value1 = 123; myData.value2 = 3.14; strcpy(myData.value3, "Hello, World!"); storeData(); // 从Flash中读取数据并输出 loadData(); Serial.print("Value 1: "); Serial.println(myData.value1); Serial.print("Value 2: "); Serial.println(myData.value2); Serial.print("Value 3: "); Serial.println(myData.value3); } void loop() { // do nothing } ``` 在这个示例代码中,我们首先定义了一个名为`DataStruct`的数据结构体,它包含了一个整型变量`value1`、一个浮点型变量`value2`以及一个字符数组`value3`。然后我们定义了一个`DataStruct`类型的实例`myData`。 在`storeData()`函数中,我们首先通过`preferences.begin()`函数打开`my-app`命名空间,并使用`preferences.putBytes()`函数将`myData`存储到Flash中。最后通过`preferences.end()`函数关闭Preferences实例。在`loadData()`函数中,我们首先通过`preferences.begin()`函数打开`my-app`命名空间,并使用`preferences.getBytesLength()`函数获取数据长度,然后使用`preferences.getBytes()`函数从Flash中读取数据并将其存储到`myData`中。最后通过`preferences.end()`函数关闭Preferences实例。 在`setup()`函数中,我们首先将串口初始化,并将一些数据存储到Flash中。然后从Flash中读取数据并通过串口输出。在`loop()`函数中,我们什么也不做。 注意,在ESP32的Arduino环境中,可以使用Preferences库来访问ESP32的EEPROM模拟器,实现类似于EEPROM的功能。然而,ESP32的EEPROM模拟器的大小也有限,不能存储过多的数据。如果需要存储大量的数据,建议使用外部存储器,如SD卡或Flash芯片。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值