本文首发于我的博客huanghaozi.cn,原链接
最近在研究STM32,看了一段洋桃电子的教学视频感觉还不错,就买了开发板回来折腾。但是在看视频刚刚看到代码的时候我就产生了大量的疑惑,因为视频里并没有一开始就上来写代码,而是对已经写好的代码进行讲解。
他们写好的代码里已经做了很多封装抽象,比如sys.h,led.h都不是官方固件库里有的,其中有大量的宏定义,我认为这增加了学习的难度,因为宏是你自己定义的,方便自己用的,给别人用还需要一定的学习记忆,对本质代码的理解很不直观。
因此我又看了其他厂商如正点原子、野火的一些视频,基本都是一个样。还在网上阅读了各种使用寄存器操作的所谓“最简”代码。最后我阅读了《STM32固件库用户手册》,自己实现了点LED灯的最简代码。
对于工程的构建大家基本上都是一样的,固件库压缩包里的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的代码之前,需要在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); } } 复制代码
本篇文章由一文多发平台ArtiPub自动发布