STM32入门教程:LED灯闪烁,流水灯实现及按键控制

本教程针对stm32F407开发板,标准库开发。
首先查看改开发板的原理图,找到LED部分:

分析原理图:
   

  • 电源是 +3.3V,通过限流电阻(R7 / R9)再接到 LED 的阳极(正极)

  • LED 的阴极(负极)接到信号端 LED0 / LED1

   所以:这两个 LED 是低电平触发(低电平点亮,高电平熄灭)

查看原理图分析LED灯对应的引脚

如图所示:LED0-->PF10,LED1-->PF9
查询8、STM32F4xx中文参考手册,CPU 核心时钟(HCLK)频率为168MHz

基本信息已经知道,现在打开Keil uVision5,新建工程。
项目框架如图所示

首先写SYSTEM下的延时部分(DELAY.c和DELAY.h)
DELAY.c

#include "stm32f4xx.h"                  // Device header
#include "DELAY.h"
void DELAY_ms(uint32_t xms)
{
	while(xms--)
	{
		SysTick->CTRL = 0;//关闭 SysTick 
		SysTick->LOAD = SystemCoreClock /1000; //设定重装值:1ms 需要的时钟 tick 数
		SysTick->VAL = 0;//清空当前计数,同时清除 COUNTFLAG 
		SysTick->CTRL = 1<<0 | 1<<2;//使能 SysTick(EN=1),时钟源选 CPU 时钟(CLKSOURCE=1),不使能中断(TICKINT=0) 
		while ((SysTick->CTRL &(1<<16))==0);//轮询 COUNTFLAG,等它从 0 变 1(计到 0)即 1 ms
		SysTick->CTRL = 0;//关 SysTick,结束本次 1 ms 
	}
}

void DELAY_us(uint32_t xus)
{
	while(xus--)
	{
		SysTick->CTRL = 0; 
		SysTick->LOAD = SystemCoreClock /1000/1000; 
		SysTick->VAL = 0; 
		SysTick->CTRL = 1<<0 | 1<<2; 
		while ((SysTick->CTRL &(1<<16))==0);
		SysTick->CTRL = 0; 
	}
}

DELAY.h

#ifndef __DELAY__H_
#define __DELAY__H_
#include "stm32f4xx.h"                  // Device header
void DELAY_ms(uint32_t xms);
void DELAY_us(uint32_t xus);
#endif

LED.c
 

#include "stm32f4xx.h"                  // Device header
//PF9   LED1
//PF10  LED0

void LED_init(void)
{
 //时钟使能GPIOF的时钟
 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF,ENABLE);
	
	 //设置相应脚位功能
	GPIO_InitTypeDef GPIO_INSTRUCT;
	GPIO_INSTRUCT.GPIO_Mode = GPIO_Mode_OUT;
	GPIO_INSTRUCT.GPIO_OType = GPIO_OType_PP;
	GPIO_INSTRUCT.GPIO_Pin = GPIO_Pin_9 |GPIO_Pin_10;
	GPIO_INSTRUCT.GPIO_PuPd = GPIO_PuPd_NOPULL;
	GPIO_INSTRUCT.GPIO_Speed = GPIO_Speed_100MHz;
  
	//使配置功能脚位生效
	GPIO_Init(GPIOF,&GPIO_INSTRUCT);

   //默认高电平,关闭LED灯
	GPIO_SetBits(GPIOF,GPIO_Pin_9);
	GPIO_SetBits(GPIOF,GPIO_Pin_10);
	
}

void LED0_on(void)
{
//分析原理图,LED灯低电平点亮
 GPIO_ResetBits(GPIOF,GPIO_Pin_10);
} 

void LED0_off(void)
{
//高电平熄灭
 GPIO_SetBits(GPIOF,GPIO_Pin_10);
} 

void LED1_on(void)
{
GPIO_ResetBits(GPIOF,GPIO_Pin_9);
}


