首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >为了提高可读性,重新定义PIC24的寄存器掩码是不好的做法吗?

为了提高可读性,重新定义PIC24的寄存器掩码是不好的做法吗?
EN

Stack Overflow用户
提问于 2020-01-14 21:56:33
回答 2查看 170关注 0票数 6

我对于使用PIC芯片还比较陌生,所以这可能是一个新手级的问题,但我正在尝试编写一个头文件,其中包括TRIS/ODC/INIT掩码,用于所有I/O端口。

在该芯片内置的PCB上,任何给定的组件都可能使用来自多个端口的引脚,并且可能有十几个单独的组件需要详细注释。例如,与特定SPI ADC模块的接口使用来自A、D和F端口的引脚。

在我看来,读者友好的编写方法似乎是按组件组织文件,这样,读者一眼就可以知道所使用的引脚是什么,它们是作为输入还是输出配置的,以及它们是如何初始化的。

例如,只显示TRIS掩码信息,下面是用于演示我所讲的内容的特定ADC模块的代码片段:

代码语言:javascript
运行
复制
#define PORTD_TRIS_MASK 0x00
#define PORTF_TRIS_MASK 0x00

// ...
// lots of hardware configuration stuff goes here
// ...

// ANALOG INPUT - THERMOCOUPLE 1
// Thermocouple ADC chip MAX31856 DNP communicates over SPI
// Accepts any type of thermocouple
// TC1_CS pulled high
// TC1_DRDY pulled high

#define TC1_MOSI    LATAbits.LATA14
#define TC1_MISO    PORTDbits.RD10
#define TC1_SCK     LATDbits.LATD11
#define TC1_CS      LATFbits.LATF6
#define TC1_DRDY    PORTFbits.RF7

#define TC1_MISO_SHIFT  1<<10
#define TC1_DRDY_SHIFT  1<<7

#define PORTD_TRIS_MASK ( PORTD_TRIS_MASK | TC1_MISO_SHIFT )
#define PORTF_TRIS_MASK ( PORTF_TRIS_MASK | TC1_DRDY_SHIFT )

上面的代码没有抛出任何错误,但是它确实抛出了一个警告:

代码语言:javascript
运行
复制
HardwareProfile.h:1173:0: warning: "PORTD_TRIS_MASK" redefined
HardwareProfile.h:1029:0: note: this is the location of the previous definition
HardwareProfile.h:1174:0: warning: "PORTF_TRIS_MASK" redefined
HardwareProfile.h:1095:0: note: this is the location of the previous definition

编译器抱怨它的事实在我看来,这可能不是鼓励行为,但对我来说,这似乎没有本质上的问题。我是不是遗漏了什么,或者这是否是一种合理的组织代码的方法,这样就可以将密码的配置细节保持在它们的定义附近?

或者,是否有一种更传统的方法来完成我想要完成的事情,以保持更广泛使用或可接受的可读性?

更新:

也许我在最初的帖子中不够清楚。它是这样构造的,因为头文件中有十几个这样的代码块。假设确实有13个这样的代码块,那么任何特定的掩码最初将被定义为0x00,并重新定义13次,其思想是每个重新定义都会添加与特定块相关的配置信息。

更新:

在回答关于如何使用这些宏的问题时,只需立即使用它们来配置端口中的所有引脚。在这个PIC24上,每个端口有16个引脚,每个引脚都有一个TRIS (数据方向控制)寄存器、ODC (开漏控制)寄存器和LAT (闩锁)寄存器,如果配置为输出,则需要一个初始值。按照惯例,一次写一位,16次是不鼓励的,而只写一次给整个端口。例如,考虑一个简化的情况,即有四个寄存器而不是16个寄存器。而不是写这个:

代码语言:javascript
运行
复制
// In source file
TRISABITS.TRISA0 = 1;
TRISABITS.TRISA1 = 1;
TRISABITS.TRISA2 = 0;
TRISABITS.TRISA3 = 0;

按照我的理解,这是一种传统的写法:

代码语言:javascript
运行
复制
// In header file
#define BIT_0_SHIFT ( 1<<0 )
#define BIT_1_SHIFT ( 1<<1 )
#define BIT_2_SHIFT ( 0<<2 )
#define BIT_3_SHIFT ( 0<<3 )
#define TRISA_MASK ( BIT_0_SHIFT | BIT_1_SHIFT | BIT_2_SHIFT | BIT_3_SHIFT )

// In source file
TRISA = TRISA_MASK;

