stm32与树莓派串口通讯发送传感器读数
最近需要将机器人的传感器发送给树莓派,通过树莓派上的ROS工具包对数据记录和可视化。主要问题是如何把下位机的浮点数发送给上位机。
主要问题:
- 浮点数的存储
- 浮点数在物理地址上数据打包发送
- 上位机解析数据
浮点数的存储
浮点数在计算机内部采用16进制,以IEEE 754标准格式方式存储;
stm32将float存储在4字节的地址上。需要注意的是不同的计算机存储顺序不同,可分为大端存储和小端存储。
大端模式:指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中。
小端模式:指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中。
stm32F405是小端模式。
浮点数在物理地址上数据打包发送:
stm32串口发送数据是以字节的形式发送。所以需要实际读取float实际存储的四字节空间上的数据。多说一句,便于理解。在同一块计算机存储的物理地址上,根据不同的读取方式,比如按int 方式读取,按float方式读取,按double方式读取,相同的数据由于不同的读取方式读到的结果也不同。在数据传输过程中,只要压缩和读取的方式一样就保证了数据的完整性。
按字节读取float有两种方式:union 和 指针。个人比较喜欢指针,代码如下。
void send_float(UART_HandleTypeDef *huart, float value)
{
float data=value;
uint8_t * pr=NULL;
pr = (uint8_t *)&data;
for(uint8_t i =0;i<4;i++)
{
HAL_UART_Transmit(huart,pr+i,1,0x100);
}
}
每个数据包配有一个标识符用于解析辨识数据。需要注意的是,标识符的数据不能在发送数据的定义域内。否则会发生解析错误。
上位机解析数据
解析数据是将串口发送的字节重新整合识别为float。代码如下:
uint8_t buff[2];
int n;
uint8_t ucData;
static unsigned char ucRxBuffer[50];
static unsigned char ucRxCnt = 0;
while(1)
{
n = sp.read(buff, 1);
if (n < 1)
{
ROS_INFO("serial read error!");
}
ucData = buff[0];
ucRxBuffer[ucRxCnt++] = ucData;
if (ucRxBuffer[0] != 0x55 &&ucRxBuffer[0] != 0x56 &&ucRxBuffer[0] != 0x57) //数据头不对,则重新开始寻找数据头
//0x55 和 0x56数据为空间三自由度向量,0x57为标量。
{
ucRxCnt = 0;
}
if (ucRxBuffer[0] == 0x55 ||ucRxBuffer[0] == 0x56)
{
if(ucRxCnt >= 13)
{
switch (ucRxBuffer[0])
{
case 0x55:
/* code */
memcpy(&qrt_state.acc,&ucRxBuffer[1],12);
break;
case 0x56:
memcpy(&qrt_state.Angle,&ucRxBuffer[1],12);
break;
}
ucRxCnt = 0; //清空缓存区
}
}
if(ucRxBuffer[0] == 0x57)
{
if(ucRxCnt>=5)
{
switch (ucRxBuffer[0])
{
case 0x57:
/* code */
memcpy(&qrt_state.realDepth,&ucRxBuffer[1],4);
break;
}
ucRxCnt = 0; //清空缓存区
}
}
}
需要注意,缓存区的ucRxBuffer的大小不能过大,否则读取的数据有延迟。