答案 0 :(得分:4)
你的问题仍然有点不清楚(正如答案中各种各样的解释所表明的那样)。我假设你想通过物理引脚号来引用引脚。如果这不正确,请澄清您的问题,以便我们提供更好的答案。
免责声明:我没有对此进行测试,也没有特别注意检查文档。该代码是针对Linux上的avr-gcc / avr-libc编写的,尽管它可能在其他地方有用。
// Map from physical pin number to associated direction register.
volatile uint8_t *ddr_map[] = {
NULL, // Vcc, GND, or some other non-IO pin.
&DDRB,
&DDRB,
&DDRC,
// etc... Values will vary for different target chips.
};
// Map from physical pin number to port mask.
uint8_t mask_map[] = {
0x00,
_BV(0),
_BV(1),
_BV(0),
// etc... Values will vary for different target chips.
}
typedef enum {
IN,
OUT
} PinDir;
void setMode(int pin, PinDir dir) {
if(dir == OUT) {
*ddr_map[pin] |= mask_map[pin];
} else {
*ddr_map[pin] &= ~mask_map[pin];
}
}
请参阅http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_port_pass
它不抽象出任何有意义的行为(它实际上消除了抽象 - 物理引脚数低于逻辑端口/引脚)。而且,对于不同的封装格式,物理引脚号不一定相同。 PORTB的引脚可能不会被分配到QFP封装上与PDIP封装相同的物理引脚编号。因此,此代码实际上更多令人困惑。
增加了开销。你有一个额外的函数调用(需要花费周期和堆栈)和两个(或更多)用于查找的数组(除非你采取特殊措施,否则它们会花费AVR上的闪存和RAM,在这种情况下它们需要额外的周期和闪存或EEPROM)更不用说所有的间接(数组查找,指针解除引用)和额外的比较和分支。在台式机和网络开发你可以嘲笑我对这么小的成本的担忧,但在AVR上,浪费会产生更大的影响。 (注意:你或许可以说服编译器优化其中的一部分,但是如果你使用-Os
则会很困难。现在你担心甚至比以前更低级别的细节......)
提供的操纵销的方法并不复杂,值得以这种方式隐藏。你应该习惯在头脑中转换十六进制和二进制(这并不难)。即使您不想使用十六进制,_BV()
宏也可以使针脚操作变得非常简单(或者只使用(1 << x)
,这样更便携,并且会被更多程序员识别。)
顺便说一句,PORTB
,DDRB
等不是常量。它们是与特定地址或寄存器相关联的变量。尝试用CONST_THINGY |= 0x03
之类的东西修改常量会产生编译错误。
C没有您描述的功能。它是一种低级语言(有时被称为“高级程序集”),它不提供许多花哨的功能(按照今天的标准)。这就是为什么它是AVR的首选语言 - 你希望靠近硬件,而且你不需要额外的开销。
C有什么指针。根据你的问题和评论,我猜你不是很熟悉它们,所以这里有一个简单的解释:
&
运算符返回指向变量的指针,使用方式如下:pointer = &variable;
*
实际上有几个用途。
int *pointer;
请注意,您必须指定它将指向的变量类型。 / LI>
pointer
指向variable
,则*pointer = 42;
会将variable
设置为42,other_var = *pointer
会将other_var
设置为variable
的值}}。所有这一切的重点在于,您可以有效地将变量本身视为值,存储它们并传递它们。除了操纵它们的值之外,你无法以任何有意义的方式修改它们,但你也不需要。
答案 1 :(得分:3)
答案 2 :(得分:1)
答案 3 :(得分:1)
C具有宏功能,可以像这样使用
#define oof(a, b) a##b
int x1 = 5;
oof(x, 1) = 10;
printf("%d", x1); //prints 10
int oof(x, 2) = 2;
printf("%d", x2); //printf 2
它可以是一个函数,可以使用其他函数,可以调用其他宏,等等。 这里的“ ##”是预处理程序运算符,用于将其旁边的对象连接起来。
答案 4 :(得分:0)
答案 5 :(得分:0)
答案 6 :(得分:0)
答案 7 :(得分:0)
对于一般情况,指针尽可能接近。 C在运行时不一定具有任何名称概念,特别是在微控制器上(某些名称通常存在于具有动态链接的OS中,但即使在那里也不需要)。
对于引脚号方案,查找表以确定任何给定数字的端口,端口位等等都可以。这就是Arduino采用的技术,它试图在AVR上抽象出C ++编程。他们喜欢重命名,例如调用PWM信号“analogWrite”,C ++“接线”和程序“草图”,所有I / O引脚都在开发板上的位置后编号。缺点是,只要你编写第一块板以外的其他东西就会产生巨大的混乱,并且当你想要做一些低级别的事情时,必须弄清楚它们库里的副作用。