最近由于项目需要使用标准库,标准库是很刚入门stm32那会学习的东西,忘得一干二净,所以编写一篇文章来记录一下建立工程模板的步骤,以便尽快熟悉标准库的架构和API。
我使用的开发板是正点原子探索者开发板,MCU为STM32F407ZGT6。
STM32标准库(官方网站)是ST在早期为STM32F0到F4系列主流芯片提供的库,使开发者不需要直接操作寄存器,而是调用库提供的API即可完成对某个片内外设的操作,所以也称为标准外设库,或者固件库。
本文中我使用的是 STM32F4xx_DSP_StdPeriph_Lib_V1.8.0
,可以从官网下载(下载地址):
解压之后,标准外设库中每个文件夹的说明如图:
在project文件下新建MDK文件夹,方便支持不同的编译器:
将标准库中的Libraires文件夹中的内容复制到刚刚建立的文件夹中:
打开Keil-MDK,在刚刚创建的 project/MDK 下建立一个新的工程,设计如下分组:
启动文件在标准库中的CMSIS\Device\ST\STM32F4xx\Source\Templates
目录下:
这里我们使用的是MDK,所以选择arm
文件夹下的启动文件,如图:
在Startup分组中添加该启动文件:
系统初始化文件在 CMSIS\Device\ST\STM32F4xx\Source\Templates
目录下:
在CMSIS分组中添加该文件:
标准外设库所有文件都在STM32F4xx_StdPeriph_Driver\src
目录中,全部添加到 STM32F4xx_StdPeriph_Driver 分组中:
STM32F407系列中没有FMC外设,要去掉该驱动文件:
① 中断处理程序文件stm32f4xx_it.c
:
中断处理程序文件在标准外设库中的示例工程中,复制到自己创建的user文件夹下:
编辑stm32f4xx_it.c
文件,去掉包含main.h的代码:
再去掉Systick中断中的内容:
② 标准外设库配置文件stm32f4xx_conf.h
:
③ 新建一个 main.c
文件:
④ 将user下的.c都添加到User分组下面:
添加两个宏定义:
USE_STDPERIPH_DRIVER
:表示工程使用标准外设库;STM32F40_41xxx
:表示工程对应的MCU型号;/**********************************************************
* @brief
* @author Mculover666
* @date
* @note
**********************************************************/
#include "stm32f4xx.h"
int main()
{
/* Main Loop */
while (1) {
}
}
① 该标准外设库不支持armcc6编译器,所以设置为默认的armcc5编译器:
② 标准库提供的文件上都有一把小黄锁,原因是这些文件都是只读文件,在libraries文件夹上右击,修改所有文件的只读属性即可:
本文中所使用的时钟初始化配置文件``是从标准外设库中复制过来的,从其注释中可以看出该配置使用的HSE为25Mhz,如图:
而本文所使用的正点原子探索者开发板所使用的外部晶振为8Mhz(这就离谱!):
为了保证主频为168Mhz,需要对该配置进行修改。
① 修改HSE宏定义的值为8000000,在stm32f4xx.h
中,如图:
② 修改PLL分频系数为8:
至此,时钟树配置完成。
这里我以LED闪烁为例,演示如何使用该模板工程。
在user文件夹下新建led文件夹及文件,用于存放led驱动:
将 bsp_led.c 添加到工程中:
将 bsp_led.h添加到头文件路径:
编写 bsp_led.h 文件:
#ifndef _BSP_LED_H_
#define _BSP_LED_H_
#include "stm32f4xx.h"
#define LED_PORT GPIOF
#define LED_PIN GPIO_Pin_9
typedef enum led_status_en {
LED_OFF = 0,
LED_ON = 1
} led_state_t;
void led_init(void);
void led_control(led_state_t status);
#endif /* _BSP_LED_H_ */
编写 bsp_led.c 文件:
#include "bsp_led.h"
void led_init()
{
GPIO_InitTypeDef GPIO_InitStructure;
/* 1. Enable Clock */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);
/* 2. Config GPIO Structure*/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Pin = LED_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Low_Speed;
GPIO_Init(LED_PORT, &GPIO_InitStructure);
}
void led_control(led_state_t status)
{
if (status == LED_ON) {
GPIO_ResetBits(LED_PORT, LED_PIN);
} else {
GPIO_SetBits(LED_PORT, LED_PIN);
}
}
在main.c中编写LED闪烁的代码:
/**********************************************************
* @brief LED blink
* @author Mculover666
* @date 2020/1/20
* @note
**********************************************************/
#include "stm32f4xx.h"
#include "bsp_led.h"
void delay(__IO uint32_t n)
{
for(; n != 0; n--);
}
int main()
{
/* Init LED */
led_init();
/* Main Loop */
while (1) {
led_control(LED_ON);
delay(0xFFFFF);
led_control(LED_OFF);
delay(0xFFFFF);
}
}
编译、下载,可以看到板载LED0闪烁。