我遇到一个问题,就是让2个LED一个接一个地或同时发光。但是,它们一次只能单独工作一个。当我试图在同一个程序中实现这个问题时,问题就来了。只有第一个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);
}
答案 0 :(得分:3)
GPIO外设具有单独的寄存器,用于设置(GPSET0
)和清除(GPCLR0
)输出引脚,因此您无需执行读 - 修改 - 写操作。写入GPSET寄存器仅设置为1的位,而0的位保持不变。写入GPCLR寄存器只会清除1的位,而0的位保持不变。
您不应该使用setBit()
和clearBit()
例程来设置和清除GPIO输出。这些例程可能适用于没有用于设置和清除位的单独寄存器的其他外设。但是,读取 - 修改 - 写入操作不适用于GPSET0
和GPCLR0
。事实上,读 - 修改 - 写操作实际上可能是您的问题的根源。可能是GPSET0
和GPCLR0
在读取它们时总是返回0x00000000,因为它们永远不必读取它们。 (我不确定,我只是猜测。)
您应该直接写入setBit()
或clearBit()
,而不是致电GPSET0
和GPCLR0
来设置GPIO输出。在写信之前,您无需阅读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);
答案 1 :(得分:1)
在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包括计时器硬件,你可以比#34; busy-loops&#34;更好地利用它。
答案 2 :(得分:0)
每个GPIO引脚有3位用于选择功能。您只设置三个位中的一个,即最低位,而仅保留高位两位。所以我的猜测是,在引导引脚18具有功能0而引脚24具有功能2(或左右)。然后将引脚18配置为功能1,因此它可以工作,但将引脚24配置为功能3,但不是。
你应该写一个函数&#34; void setFunction(uint32_t pin,uint32_t fn)&#34;根据引脚,加载GPFSEL0 / GPFSEL1 / GPFSEL2中的一个,屏蔽指定引脚的3位,在fn中指定的3位中的ors,最后将其写回寄存器。
我发现的另一件事,就是上面已经提到的,GPSET0 / GPCLR0不需要读 - 修改 - 写。只需直接写入要设置/清除的位即可。它不会影响任何其他位。