首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >PIC18F45K42:如何将4个字节组合成Int?

PIC18F45K42:如何将4个字节组合成Int?
EN

Stack Overflow用户
提问于 2019-08-23 12:37:59
回答 1查看 849关注 0票数 2

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

我可以从卡片上读取数据并获得良好的结果,直到将表示.wav文件大小的4个字节组合起来为止。

代码语言:javascript
复制
#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 media\n\r");
if( SD_SPI_IsMediaPresent() == false)
{
    printf("No media\n\r");
    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("\n\r");
            printf("contents 4-7: %u %u %u %u", contents[4],contents[5],contents[6],contents[7]);
            printf("\n\r");
            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("\n\r");
            printf("Size: %u kB: %u", file_size, kb);
            printf("\n\r");
// . . . OMITTED . . .

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

代码语言:javascript
复制
Checking media
RIFF
contents 4-7: 4 122 18 0
00000000000100100111101000000100
Size: 31254 kB: 0

该二进制文件为文件大小提供了正确的数字,1210884,所以我试图通过合并字节获得的大小是错误的。我想这是因为我收到了以下的编辑警告:

代码语言:javascript
复制
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知识是有限的,而且我也不能百分之百地确定这个位移位表达式在做什么。我的天真理解是,应该将contents[7]的最右边位移到32位整数的第24位,将contents[6]最右边的位移到第16位等等,不知怎么的,可能是因为某种数据类型问题,这是不正确的。但我当然不知道,我也不知道微芯片XC公司有哪些限制。

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

非常感谢你的寻找。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-08-23 12:57:49

一些基本的事情:

  • 在编写嵌入式系统程序时,永远不要使用默认类型的C。使用stdint.h代替。特别是char类型是有问题的,因为它具有实现定义的签名性。
  • 在8位MCU上对小整数类型进行算法是很困难的。至少,您必须知道Implicit type promotion rules
  • 32位算术在PIC上非常慢,在可能的情况下应该避免。在这种特殊情况下可能不是一个选择。
  • PIC是一个8苦的,有16位int.

如果这个问题得到解决,我们可以注意到,每一次转移都是错误的:

代码语言:javascript
复制
file_size = (contents[7] << 24) | (contents[6] << 16) | (contents[5] << 8) | contents[4];

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

代码语言:javascript
复制
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的转换将“签名扩展”该值。就像上面建议的那样,不要使用char。)

请注意,这会根据某些端点顺序(从7到4,无论在您的情况下意味着什么)将数据排序到uint32_t中,这可能是一个问题,特别是如果您在某些数据通信协议中删除了结果。理论上,8位比特没有使用endianess,尽管在实践中,只要在核心中有双累加器或16位索引寄存器之类的东西,它们就会使用。在这种情况下,PIC是小Endian。

还请注意,%u是假设unsigned int,一个16位类型的事先知情同意。要打印uint32_t,您应该使用intypes.h中的"%"PRIu32,尽管%lu也会工作。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57626510

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档