【问题标题】:PIC 18F45K42: How to combine 4 bytes to Int?PIC 18F45K42:如何将 4 个字节组合成 Int?
【发布时间】:2019-08-23 12:37:59
【问题描述】:

我正在为 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 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 . . .

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

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 个文件大小字节来获得正确的值。

非常感谢您的关注。

【问题讨论】:

  • 伦丁,没错。纯粹的黑客行为。我并不是要发布包含(unit32_t)s 的代码,我只是在编辑帖子以删除它们,然后有几个非常快速的响应。
  • 嗯,这似乎是错误,所以...?
  • 这样做 'file_size = ((unint32_t) contents[7]

标签: c embedded wav microchip pic18


【解决方案1】:

一些基本的东西:

  • 在对嵌入式系统进行编程时,切勿使用默认类型的 C。请改用stdint.hchar 类型尤其有问题,因为它具有实现定义的签名。
  • 在 8 位 MCU 上很难对小整数类型进行算术运算。至少,您必须知道Implicit type promotion rules
  • 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 是 Little Endian。

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

【讨论】:

  • 在您的解决方案中也是如此 - 如果内容仍然是 char 的数组,则如果它们已签名,则此操作无效。
  • @AnttiHaapala 为什么不呢,它们将“以某种实现定义的方式”转换为 uint32_t,这很可能意味着 2 的 compl 的二进制表示。 number 被视为无符号数。事实上,我前几天阅读了 MPLAB 编译器手册,所以我很确定这正是发生的事情。
  • 哦,它甚至不是实现定义的,而是定义明确的。 6.3.1.3/2.
  • 有符号整数将通过模算术句点转换为无符号整数。这里绝对不是你想要的。
  • @AnttiHaapala "否则,如果新类型是无符号的,则在新类型可以表示的最大值的基础上反复加减一,直到值在范围内新型的。”这很好,因为 char 中的数据一开始就是原始二进制文件。
猜你喜欢
  • 2022-06-17
  • 1970-01-01
  • 2012-09-10
  • 2016-06-02
  • 1970-01-01
  • 1970-01-01
  • 2019-11-19
  • 2011-02-19
  • 2013-04-19
相关资源
最近更新 更多