我正在对F401RE板进行编程,我试图通过按板上的按钮来切换LED的开/关。我使用的是低级方法,因为这是大学的功课,我无法使用高级库。
这是我所做的,但不起作用,led灯不动... 该代码应该是正确的,我缺少什么?
#include "stm32f4xx.h"
int main(void){
int flag=0;
//PORT REGISTERS
volatile uint32_t *GPIOA_MODER = (uint32_t*) (0x40020000 + 0x00);
volatile uint32_t *GPIOA_ODR = (uint32_t*) (0x40020000 + 0x14);
volatile uint32_t *GPIOC_MODER = (uint32_t*) (0x40020000 + 0x0800 + 0x00);
volatile uint32_t *GPIOC_IDR = (uint32_t*) (0x40020000 + 0x0800 + 0x10);
//CLOCK REGISTERS
volatile uint32_t *RCC_AHB1ENR = (uint32_t*) (0x40023800 + 0x30);
*RCC_AHB1ENR |= 0x05U;
*GPIOA_MODER = *GPIOA_MODER | 0x400;
*GPIOC_MODER = *GPIOC_MODER | 0x0C000000;
*GPIOA_ODR = *GPIOA_ODR | 0x20;
// Application code (Infinite loop)
while (1){
if((((*GPIOC_IDR>>13) & 0x01) == 0x01)){
flag=1;
}else if((((*GPIOC_IDR>>13) & 0x01) == 0x00) && flag==1){
*GPIOA_ODR = *GPIOA_ODR ^ 0x20;
flag=0;
}
}
}
答案 0 :(得分:4)
警告:我不是是使用此特定MCU的专家。小心点。
从this参考手册中提取的所有MCU寄存器信息。
无论如何,既然我已经完成了免责声明,那就让我们开始吧。
//Lines 16-20
...
*GPIOA_MODER = *GPIOA_MODER | 0x400;
*GPIOC_MODER = *GPIOC_MODER | 0x0C000000;
*GPIOA_ODR = *GPIOA_ODR | 0x20;
...
我相信这是包含错误的代码段。您将GPIOA_MODER5
设置为使用通用输出模式,并将GPIOC_MODER13
设置为使用模拟模式。再一次,这里不是专家,但是我认为应该将其设置为使用输入模式。不执行任何操作(因为端口C的重置值为0x00000000
),或者使用*GPIOC_MODER = *GPIOC_MODER & ~(0x0C000000);
显式重置寄存器的那部分。
在调试过程中,我重新格式化了您的代码,以符合我大学的编码标准以及我的个人喜好。这里是。
#include "stm32f4xx.h"
//Magic numbers are BAD. Use macros instead.
#define GPIOA_MEMOFFSET 0x40020000
#define GPIOC_MEMOFFSET 0x40020800
#define CLOCK_MEMOFFSET 0x40023800
//more macros. These are bit offsets for various registers.
#define GPIOC_MODER13 26
#define GPIOA_MODER5 10
#define GPIOC_IDR13 13
#define GPIOA_ODR5 5
#define RCC_AHB1ENR_GPIOAEN 0
#define RCC_AHB1ENR_GPIOCEN 1
int main(void)
{
//Different compilers have different lengths for ints.
//uint8_t is always 8 bits long.
uint8_t flag=0;
//This area has been width formatted to be easier to read.
//The compiler doesn't care about whitespace. See the macros at work?
//PORT REGISTERS
volatile uint32_t *GPIOA_MODER = (uint32_t*) (GPIOA_MEMOFFSET + 0x00);
volatile uint32_t *GPIOA_ODR = (uint32_t*) (GPIOA_MEMOFFSET + 0x14);
volatile uint32_t *GPIOC_MODER = (uint32_t*) (GPIOC_MEMOFFSET + 0x00);
volatile uint32_t *GPIOC_IDR = (uint32_t*) (GPIOC_MEMOFFSET + 0x10);
//CLOCK REGISTERS
volatile uint32_t *RCC_AHB1ENR = (uint32_t*) (CLOCK_MEMOFFSET + 0x30);
//No, it's not as concise as your version. But since all of this is constant,
//any GOOD compiler will literally turn all that into a 5. It makes debugging
//for other programmers easier to see what's actually going on.
*RCC_AHB1ENR |= (1 << RCC_AHB1ENR_GPIOAEN) | (1<<RCC_AHB1ENR_GPIOCEN);
//I turned every assignment operator into its equivalent boolean assignment.
*GPIOA_MODER |= (0b01 << GPIOA_MODER5);
*GPIOA_MODER &= ~(0b10 << GPIOA_MODER5);
*GPIOC_MODER &= ~(0b11 << GPIOC_MODER13);
*GPIOA_ODR = *GPIOA_ODR | (1 << GPIOA_ODR5);
// Application code (Infinite loop)
while (1)
{
//Lots of work here. C standard defines false as 0 and true as !false
//so you're able to turn 'if (xx!=0)' into just 'if (xx)'
//...usually. The rules get iffy when you do weird things.
if (*GPIOC_IDR & (1<<GPIOC_IDR13)) //AND masking IDR13.
{
flag=1;
}
else if(!(*GPIOC_IDR & (1<<GPIOC_IDR13)) && flag) //AND masking IDR13 again, but also boolean inverting the result.
{
*GPIOA_ODR ^= (1<<GPIOA_ODR5);
flag=0;
}
}
}
答案 1 :(得分:0)
您是否打算将端口引脚PC13用于按钮输入?将GPIOC_MODER与0x0C000000进行OR运算会将PC13设置为模拟模式。我认为您想要输入模式而不是模拟模式。输入模式是PC13的默认模式。因此,请尝试仅注释掉以下行。
<Style ...">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Margin="5" Text="Save"/>
<Image Source="Resources\icons\save.png" Margin="5"
Height="16" Width="16"></Image>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>