官方固件库手册给STM32点LED灯的方法

首页 / 技术 / 正文

最近在研究STM32,看了一段洋桃电子的教学视频感觉还不错,就买了开发板回来折腾。但是在看视频刚刚看到代码的时候我就产生了大量的疑惑,因为视频里并没有一开始就上来写代码,而是对已经写好的代码进行讲解。

他们写好的代码里已经做了很多封装抽象,比如sys.h,led.h都不是官方固件库里有的,其中有大量的宏定义,我认为这增加了学习的难度,因为宏是你自己定义的,方便自己用的,给别人用还需要一定的学习记忆,对本质代码的理解很不直观

因此我又看了其他厂商如正点原子、野火的一些视频,基本都是一个样。还在网上阅读了各种使用寄存器操作的所谓“最简”代码。最后我阅读了《STM32固件库用户手册》,自己实现了点LED灯的最简代码。

构建Project

对于工程的构建大家基本上都是一样的,固件库压缩包里的Library(库)文件夹才是本体。下面列出它的文件目录树:

├─CMSIS
│  ├─CM3
│  │  ├─//CoreSupport -- CMSIS
│  │  └─DeviceSupport
│  │      └─ST
│  │          └─//STM32F10x -- CMSIS
│  │              └─startup
│  │                  ├─//arm -- STARTUP
│  │                  ├─gcc_ride7
│  │                  ├─iar
│  │                  └─TrueSTUDIO
│  └─Documentation
└─//STM32F10x_StdPeriph_Driver -- LIB
    ├─inc
    └─src

其中标注//的目录下含有.h、.c、.s后缀的C/汇编源码文件,一般需要将其单独复制出来,建立一个工程模板方便使用。

单独复制出来有三个文件夹:CMSIS、LIB、STARTUP,实际上还需建立一个放我们自己代码的文件夹——User,ST公司对此提供了一个工程模板,并不在Library中,而是在固件库压缩包的Project-->STM32F10x_StdPeriph_Template文件夹中。我们仅需复制其中的main.c、stm32f10x_it.c、stm32f10x_it.h、stm32f10x_conf.h即可。

之后我们在keil5里新建工程,导入这几个文件夹即可,如下图所示:

编译设置

导入文件后需要做一些编译设置,点击工具栏上的魔术棒按钮,如下图设置:

Define编辑框内设置:STM32F10X_MD,USE_STDPERIPH_DRIVER
Include Paths编辑框内设置:.\CMSIS;.\LIB\inc;.\USER

输出设置,如下图:

编写代码

准备工作

首先需要清空main.c,加入如下最简的代码,编译构建一遍看是否出错,若出错需检查上一步骤:

#include "stm32f10x.h"

int main()
{
    while(1)
    {

    }
}

若无错误就可以开始对照《STM32固件库用户手册》进行编程啦。

我的开发板上的LED灯电路比较简单,如下图所示:

LED1接在PB0上,LED2接在PB1上,PB实际上是GPIO口(标准IO口)

初始化引脚

在固件库的用户手册中提到,操作引脚必须先对其进行初始化,在手册中第2.3节提到了具体的代码编写方法:


我总结了一下以上内容大概是:假设外设接口叫PPP,首先要声明一个PPP_InitTypeDef类型的名为PPP_InitStructure结构体,然后对结构体的参数进行设置(不同外设接口参数不一样),最后使用PPP_Init函数初始化外设。此外,需要记住的是,在初始化外设之前还需要初始化时钟,可使用RCC_AHBPeriphClockCmd、RCC_APB2PeriphClockCmd、RCC_APB1PeriphClockCmd函数操作。

而我的LED灯接在GPIO口上,自然需要查阅初始化GPIO的一些函数。翻一翻用户手册的目录,我直接找到了目录中的GPIO_Init函数,其中对其参数介绍非常详细,读者可自行查阅。

由此便可以写出初始化的代码了:

void LED_Init()
{
    //把GPIOB的时钟初始化了
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

    //设定好GPIO初始化的参数
    GPIO_InitTypeDef LED_InitStructure;
    LED_InitStructure.GPIO_Pin = GPIO_Pin_0; //第0脚
    LED_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //50MHz最大速度
    LED_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出模式

    //执行初始化
    GPIO_Init(GPIOB, &LED_InitStructure); //GPIOB组引脚
}

点亮LED

编写点亮LED的代码之前,需要在main函数中执行我们上面写好的初始化代码。

//在while死循环前加入
LED_Init();

下一步便是点亮LED了,由我的电路可知,要给引脚输出高电平才能点亮LED。再次查阅手册,发现GPIO_SetBits函数可以很好地实现这个功能。

于是在main函数中加入如下代码:

//在while循环中加入
GPIO_SetBits(GPIOB, GPIO_Pin_0);

构建,烧录运行,是不是看到效果啦?!总体代码如下,是不是很简单:

#include "stm32f10x.h"

void LED_Init()
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    GPIO_InitTypeDef LED_InitStructure;
    LED_InitStructure.GPIO_Pin = GPIO_Pin_0;
    LED_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    LED_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init(GPIOB, &LED_InitStructure);
}

int main()
{
    LED_Init();
    while(1)
    {
        GPIO_SetBits(GPIOB, GPIO_Pin_0);
    }
}
打赏
评论区
头像
    头像
    茶半侬
    2020年05月12日 23:03
    回复

    {{xieyanxiao}} 偶然间遇到大佬,我也只能在32的版块下留个言了,棒棒!

      头像
      huanghaozi
      2020年06月16日 21:21
      回复

      {{liulei}} 我不是大佬嗷,甚至是外行.......