首页 > 解决方案 > 无法打开或关闭绿色/蓝色 LED STM32F429ZI - Nucleo 板?

问题描述

我正在尝试编写一个裸机程序来闪烁绿色 LED。事实上,我无法打开或关闭任何 LED。这是一个现成的板。电路板名称为 NUCLEO F429ZI。 董事会形象

我已经浏览了原理图,我确定引脚是PA5端口 A 和引脚 5。但是,LED 根本不闪烁。我可以看到我的代码使用 uVision IDE 加载到 STM32 板上。

我曾尝试设置蓝色 LED 即 PB7,但这也根本不起作用。

void delayMs(int delay);

int main(void)
{
    //enable clock access to A
    RCC->AHB1ENR |= 1;  //enable GPIO A clock
    GPIOA->MODER |= 0x400; //       PA-5 01   0000 - PA0
    while(1)
    {
          GPIOA->ODR |= 0x20;
         //delay
          delayMs(100);
          GPIOA->ODR &=~ 0x20;
          delayMs(100);
    }

}

void delayMs(int delay)
{
    int i = 0;
    for(; delay >0; delay--)
    {
     for(i=0; i<3195; i++)
        {
        }
    }
}

STM32F429ZI 中的绿色 LED 应该闪烁。

接下来,我尝试打开同样不工作的蓝色 LED。根据我通过查看原理图的理解 - PB7 应该为蓝色 LED 打开。但这也行不通。

#include "stm32f4xx.h"
int main(void)
{
    RCC->AHB1ENR |= 1;
    // ob 01 00 00 00 00 00 00 00 // PB7
    GPIOB->MODER = 0x4000;
    for(;;)
    {
        GPIOB->ODR = 0x80;
    }
}

标签: cembedded

解决方案


相当无益的是, https: //www.st.com/en/evaluation-tools/nucleo-f429zi.html#resource 上的 Nucleo F429ZI UM1974 用户手册下载链接似乎已损坏(在撰写本文时),但我发现了一个在别处复制,三个用户 LED 的引脚分配如下所述:

在此处输入图像描述

示意图表明,焊桥 SB120 和 SB119 的出厂状态设置为 PB0 上的 LD1,而不是 PA5。您尝试设置 LD2(蓝色)的问题在于您没有在 RCC 中启用 GPIOB - 它启用了 GPIOA,就像在 LD1(绿色)尝试中一样。

另一个问题是您的 GPIO MODER 设置假定端口的复位状态为零。情况并非如此(尽管它适用于有问题的特定引脚 - 所以在这种情况下你“摆脱它”):

在此处输入图像描述

在一个地方定义所有端口/引脚特定常量是一个好主意,这样您就可以轻松切换或添加输出,并且出错的机会更少:

#define LED_PORT              GPIOB
#define LED_PORT_RCC_EN       0x2u 
#define GPIO_MODE_MASK       ~0x3u
#define GPIO_MODE_OUTPUT      0x1u

#define GREEN_LED_PIN         0u
#define BLUE_LED_PIN          7u
#define RED_LED_PIN           14u
#define FLASH_LED             GREEN_LED_PIN

int main(void)
{
    RCC->AHB1ENR |= LED_PORT_RCC_EN ;
    LED_PORT->MODER &= GPIO_MODE_MASK << (FLASH_LED << 1) ;
    LED_PORT->MODER |= GPIO_MODE_OUTPUT << (FLASH_LED << 1) ;

    for(;;)
    {
          LED_PORT->ODR |= 0x1 << FLASH_LED ;
          delayMs( 100 ) ;
          LED_PORT->ODR &= ~(0x1 << FLASH_LED) ;
          delayMs( 100 ) ;
    }

    return 0 ;
}

您的延迟功能存在严重缺陷,可能会被优化为“什么都不做”。您的循环计数器需要声明为 volatile 以避免被优化。如果发生这种情况,指示灯将不会明显闪烁,而是会以非常高的频率脉动并亮起,但不会全亮。

以下将防止循环被优化。

void delayMs( unsigned delay )
{
    for( volatile unsigned d = delay; d > 0; d--)
    {
        for( volatile int i = 0; i < 3195; i++ )
        {
        }
    }
}

然而它是一个 180MHz 的部分;如果你以全速 3195 次迭代运行它,它可能不会花费 1ms。更像是几十微秒。即使以 16MHz 的启动 HSI 频率运行,它也可能在几百微秒的数量级,并且在任何情况下都会随着优化设置和任何中断处理程序运行所花费的时间而变化。使用 Cortex-M SYSTICK 计数器要好得多,如下所示:

static volatile uint32_t ms_tick = 0 ;

void SysTick_Init(void) 
{
    SysTick_Config( SystemCoreClock / 1000 ) ;  
}

void SysTick_Handler(void)
{
    ms_tick++;
}

void delayMs( uint32_t delay)
{
    uint32_t start_tick = ms_tick ;
    while( (ms_tick - start_tick) < delay );
}

然后,无论您以何种时钟速度运行处理器或中断负载,延迟都是准确的。


推荐阅读