无法使2个LED工作。 [覆盆子pi,裸金属]

时间:2014-05-18 09:10:14

标签: c embedded raspberry-pi bare-metal

我遇到一个问题,就是让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);
}

3 个答案:

答案 0 :(得分:3)

GPIO外设具有单独的寄存器,用于设置(GPSET0)和清除(GPCLR0)输出引脚,因此您无需执行读 - 修改 - 写操作。写入GPSET寄存器仅设置为1的位,而0的位保持不变。写入GPCLR寄存器只会清除1的位,而0的位保持不变。

您不应该使用setBit()clearBit()例程来设置和清除GPIO输出。这些例程可能适用于没有用于设置和清除位的单独寄存器的其他外设。但是,读取 - 修改 - 写入操作不适用于GPSET0GPCLR0。事实上,读 - 修改 - 写操作实际上可能是您的问题的根源。可能是GPSET0GPCLR0在读取它们时总是返回0x00000000,因为它们永远不必读取它们。 (我不确定,我只是猜测。)

您应该直接写入setBit()clearBit(),而不是致电GPSET0GPCLR0来设置GPIO输出。在写信之前,您无需阅读GPSET0GPCLR0。因为当你写入它们时,只有你设置为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不需要读 - 修改 - 写。只需直接写入要设置/清除的位即可。它不会影响任何其他位。