STM32之点亮LED

学习一个新的处理器,第一个程序肯定就是点亮LED,它可以让我们较快的、较清晰的了解到一个处理器的程序结构,学习32也不例外,首先第一个程序我们就来点亮LED,点亮LED程序有很多种,这里我们用库函数来实现LED的闪烁
本人使用的开发板是正点原子的精英版开发板。
首先复制一下我们之前建好的工程模板,然后把文件夹命名为LED。
然后打开这个工程文件,第一步我们需要再建立两个空白页,并按照我上一篇博客的方法把他俩存到HARDWARE文件夹里面,一个命名为led.c,另一个命名为led.h,然后再在keil MDK软件里面把这两个文件给添加到工程中去,添加完之后,我们的工程结构如下图

添加完之后,我们不要忘记要把这个.h文件路径给添加进去。点击keil MDK软件中的那个魔术棒标志,然后进入到c/c++那一栏,点击include Paths后面的那三个点




经过以上几个步骤之后,然后找到HARDWARE文件夹,双击一下那个LED文件夹就可以了(请忽略我里面已经添加好的路径),注意32添加路径的时候,必须精确到最后一级文件夹

其实其它的几个文件夹都需要添加路径,具体的做法正点原子官方论坛提供的资料中的不完全手册里面都讲的很清楚,大家可以去看一下。
附上正点原子官方论坛网址:http://www.openedv.com/thread-13912-1-1.html

这些基本工作做好之后,我们就可以开始写程序了
首先在led.h文件中写如下程序

#ifndef __LED_H
#define __LED_H
#include"sys.h"
#define LED0 PBout(5)


void led_init(void);

#endif

(注意在每一个.c和.h文件的最后,我们都需要加上一个回车,这可能是keil MDK软件自身的一个BUG,如果不加的话,编译的时候会有警告)
其中这个.h文件中程序就是用来定义一个led.h头文件,以便我们在led.c文件里面可以进行调用。
头文件的声明也是固定的格式,格式如下:

#ifndef __LED_H
#define __LED_H


#endif

意思就是如果没有定义led.h头文件的话,我们就定义一个led.h头文件,然后最后加上#endif表示定义完毕

然后这个led.h文件里面的#include “sys.h”是调用工程中的”sys.h”头文件,以后每个新定义的头文件都需要调用这个头文件,这个”’sys.h”头文件里面定义了一些32程序所需要的东西,有兴趣的你可以进入这个头文件里面看一下。

#define LED0 PBout(5)

这一条语句就是一个宏定义,你可以理解为它就相当于我们51单片机中写的sbit的作用,就是用LED0来代替了PB5引脚,并且PB5引脚为输出,即表达格式为PBout(5)

然后再在led.c文件里面写程序

#include"led.h"

void led_init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5;
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_Init(GPIOB,&GPIO_InitStructure);
}

这个led.c文件主要就是定义了一个GPIO口初始化的程序,就是来配置一下我们点亮LED所用到的GPIO口,(注意32在定义函数的时候,如果没有参数需要传递的话,那么必须要写入 void,即我们要写成led_init(void),否则编译也会出现警告,但是在函数调用的时候,如果没有参数传递,我们就不用再写入void ,我们可以直接调用led_init()即可)另外对于32来说,一般所有的配置都是用结构体来实现的,结构体中的成员就代表了这个功能所工作的方式。就拿我们这次点亮LED来说,我们使用的是LED0,他在正点原子的精英版上是接在了PB5引脚上,也就是说我们需要把PB5引脚配置成可以让LED点亮的工作方式。
首先我们要声明一个结构体 GPIO_InitStructure

GPIO_InitTypeDef GPIO_InitStructure;

其中GPIO_InitStructure这个结构体的名字我们是可以随意写的,但是GPIO_InitTypeDef这个名字就只能写成这种形式,因为它是在固件库中已经定义好的,所以说我们不能随意改动。注意,结构体的定义必须在函数的开头,我们不能在函数中间进行定义变量(其实所有的定义都必须要在函数的开头,这一点也和我们当初学的C语言是一样的)
然后我们就需要开启GPIOB的时钟,因为32基本上每一部分都有自己独立的时钟,我们要想让某一个模块工作,我们就必须使能它的时钟,使能时钟的函数也是固定的,我们只需要调用这个函数,然后传入对应的参数就行,原函数如下

RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState)

