2

对于低级编程,有时有必要说,在给定的内存位置,这是我的地址所在的位置。对于这篇文章,示例是PIR1PIC16F886 和相关微控制器中的寄存器。它始终位于地址 0x000C。

我采用了这种方法:

#define pir1 (*(uint8_t*)0xc)

现在我可以用类似的东西分配给变量pir1 |= 0x40(好吧,我会使用#defined常量而不是幻数,但你明白我的意思)。这在 GCC 上编译得很好,即使我使用-Wextra -Wall. 为了检查我的假设,GCC 吐出了以下 x86_64:

movl    $12, %eax
movb    $64, (%rax)

正是我想要的(好吧,我现在确定为什么它是eax一个又rax一个,这可能是另一个愚蠢的 x86 怪癖,但无关紧要,因为无论如何我都想要 PIC14 代码)

现在,以 PIC14 为目标,我实际上使用的是 SDCC 编译器。我像这样调用它

sdcc --std-c99 -mpic14 -p16f886 --use-non-free source.c

上面以开头的代码#define给出了以下警告:

source.c:412: warning 88: cast of LITERAL value to 'generic' pointer
from type 'const-int literal'
to type 'unsigned-char generic* fixed'     

我试过这样做:

__code __at (0xc) uint8_t PIR1;

但这会导致错误消息

error 33: Attempt to assign value to a constant variable (=)

当我尝试分配任务时。

所以我的问题是我是否错过了在 C 中执行此操作的惯用方式?为什么 SDCC 会警告我?我在这里忽略了一些特定的 SDCC 特定的放克吗?

4

2 回答 2

4

关于警告,它可能是编译器中的错误。如前所述,您必须(volatile uint8_t*)0xc改为使用内存映射访问

SDCC 中绝对寻址的标准方法是通过编译器扩展,但您做错了。__code __at (0xc) uint8_t PIR1;将变量放在不可写的代码部分中。这就是您看到错误的原因error 33: Attempt to assign value to a constant variable (=)。请记住 PIC14 使用哈佛架构。如果地址在 RAM 中,则使用

volatile __data __at (0xc) uint8_t PIR1;

如果它在 xdata 中,则使用

volatile __xdata __at (0xc) uint8_t PIR1;

请参阅文档中的绝对寻址

在 Godbolt 上演示

于 2021-09-21T11:32:31.563 回答
1

“警告 88:将 LITERAL 值转换为‘通用’指针”似乎是误报。您的宏在语法或语言方面没有任何错误。C 标准明确允许此类转换,请参阅 C17 6.3.2.3/5:

整数可以转换为任何指针类型。除非前面指定,结果是实现定义的,可能没有正确对齐,可能不指向引用类型的实体,并且可能是陷阱表示。

(在这种情况下,对齐和陷阱无关紧要。)

一般来说,嵌入式系统编译器,特别是 PIC 编译器,在不符合标准 C 方面的声誉很差。因此,您要么必须弄清楚如何禁用损坏的警告,要么考虑使用不同的编译器。

与警告无关,您还有一个严重的错误,即缺少volatile. 我建议研究一下:如何从固件访问硬件寄存器?

于 2021-09-21T11:23:28.200 回答