关于可读性的另一个问题,我赞成这种结构的论点是,这个芯片上端口的组织方式在物理上是没有意义的。任何特定端口上的引脚不一定彼此接近或有序,并且没有单个设备(例如外部SPI模块)仅限于单个端口。按端口组织头文件意味着读取器需要滚动整个头文件以检查单个设备的配置,而按设备组织文件则允许在单个屏幕上清晰地看到整个设备的定义和配置。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-01-15 00:42:05

预处理器的工作方式与代码的工作方式不同。例如,考虑以下代码:

代码语言:javascript
运行
复制
int main(void)
{
    int A = (B+C);
    int B = (C+2);
    int C =  3;
    int x = A;
    return x;
}

这不起作用,因为B和C是在声明之前使用的。编译器的输出是:

代码语言:javascript
运行
复制
cc -Wall demo.c -o demo
demo.c:3:14: error: use of undeclared identifier 'B'
    int A = (B+C);
             ^
demo.c:3:16: error: use of undeclared identifier 'C'
    int A = (B+C);
               ^
demo.c:4:14: error: use of undeclared identifier 'C'
    int B = (C+2);
             ^

现在,使用#defines对A、B和C使用相同的方法:

代码语言:javascript
运行
复制
#define A (B+C)
#define B (C+2)
#define C  3

int main(void)
{
    int x = A;
    return x;
}

这一次,即使#define不正常,也没有警告或错误。当预处理器看到一个#define时,它只是将一个条目添加到它的字典中。因此,在阅读了字典中包含的三个#defines之后

代码语言:javascript
运行
复制
Search   Replacement
 Text       Text
--------------------
   A       (B+C)
   B       (C+2)
   C       3

注意,预处理器尚未计算替换文本。它只是存储文本。当预处理程序在代码中找到搜索项时,它将使用替换文本。所以这条线

代码语言:javascript
运行
复制
int x = A;

变成了

代码语言:javascript
运行
复制
int x = (B+C);

在执行替换之后,预处理器重新处理文本,以查看是否可以进行更多的替换。经过第二次扫描,我们有:

代码语言:javascript
运行
复制
int x = ((C+2)+3);

最后的结果是:

代码语言:javascript
运行
复制
int x = ((3 +2)+3);

大多数编译器都可以选择在预处理完成后输出代码。对于gcc或clang,使用-E选项查看预处理器输出。

好的,现在我们应该有足够的背景来回答你的问题。考虑以下定义:

代码语言:javascript
运行
复制
#define PORTD_TRIS_MASK 0x00
#define PORTD_TRIS_MASK ( PORTD_TRIS_MASK | TC1_MISO_SHIFT )
#define PORTD_TRIS_MASK ( PORTD_TRIS_MASK | SB1_DATA_SHIFT )

我们这里有三个主要问题:

替换文本没有被计算,因此位不是或d together.

  • Only,其中一个定义(最后一个)将保存在预处理器字典中。这就是发出警告的原因。预处理器告诉您,它已经为该搜索项设置了一个条目,它将丢弃先前的替换文本。

  • 当在代码中找到PORTD_TRIS_MASK时,预处理程序将其替换为( PORTD_TRIS_MASK | SB1_DATA_SHIFT )。然后,它重新开始,并再次找到PORTD_TRIS_MASK。结果是无限递归。幸运的是,预处理器对这些东西有保护,并且会停止。编译器稍后将生成一个错误。

解决方案是为每个组件创建唯一命名的定义:

代码语言:javascript
运行
复制
#define TRIS_MASK_D1 TC1_MISO_SHIFT
#define TRIS_MASK_F1 TC1_DRDY_SHIFT

#define TRIS_MASK_D2 SB1_DATA_SHIFT
#define TRIS_MASK_F2 0

然后把它们放在一起:

代码语言:javascript
运行
复制
#define PORTD_TRIS_MASK (TRIS_MASK_D1 | TRIS_MASK_D2 | ... | TRIS_MASK_D13)
#define PORTF_TRIS_MASK (TRIS_MASK_F1 | TRIS_MASK_F2 | ... | TRIS_MASK_F13)
票数 7
EN

Stack Overflow用户

发布于 2020-01-15 04:47:34

PORTD_TRIS_MASK这样的宏是由PIC在使用的微控制器基础上定义的。

我不建议您更改或重新定义这些宏。

相反,您可以做的是使用自己的宏来实现特定的功能。例如:

代码语言:javascript
运行
复制
#define TC1_MISO_SHIFT  1<<10
#define TC1_DRDY_SHIFT  1<<7

#define TC1_MISO_MASK ( PORTD_TRIS_MASK | TC1_MISO_SHIFT )
#define TCI_DRDY_MASK ( PORTF_TRIS_MASK | TC1_DRDY_SHIFT )
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59742345

复制
相关文章

相似问题

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