我正在尝试编写一个裸机程序来使绿色LED闪烁。 实际上,我无法打开或关闭任何LED。这是一个现成的板。 板名是NUCLEO F429ZI。 Board Image
我已经仔细查看了原理图,并且确定引脚为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;
}
}
答案 0 :(得分:1)
https://www.st.com/en/evaluation-tools/nucleo-f429zi.html#resource上的Nucleo F429ZI UM1974用户手册下载链接似乎坏了(在撰写本文时),但我发现有一个副本elsewhere,以及三个用户的引脚分配因此描述了LED:
该示意图表明,将焊桥SB120和SB119的出厂状态设置为PB0而不是PA5上的LD1。尝试设置LD2(蓝色)的问题在于您没有在RCC中启用GPIOB-它像在LD1(绿色)尝试中一样启用了GPIOA。
另一个问题是您的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 );
}
然后,无论您在加载或中断负载的情况下运行处理器的时钟速度如何,延迟都将是准确的。
答案 1 :(得分:0)
您不应直接修改ODR,因为它会在整个端口上进行读/写操作。相反,您应该使用BSRR寄存器,该寄存器只能影响一位。请注意,某些STM32部分使用单个32位BSRR寄存器来设置和清除这些位(一个操作向左移16位),而其他部分则使用两个16位寄存器,因此请查阅参考手册或头文件以获取详细信息。
您的MODER设置不正确。您需要先将PA5的2位清除,然后再对01进行“或”操作,例如
GOPIOA->MODER &= ~0b1100000000;
GPIOA->MODER |= 0b0100000000;
答案 2 :(得分:0)
This is complete solution for Nucleo 144 - STM32F429ZI.
#include "stm32f4xx.h"
#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 BLUE_LED_PIN
void delayMs( unsigned delay );
int main(void)
{
RCC->AHB1ENR |= LED_PORT_RCC_EN ; // enable for PORT B
//LED_PORT->MODER &= GPIO_MODE_MASK << FLASH_LED ;
//LED_PORT->MODER |= GPIO_MODE_OUTPUT << FLASH_LED ;
GPIOB->MODER |= 0x4000; // blue LED PB7
GPIOB->MODER |= 0x1; // green LED PB0
GPIOB->ODR |= 0x1; // green LED ODR
GPIOB->MODER |= 0x1 << 28; // red LED PB14
GPIOB->ODR |= 0x1 <<14; // RED LED ODR
//GPIOB->BSRR |= 0x4000; // 7th pin
// connected to pull up resistor -- when we press button , it goes low
//B1 user button is connected to PC13 - i.e. blue button
// Enable clock to PC13 i.e. Port C
RCC->AHB1ENR |= 0x1 << 2;
//GPIOC->MODER |= //Input mode PC13- 13th pin 0
// by default pins are input only
GPIOC->MODER |= 0;
for(;;)
{
// pressed blue button
if( (GPIOC->IDR & (1<<13)) ) // PC13
{
LED_PORT->ODR |= 0x1 << FLASH_LED ;
}
else
{
LED_PORT->ODR &= ~(0x1 << FLASH_LED) ;
}
}
return 0 ;
}
void delayMs( unsigned delay )
{
for( volatile unsigned d = delay; d > 0; d--)
{
for( volatile int i = 0; i < 3195; i++ )
{
}
}
}