我面临的问题是让2个led一个接一个或同时发光。然而,它们一次只能单独工作一个。当我试图在同一个程序中实现这一点时,问题就来了。只有第一个LED开始过滤,而不是另一个。下面是我的代码:
#define GPFSEL1 0x20200004
#define GPFSEL2 0x20200008
#define GPSET0 0x2020001C
#define GPCLR0 0x20200028
#define SET_PIN18_OUTPUT (0x01 << 24) // GPFSEL1
#define SET_PIN23_OUTPUT (0x01 << 9) // GPFSEL2
#define SET_PIN24_OUTPUT (0x01 << 12) // GPFSEL2
#define SET_GPION(x) (0x01 << x)
#define CLEAR_GPION(x) (0x01 << x)
#define NUM_OF_LEDS 3
//-------------------------------------------------------------------------
typedef unsigned int* UINT32_P;
void dummy(volatile unsigned int val)
{
val++;
}
void setBit(unsigned int regAdd, unsigned char bit)
{
unsigned int temp;
temp = *(UINT32_P)(regAdd);
temp |= (0x1 << bit);
*(UINT32_P)(regAdd) = temp;
}
void clearBit(unsigned int regAdd, unsigned char bit)
{
unsigned int temp;
temp = *(UINT32_P)(regAdd);
temp &= ~(1 << bit);
*(UINT32_P)(regAdd) = temp;
}
int notmain ( void )
{
unsigned int ra;
setBit(GPFSEL1, 24); // Configure PIN 18 to output
setBit(GPFSEL2, 12); // Configure PIN 24 to output
while(1)
{
// L1 - -
setBit(GPSET0, 18);
setBit(GPSET0, 24);
for(ra=0;ra<0x100000;ra++) dummy(ra);
// - L2 -
setBit(GPCLR0, 18);
setBit(GPCLR0, 24);
for(ra=0;ra<0x100000;ra++) dummy(ra);
for(ra=0;ra<0x100000;ra++) dummy(ra);
}
return(0);
}
GPIO外设有单独的寄存器用于设置(GPSET0
)和清除(GPCLR0
)输出引脚,因此您不必进行读-修改-写操作。写入GPSET寄存器只设置为1的位,而0的位保持不变。写入GPCLR寄存器只清除为1的位,而为0的位保持不变。
您不应该使用setBit()
和clearBit()
例程来设置和清除GPIO输出。这些例程可能适用于没有单独寄存器来设置和清除位的其他外设。但是读-修改-写操作不适合GPSET0
和GPCLR0
。实际上,读-修改-写操作实际上可能是问题的根源。可能GPSET0
和GPCLR0
在读取它们时总是返回0x00000000,因为不需要读取它们。(我不敢肯定,我只是猜测。)
而不是调用setBit()
和clearBit()
来设置GPIO输出,你应该直接写入GPSET0
或GPCLR0
。在写入GPSET0
或GPCLR0
之前,您不需要读取它们。因为当你写入它们时,只有你设置为1的位会改变,你写为0的位会保持不变。
试试这样写:
// Set bits
*(UINT32_P)GPSET0 = (1 << 18);
*(UINT32_P)GPSET0 = (1 << 24);
// Clear bits
*(UINT32_P)GPCLR0 = (1 << 18);
*(UINT32_P)GPCLR0 = (1 << 24);
在notmain()
中不能调用clearBit()
,只能调用setBit()
。
类型:
typedef unsigned int* UINT32_P;
应该声明为:
typedef volatile unsigned int* UINT32_P;
我建议把你的地址定义为指针而不是整数:
#define GPFSEL1 ((UINT32_P)0x20200004)
#define GPFSEL2 ((UINT32_P)0x20200008)
#define GPSET0 ((UINT32_P)0x2020001C)
#define GPCLR0 ((UINT32_P)0x20200028)
set/clearBit接受UINT32_P类型而不是unsigned int类型。这样就不需要多次强制类型转换了。
BCM2835包含定时器硬件,您可以比"忙环"更好地利用。
每个GPIO引脚有3位选择一个功能。您只设置三个位中的一个,即最低的位,而保留上面的两个位。所以我的猜测是,在启动引脚18有功能0和引脚24有功能2(或左右)。然后将引脚18配置为功能1,因此它可以工作,但将引脚24配置为功能3,这不起作用。
你应该写一个函数"void setFunction(uint32_t pin, uint32_t fn)",根据引脚,加载GPFSEL0/GPFSEL1/GPFSEL2中的一个,屏蔽掉指定引脚的3位,或在fn中指定的3位,最后将其写回寄存器。
我发现的另一件事(上面已经提到过)是GPSET0/GPCLR0不需要读-修改-写。只需直接将您想要设置/清除的位写入它们即可。它不会影响任何其他位