void LED1_off(void)
{
GPIO_SetBits(GPIOF,GPIO_Pin_9);
}


LED.h

#ifndef __LED__H_
#define __LED__H_
void LED_init(void);
void LED0_on(void);
void LED0_off(void);
void LED1_on(void);
void LED1_off(void);
#endif

main.c
 

#include "stm32f4xx.h"                  // Device header
#include "LED.h"
#include "DELAY.h"   // 延时函数

int main(void)
{
    LED_init();   // 初始化 LED

    while(1)
    {
        //LED灯闪烁
        LED0_on();
        DELAY_ms(500);   // 延时500ms
        LED0_off();
        DELAY_ms(500);
    }
}

运行效果:

LED0循环闪烁,每次:亮0.5s——>灭0.5s——>亮0.5s.......一直循环。

当想实现流水灯效果时,只需要修改main.c

#include "stm32f4xx.h"                  // Device header
#include "LED.h"
#include "DELAY.h"

int main(void)
{
    LED_init();         // 初始化 LED

    while(1)
    {
        LED0_on();                  // 点亮 LED0
        DELAY_ms(300);              // 延时 300ms
        LED0_off();                 // 熄灭 LED0

        LED1_on();                  // 点亮 LED1
        DELAY_ms(300);
        LED1_off();
    }
}

运行效果:
LED0与LED1呈现流水灯效果。

由于我的开发板只有两个LED灯,所以流水灯效果不是很明显,可以根据自己开发板的LED灯数增加,LED灯数越多,效果越明显。

现在可以升级程序,添加按键控制功能,使用按键控制LED灯的状态

依旧查看按键的原理图及对应的引脚

由按键的原理图可以看出,WK_UP按键对应PA0,按下后为高电平,松开为低电平。KEY_0按键对应PE4,按下后为低电平,松开为高电平。
现在知道按键的相关信息,开始编写按键代码

继续在HARDWARE文件夹下添加KEY.c与KEY.h,使其与LED.c与LED.h在同一路径。

KEY.c
 

#include "stm32f4xx.h"                  // Device header
#include "KEY.h"
#include "LED.h"

// WK_UP : PA0, 按下=高电平
// KEY0  : PE4, 按下=低电平

void KEY_init(void)
{
    // 使能 GPIOA 和 GPIOE 时钟
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);

    GPIO_InitTypeDef GPIO_INSTRUCT;
    GPIO_INSTRUCT.GPIO_Mode  = GPIO_Mode_IN;      // 输入模式
    GPIO_INSTRUCT.GPIO_OType = GPIO_OType_PP;     // 推挽(对输入脚其实没影响)
    GPIO_INSTRUCT.GPIO_PuPd  = GPIO_PuPd_NOPULL;  // 浮空
    GPIO_INSTRUCT.GPIO_Speed = GPIO_Speed_100MHz;

    // PA0 (WK_UP)
    GPIO_INSTRUCT.GPIO_Pin = GPIO_Pin_0;
    GPIO_Init(GPIOA, &GPIO_INSTRUCT);

    // PE4 (KEY0)
    GPIO_INSTRUCT.GPIO_Pin = GPIO_Pin_4;
    GPIO_Init(GPIOE, &GPIO_INSTRUCT);
}

// 按键检测并控制 LED
void KEY_ScanAndControl(void)
{
    // WK_UP 按下=高电平
    if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == 1)
    {
        LED0_on();
    }
    else
    {
        LED0_off();
    }

    // KEY0 按下=低电平
    if (GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_4) == 0)
    {
        LED1_on();
    }
    else
    {
        LED1_off();
    }
}

KEY.h

#ifndef __KEY__H_
#define __KEY__H_
#include "stm32f4xx.h"                  // Device header
void KEY_init(void);
void KEY_ScanAndControl(void);
#endif

main.c

#include "stm32f4xx.h"
#include "LED.h"
#include "KEY.h"
#include "DELAY.h"

