基于SPI在两块Arduino间传输浮点数的技术问题求助
解决Arduino SPI传输浮点数的重载调用错误及主从通信方案
嘿,我来帮你搞定这个SPI传输浮点数的问题,尤其是你碰到的那个重载调用错误~
先搞懂错误原因
你遇到的call of overloaded...错误,核心原因是Arduino的SPI库transfer()函数没有直接支持float类型的重载。默认情况下,transfer()只接受uint8_t(字节)、char或者uint16_t类型的参数,直接传float的话,编译器找不到对应的函数,就会报错。
解决方案:把浮点数拆成字节传输
float在Arduino里是4字节的(和uint32_t大小一致),我们可以用**共用体(union)**或者强制类型转换,把浮点数转换成字节数组,然后逐个字节传输,接收端再还原成float。
1. 静态值2.25的测试代码
先给你一套能跑通的主从测试代码,解决静态浮点数的传输问题:
主设备代码(比如Arduino Uno)
#include <SPI.h> #define SLAVE_SELECT_PIN 10 // 选通从设备的引脚 // 共用体:实现float和字节数组的互转 union FloatConverter { float floatVal; uint8_t byteArr[4]; }; void setup() { SPI.begin(); pinMode(SLAVE_SELECT_PIN, OUTPUT); Serial.begin(9600); digitalWrite(SLAVE_SELECT_PIN, HIGH); // 初始保持高电平,不选通从设备 } void loop() { FloatConverter sendData; sendData.floatVal = 2.25; // 要传输的静态浮点数 // 选通从设备,开始传输 digitalWrite(SLAVE_SELECT_PIN, LOW); // 逐个发送4个字节 for (int i = 0; i < 4; i++) { SPI.transfer(sendData.byteArr[i]); } digitalWrite(SLAVE_SELECT_PIN, HIGH); // 结束传输,取消选通 Serial.print("已发送浮点数:"); Serial.println(sendData.floatVal); delay(1000); }
从设备代码(另一台Arduino Uno)
#include <SPI.h> // 和主设备用一样的共用体 union FloatConverter { float floatVal; uint8_t byteArr[4]; }; void setup() { SPI.beginSlave(); // 初始化作为SPI从设备 Serial.begin(9600); } void loop() { FloatConverter recvData; // 逐个接收4个字节,发送空字节0x00触发接收 for (int i = 0; i < 4; i++) { recvData.byteArr[i] = SPI.transfer(0x00); } Serial.print("已接收浮点数:"); Serial.println(recvData.floatVal); delay(1000); }
拓展到主设备请求、从设备响应的模式
接下来适配你的最终需求:主设备发请求,从设备采集传感器数据再回传。只需要在上面的代码基础上做一点修改:
修改后的主设备代码
#include <SPI.h> #define SLAVE_SELECT_PIN 10 #define REQUEST_CMD 0x01 // 定义请求数据的指令码 union FloatConverter { float floatVal; uint8_t byteArr[4]; }; void setup() { SPI.begin(); pinMode(SLAVE_SELECT_PIN, OUTPUT); Serial.begin(9600); digitalWrite(SLAVE_SELECT_PIN, HIGH); } void loop() { FloatConverter recvSensorData; digitalWrite(SLAVE_SELECT_PIN, LOW); // 第一步:发送请求指令 SPI.transfer(REQUEST_CMD); // 第二步:接收从设备回传的4个字节 for (int i = 0; i < 4; i++) { recvSensorData.byteArr[i] = SPI.transfer(0x00); } digitalWrite(SLAVE_SELECT_PIN, HIGH); Serial.print("收到传感器数据:"); Serial.println(recvSensorData.floatVal); delay(1000); }
修改后的从设备代码
#include <SPI.h> #define REQUEST_CMD 0x01 union FloatConverter { float floatVal; uint8_t byteArr[4]; }; // 模拟线性位移传感器读取函数,实际替换成你的传感器代码 float readLinearSensor() { // 这里可以替换成你的传感器读取逻辑,比如用analogRead后转换为浮点数 return 3.75; // 模拟返回的传感器值 } void setup() { SPI.beginSlave(); Serial.begin(9600); } void loop() { // 先接收主设备的指令 uint8_t receivedCmd = SPI.transfer(0x00); if (receivedCmd == REQUEST_CMD) { // 采集传感器数据 FloatConverter sensorData; sensorData.floatVal = readLinearSensor(); // 回传数据给主设备 for (int i = 0; i < 4; i++) { SPI.transfer(sensorData.byteArr[i]); } Serial.print("已回传传感器数据:"); Serial.println(sensorData.floatVal); } }
额外注意事项
- SPI参数一致性:主从设备的SPI模式(CPOL、CPHA)、时钟速度必须一致,默认是
SPI_MODE0,如果修改了要两边同步。 - 字节序问题:Arduino都是小端序,所以直接按数组顺序传输即可,不用额外处理字节序转换。
- 精度排查:如果传输后浮点数精度不对,可以串口打印每个字节的十六进制值,对比发送和接收的字节是否完全一致,排查传输过程中的丢包问题。
内容的提问来源于stack exchange,提问作者mecheng6769
相关产品推荐
相关产品推荐