其中这个函数的第一个参数就是选择你是要使能哪一个模块的时钟,第二个参数就是选择使能或者不使能,使能就是ENABLE,不使能就是DISABLE。(这里我们使用的是APB2总线,32还有APB1总线,APB2是高速总线,APB1是低速总线,有的模块是挂在APB1总线,有的是挂在APB2总线,我们应该具体情况具体分析)
所以我们现在要用PB5引脚,即我们要使能GPIOB的时钟,所以我们要写成如下的形式

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);

接下来我们就需要对刚才定义过的结构体中的成员进行赋值了,
首先我们输入GPIO_InitStructure,然后再输入一个点“.”也就是输入
GPIO_InitStructure.,这个时候,程序会自动出现这个结构体中的各个成员变量供你选择(这一点和我们的C语言是一样的)。其中这个结构体我们需要对三个成员进行配置,分解为GPIO_ModeGPIO_Pin、GPIO_Speed`

然后我们选中GPIO_Mode,然后右鼠标点击右键,进入Go To Definition of “GPIO_Mode”,然后我们就会转入到一个 gpio.h 文件,在里面我们找到关于GPIO_Mode的相关定义,

#define IS_GPIO_MODE(MODE) (((MODE) == GPIO_Mode_AIN) || ((MODE) == GPIO_Mode_IN_FLOATING) || \
                            ((MODE) == GPIO_Mode_IPD) || ((MODE) == GPIO_Mode_IPU) || \
                            ((MODE) == GPIO_Mode_Out_OD) || ((MODE) == GPIO_Mode_Out_PP) || \
                            ((MODE) == GPIO_Mode_AF_OD) || ((MODE) == GPIO_Mode_AF_PP))

我们可以看到GPIO有很多工作模式,我们需要根据自己的实际需要来选择具体的工作模式,这里我们要实现的是点亮LED灯,所以我们选择推挽输出工作模式,也就是选择GPIO_Mode_Out_PP
然后另外的两个结构体成员的配置同理,最后三个成员配置如下

GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;

(关于GPIO_Speed其实我也不是很理解他的意思,他好像是配置GPIO口的最大输出速度,这里我们选择最大的速度,也就是50MHz)
对各个成员变量赋值之后,我们要把这些值给导入到结构体当中去,此时我们又需要另外一个函数

GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)

这个函数就是把刚才各个成员的值都给导入到结构体中去(如果暂时不理解,可以先记住,以后每一次配置都会用到这个函数),这个函数的第一个参数就是填入你要配置的是哪一个GPIO口,第二个参数就是你刚才定义的那个结构体名字加上符号“&”,最后这条程序如下

GPIO_Init(GPIOB,&GPIO_InitStructure);

到此,我们就完成了GPIO口的初始化过程,然后就是在主函数中调用了。注意你在.c文件中所定义的函数,不要忘记在这个.c文件所对应的.h文件中进行声明,这里我们在led.c里面定义了一个函数led_init(void),那么我们就需要把这个函数在led.h文件中进行声明,led.h文件如下

#ifndef __LED_H
#define __LED_H
#include "sys.h"
#define LED0 PBout(5)


void led_init(void);

#endif

接下来,我们在main.c里面进行操作,程序如下

#include "sys.h"
#include "delay.h"
#include "led.h"

int main(void)
{
    led_init();
    delay_init();
    while(1)
    {
        LED0=0;
      delay_ms(100);
      LED0=1;
      delay_ms(100);
    }
}

首先就是先添加我们程序中所用到的头文件

#include "sys.h"
#include "delay.h"
#include "led.h"

其中delay.h也是在建工程模板的时候添加的,里面定义了一些延时函数,我们一般都在主函数中添加这个delay.h文件,以便我们随时调用延时函数(你在哪个,c文件中调用了对应的函数,你就必须把这个函数所对应的的.h文件给添加到当前的.c文件中去,可能我说的比较乱,以后慢慢理解)。
然后就是写主函数,注意32 的主函数不能是void main(void),必须是int main(void)(我也不知道为啥)
在主函数中,我们首先调用我们在led.c文件中所写的LED初始化函数,然后再调用延时函数,然后写一个while循环,让LED在循环里面不断地进行状态翻转,程序如下

int main(void)
{
    led_init();
    delay_init();
    while(1)
    {
        LED0=0;
      delay_ms(100);
      LED0=1;
      delay_ms(100);
    }
}

到此为止,我们这个点亮LED的程序就写完了,编译之后,如果没有错误就可以把它烧录到开发板进行测试了,如果都正确的话,我们可以看到开发板上的一个小灯会不断地闪烁,闪烁间隔就是我们在 while循环里面所写的100ms。

点亮LED实验到此结束!

猜你喜欢

转载自blog.csdn.net/qq_36554582/article/details/81228601