如何通过串行终端检索数据而不破坏其在 GNU ARM 嵌入式中的基本价值?

How can I retrieve data through a serial terminal without corrupting its fundamental value in GNU ARM embedded?

我想知道是否有人可以帮助我发现这里的问题...

在我用于 STM32L 的 C++ 嵌入式程序中,我试图通过 CLI(或终端,或任何可以工作的方式)通过串行连接检索存储在 SD 卡上的二进制数据文件。到目前为止,我可以使用 FatFs f_read 函数很好地读取数据文件。它的内容存储在 f_read 缓冲区中,我可以在调试模式下对其进行验证。

但是,问题是我使用的 RTOS 要求传出数据采用 const char* 形式,所以我不得不以某种方式将元素转换为该类型。到目前为止,我一直在通过转换来做到这一点,但是,根据我用作 f_read 缓冲区的类型,这要么导致不打印任何内容,要么在通过串行连接传输时更改其基本十六进制值到我的 CPU 上的 CLI。

这是我的代码的执行部分。在这种情况下,我将缓冲区数据存储为 uint16_t,但我尝试了许多其他类型(char、BYTE、char*),其中 none 设法将数据传输到另一端没有被破坏。

FRESULT res;
FIL fsrc;
uint16_t buffer[512];
uint16_t bw = 0;

res = f_open(&fsrc, "zurn.dat", FA_READ | FA_OPEN_ALWAYS);  

res = f_read(&fsrc, buffer, sizeof buffer, &bw);                                      

//just printing the first few elements to see if it works
for(int i=0; i<10; i++){
     CLI_printMessage(ZString((const char*)buffer[i])); 
}

f_close(&fsrc);                                               

我必须强调,我要传输的是基本的十六进制值。一位用户已经友好地向我展示了如何让十六进制值的 ASCII 表示通过(我可能最终不得不诉诸于此),但是,如果有一种方法来维护它对我来说会更有用十六进制更重视自己。

为了进一步说明,例如:数据文件的前几个字符在 ASCII 中如下所示:Èì‰Jà©í,在十六进制中为:ecc8 8903 e04a a9ad。这是我在另一边需要的,而不是 ASCII 中的这个:ecc8 8903 e04a a9ad,这是十六进制的:6563 6338 2038 3930 3320 6530 3461 2061 3961 64.

一些进一步的想法: 我意识到问题可能出在演员表上。对于初学者,它给了我警告 "cast to pointer from integer of different size [-Wint-to-pointer-cast]"。我知道这是因为在 C++ 中指针默认为 16 位,因此 uint16_t 类型用于我的缓冲区。

我也试过将缓冲区中存储的数据复制到另一个变量,然后转换它。在大多数情况下,这会在调试级别显示正确的十六进制值,但会附加大量 ASCII 垃圾,对此我没有解释。我也试过将缓冲区数组大小减少到只有 8 个元素,但仍然没有区别。

答案也可能特定于我的 RTOS,它有许多我不完全理解的特殊类型,尽管它主要基于 FreeRTOS。如果你没有注意到我不是一个非常有经验的程序员...

此外,我正在使用 Eclipse IDE 和 GNU Arm 构建工具。

转换不能解决问题,也许您已经说明了为什么转换不好。


你需要这样的函数,

/* four 'nibbles' (nibble = 4 bits = one hex) is 16 bits. */
void int16ToString(char *buf[4], uint16_t val)
{
   static const char *lookup = "0123456789ABCDEF";
   buf[3] = lookup[val & 0xf]; /* write backwards or you need a copy of val */
   val = val >> 4;
   buf[2] = lookup[val & 0xf];
   val = val >> 4;
   buf[1] = lookup[val & 0xf];
   val = val >> 4;
   buf[0] = lookup[val & 0xf];
}

C 库等中有各种函数可以做类似的事情。显然,该例程需要一个 4 字节的缓冲区,并且它不会被例程终止。它只是为了演示需要发生什么。 sprintfsnprint 等和 itoa 等一样有用。


为什么需要这样的功能?因为对话有两个方面,他们可以(并且可能 interpret things differently)。一般来说,您可以传输低位 ascii 字符而不会产生任何影响。例如 'XON' 是可以嵌入数据流中的流控制字符。

如果您要通过 CLI 传输二进制数据,您需要 'clean it' 然后您需要 CLI uart 另一端的代码来撤消它。您可以只发送十六进制,然后转换回二进制。有更有效的方法可以做到这一点,例如 zmodem and base64 if the data is large or the link (CLI uart) is not reliable. A simple itoa() with a hexdump 在另一台主机上转换将传输适合调试传输的二进制文件。