C语言 PIC 18F45K42:如何将 4 个字节组合到 Int?



我正在为 PIC 18F45K42 编写代码以从 HCSD 卡读取.wav文件。我正在使用 MPLAB X IDE v5.20 和 XC v2.05。我正在使用 FATF 库从卡上读取数据。

我可以从卡上读取数据并获得良好的结果,直到合并代表.wav文件大小的 4 个字节。

#define BYTE_TO_BINARY_PATTERN "%c%c%c%c%c%c%c%c"
#define BYTE_TO_BINARY(byte)  
(byte & 0x80 ? '1' : '0'), 
(byte & 0x40 ? '1' : '0'), 
(byte & 0x20 ? '1' : '0'), 
(byte & 0x10 ? '1' : '0'), 
(byte & 0x08 ? '1' : '0'), 
(byte & 0x04 ? '1' : '0'), 
(byte & 0x02 ? '1' : '0'), 
(byte & 0x01 ? '1' : '0') 
UINT actualLength;
UINT br;
char contents[44]; // Buffer
uint32_t file_size;
char result;
printf("Checking medianr");
if( SD_SPI_IsMediaPresent() == false)
{
printf("No medianr");
return;
}
if (f_mount(&drive,"0:",1) == FR_OK)
{
if (f_open(&file, "P.WAV", FA_READ) == FR_OK){
result = f_read(&file, contents, 44, &br);
if ( result == FR_OK){
printf("%c%c%c%c", contents[0],contents[1],contents[2],contents[3]);
printf("nr");
printf("contents 4-7: %u %u %u %u", contents[4],contents[5],contents[6],contents[7]);
printf("nr");
printf(""BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(contents[7]));
printf(""BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(contents[6]));
printf(""BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(contents[5]));
printf(""BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(contents[4]));
file_size = (contents[7] << 24) | (contents[6] << 16) | (contents[5] << 8) | contents[4];
int kb = file_size/1024;
printf("nr");
printf("Size: %u kB: %u", file_size, kb);
printf("nr");
// . . . OMITTED . . .

我正在打印二进制文件,以确保从卡写入的数据是正确的。我得到的输出是

Checking media
RIFF
contents 4-7: 4 122 18 0
00000000000100100111101000000100
Size: 31254 kB: 0

该二进制文件为我提供了文件大小的正确数字,1210884,因此我通过尝试通过组合字节获得的大小是错误的。我认为这是因为我收到以下合规警告:

main.c:108:42: warning: shift count >= width of type [-Wshift-count-overflow]
file_size = (contents[7] << 24) | (contents[6] << 16) | (contents[5] << 8) | contents[4];
^  ~~
main.c:108:64: warning: shift count >= width of type [-Wshift-count-overflow]
file_size = (contents[7] << 24) | (contents[6] << 16) | (contents[5] << 8) | contents[4];

我已经搜索了这些警告并尝试了许多推荐的修复程序,但到目前为止,我还没有找到任何适用于这种情况的方法。我赶紧补充说,我的 C 知识是有限的,我不能 100% 确定位移表达式在做什么。我的天真理解是,contents[7]的最右边应该移动到 32 位整数的第 24 位,contents[6]最右边的位移动到第 16 位等,不知何故,可能是因为某种数据类型问题,这没有正确发生。但我当然不知道,我不确定Microchip XC编译器有什么限制。

除了建议我最终学习一门好的 C 课程之外,有人可以建议出了什么问题以及如何通过正确组装 4 个文件大小字节来获得正确的值。

非常感谢您的关注。

一些基本的东西:

  • 在对嵌入式系统进行编程时,切勿使用默认类型的 C。请改用stdint.h。特别是char类型是有问题的,因为它具有实现定义的符号。
  • 在 8 位 MCU 上对小整数类型进行算术很困难。至少,您必须了解隐式类型升级规则。
  • 32 位算术在 PIC 上非常慢,应尽可能避免使用。在这种特定情况下可能不是一种选择。
  • PIC是8苦的,有16位int

澄清了这一点后,我们可以注意到这些转变中的每一个都是错误的:

file_size = (contents[7] << 24) | (contents[6] << 16) | (contents[5] << 8) | contents[4];

contents[i]属于char类型(如果将代码固定为适当的类型,则uint8_t(。这是一个小整数类型。如上面的链接所述,它将通过整数提升隐式提升为int。这就是编译器给你警告的原因。您需要在移位之前将每个操作数转换为uint32

file_size = ( ((uint32_t)contents[7] & 0xFF) << 24) | 
( ((uint32_t)contents[6] & 0xFF) << 16) | 
( ((uint32_t)contents[5] & 0xFF) <<  8) | 
( ((uint32_t)contents[4] & 0xFF) <<  0) ;

(如果char是有符号的并且是负数,则0xFF的字节掩码是必要的,在这种情况下,转换为uint32_t将"符号扩展"值。TL;DR 只需按照上述建议远离char

请注意,这会根据某些字节序(从 7 到 4,无论您的情况是什么意思(将数据分类到uint32_t中,这可能是一个问题,特别是如果您将结果放入某些数据通信协议中。从理论上讲,8 苦味没有使用恩迪亚,但在实践中,只要你在核心中有双累加器或 16 位索引寄存器之类的东西,它们就会使用。在这种情况下,PIC是小端序。

另请注意,%u假设unsigned int,PIC 上的 16 位类型。要打印uint32_t,您应该使用 inttypes.h 中的"%"PRIu32,尽管%lu也可以使用。

最新更新