0

我面临一个问题是让 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);
}
4

3 回答 3

3

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

您不应该使用您的setBit()clearBit()例程来设置和清除 GPIO 输出。这些例程可能适用于其他没有用于设置和清除位的单独寄存器的外围设备。但是 read-modify-write 操作不适用于GPSET0and GPCLR0。事实上,读-修改-写操作实际上可能是您问题的根源。可能是这样,GPSET0并且GPCLR0在您阅读它们时总是返回 0x00000000,因为永远不需要阅读它们。(我不确定,我只是推测。)

而不是调用setBit()clearBit()设置 GPIO 输出,您应该只写入GPSET0GPCLR0直接写入。您不需要阅读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);
于 2014-05-19T01:15:42.793 回答
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 而不是无符号整数。那么你就不需要大量的演员表了。

BCM2835包含比“忙循环”更好的定时器硬件。

于 2014-05-18T18:16:08.480 回答
0

每个 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 不需要读取-修改-写入。只需将您要设置/清除的位直接写入它们即可。它不会影响任何其他位。

于 2015-02-20T10:56:58.017 回答