int main(void)
{
    LED_init();   // 初始化 LED
    KEY_init();   // 初始化按键

    while(1)
    {
        KEY_ScanAndControl();  // 检测按键并控制 LED
        DELAY_ms(10);          // 软件消抖(10ms)
    }
}

对于按键控制LED灯时,最好加入延时函数,进行消抖处理。负责有可能出现按一次按键,实际按了很多次。

运行效果:

  • 按下 WK_UP (PA0 高电平)LED0 点亮,松开熄灭

  • 按下 KEY0 (PE4 低电平)LED1 点亮,松开熄灭

如果想实现按键控制 LED 的“翻转开关”效果,按一下松开开关:打开LED,再按一下松开开关:关闭LED。那么就要实现状态翻转 + 消抖。

KEY.c

#include "stm32f4xx.h"
#include "KEY.h"
#include "LED.h"
#include "DELAY.h"   // 用于按键消抖延时

// WK_UP : PA0, 按下=高电平
// KEY0  : PE4, 按下=低电平

void KEY_init(void)
{
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);

    GPIO_InitTypeDef GPIO_INSTRUCT;
    GPIO_INSTRUCT.GPIO_Mode  = GPIO_Mode_IN;
    GPIO_INSTRUCT.GPIO_OType = GPIO_OType_PP;
    GPIO_INSTRUCT.GPIO_PuPd  = GPIO_PuPd_NOPULL;
    GPIO_INSTRUCT.GPIO_Speed = GPIO_Speed_100MHz;

    // PA0 (WK_UP)
    GPIO_INSTRUCT.GPIO_Pin = GPIO_Pin_0;
    GPIO_Init(GPIOA, &GPIO_INSTRUCT);

    // PE4 (KEY0)
    GPIO_INSTRUCT.GPIO_Pin = GPIO_Pin_4;
    GPIO_Init(GPIOE, &GPIO_INSTRUCT);
}

// 按键扫描(带翻转功能)
// 返回值:0=无操作, 1=WK_UP触发, 2=KEY0触发
uint8_t KEY_Scan(void)
{
    // WK_UP: 按下=高电平
    if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == 1)
    {
        Delay_ms(20); // 消抖
        if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == 1)
        {
            while(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == 1); // 等待松手
            return 1;
        }
    }

    // KEY0: 按下=低电平
    if (GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_4) == 0)
    {
        Delay_ms(20); // 消抖
        if (GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_4) == 0)
        {
            while(GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_4) == 0); // 等待松手
            return 2;
        }
    }

    return 0;
}

KEY.h

#ifndef __KEY__H_
#define __KEY__H_
#include "stm32f4xx.h"                  // Device header
void KEY_init(void);
uint8_t KEY_Scan(void);
#endif

main.c

#include "stm32f4xx.h"
#include "LED.h"
#include "KEY.h"
#include "DELAY.h"

int main(void)
{
    LED_init();
    KEY_init();

    uint8_t led0_state = 0;  // 记录 LED0 状态
    uint8_t led1_state = 0;  // 记录 LED1 状态

    while(1)
    {
        uint8_t key = KEY_Scan();
        if (key == 1) // WK_UP
        {
            led0_state = !led0_state;  // 翻转
            if (led0_state) LED0_on();
            else LED0_off();
        }
        else if (key == 2) // KEY0
        {
            led1_state = !led1_state;  // 翻转
            if (led1_state) LED1_on();
            else LED1_off();
        }
    }
}

运行效果:

  • 按一次 WK_UP (PA0)LED0 状态翻转(亮 ↔ 灭)

  • 按一次 KEY0 (PE4)LED1 状态翻转

  • 每次按下都要松开后才能再次识别(消抖+等待松手机制)

本文章将STM32入门点亮LED灯延申实现流水灯,再延申实现按键控制LED灯,由浅入深。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值