手撕STM32库函数工程(1)–自建stm32f10x.h
文章目录
- 手撕STM32库函数工程(1)--自建stm32f10x.h
- **0. 准备工作及工程文件概览:**
- 1、建立Keil工程
- 2. 改进:定义自定义的文件,保存自定义的变量和函数,如延时函数等
- 3. 尝试用库中的stm32f10x.h
- 4. 继续封装stm32f10x_xxx.h
- 5. 模仿继stm32f10x_conf.h的思路,续封装用户自定义文件
- 6 作业:用一个按键点亮LED灯
- 参考文献:野火--STM32库开发实战指南
0. 准备工作及工程文件概览:
0.1 新建一个keil_LED工程文件夹
0.2 在keil_LED文件夹中建立一个keil点灯工程:xxxx
事先放入启动文件:startup_stm32f10x_hd.S ???
startup_stm32f10x_ld.S | 小容量的Flash芯片:16-32K | STM32F101xx,STM32F102xx,STM32F103xx |
---|---|---|
startup_stm32f10x_md.S | 中容量的Flash芯片:64-128K | STM32F101xx,STM32F102xx,STM32F103xx |
startup_stm32f10x_hd.S | 大容量的Flash芯片:256-512K | STM32F101xx,STM32F102xx,STM32F103xx |
startup_stm32f10x_xl.S | 超大容量的Flash芯片:512-1024K | STM32F101xx,STM32F102xx,STM32F103xx |
0.3 keil工程中最终包含以下四个文件:
- main.c 主程序
- startup_stm32f10x_hd.S 启动文件
- stm32f10x_gpio.c GPIO外设驱动文件
- system_stm32f10x.c 系统时钟配置函数等
main.c | 主程序 |
---|---|
startup_stm32f10x_hd.S | 启动文件 |
stm32f10x_gpio.c | GPIO外设驱动文件 |
system_stm32f10x.c | 系统时钟配置文件 |
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tafLh5j6-1635738492274)(建立自己的STM32库函数工程(1)–自建stm32f10x.h.assets/L(7LTP]OC$SXO2)]6C3EN}TW.png)
1、建立Keil工程
新建xxx文件夹,新建keil工程(包括选择器件,配置keil工程,生产hex文件等),并将工程保存到xxx文件夹下。
1.1 往keil工程中添加 startup_stm32f10x_hd.S头文件
- 将startup_stm32f10x_hd.S文件copy到xxx工程目录下****
- 将 startup_stm32f10x_hd.S添加到kei工程中去****
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i5E4bby4-1635738492276)(建立自己的STM32库函数工程(1)–自建stm32f10x.h.assets/66-16356454926281-16356792208641.png)]
1.2 自建 stm32f10x.h
1.2.1 准备工作:建立core_cm3.h、stdint.h、system_stm32f10x.h/c文件
说明:库函数的stm32f10x.h文中中包含了以下三个文件,所以我们要提前建立它们:
- core_cm3.h : 内核寄存器映射及volatile关键字
- stdint.h : 定义各种数据类型
- system_stm32f10x.h : 系统时钟配置,SystemInit(void)
1.2.1.1 建立core_cm3.h (该文件无需添加到工程,会在stm32f10x.h中include进去)
在keil工程中,新建core_cm3.h头文件。代码如下:
#ifndef __CORE_CM3_H__
#define __CORE_CM3_H__
// stm32f10x.h 外设寄存器映射 <---------> core_cm3.h 内核的寄存器映射头
/* stm32f10x.h/core_cm3.h:
(1) 内核/外设寄存器: 结构体定义
(2) 内核/外设寄存器: 基地址映射
(3) 内核/外设寄存器: 指向寄存器结构体的指针的声明
*/
// 其他辅助定义,如_IO, IO_ ,__IO
#define __IO volatile
// 其他代码详见标准库中的标准core_cm3.h 和core_cm3.c
#endif
说明:core_cm3.h主要实现了内核寄存器映射,其中定义了我们经常要用到的volatile关键字相关的宏。
core_cm3.c主要实现了操作内核外部寄存器的函数,用的比较少,这里不考虑
这里只是为了学习标准库的结构,不涉及内核寄存器映射代码,详细代码参见标准库中的标准core_cm3.h
1.2.1.2 建立stdint.h (该文件无需添加到工程,会在stm32f10x.h中include进去)
在keil工程中,新建stdint.h 头文件。代码如下:
#ifndef __STDINT_H__
#define __STDINT_H__
// stdint.h 中定义来各种数据类型,类似于C语言中的stdio.h
typedef signed char int8_t;
typedef signed short int int16_t;
typedef signed int int32_t;
// typedef signed __INT64 int64_t;
typedef unsigned char uint8_t;
typedef unsigned short int uint16_t;
typedef unsigned int uint32_t;
// typedef unsigned __INT64 uint64_t;
// 其他代码详见标准库中的标准stdint.h
#endif
1.2.1.3 建立system_stm32f10x.h和system_stm32f10x.c(system_stm32f10x.c要添加到工程中,system_stm32f10x.h不用)
在keil工程中,新建system_stm32f10x.h和system_stm32f10x.c, 进行系统时钟配置。代码如下:
#include "system_stm32f10x.h"
// 实现系统SMT32的时钟配置,操作的是片上的RCC这个外设。
// 系统上电后,首先会执行由汇编编写的启动文件,启动文件中的复位函数会调用本文件中的SystemInit()函数来配置时钟。
// 调用完毕后,系统的时钟就被初始化为72M.
// 如果需要重新配置系统时钟,则修改此函数
void SystemInit(void)
{
; // 暂时为空,系统时钟默认被初始化为72M
}
// 其他代码详见:systme_stm32f10x.h
#ifndef __STM32F10X_H__
#define __STM32F10X_H__
// 实现系统SMT32的时钟配置,操作的是片上的RCC这个外设。
// 系统上电后,首先会执行由汇编编写的启动文件,启动文件中的复位函数会调用本文件中的SystemInit()函数来配置时钟。
// 调用完毕后,系统的时钟就被初始化为72M.
// 如果需要重新配置系统时钟,则修改此函数
void SystemInit(void);
// 其他代码详见:systme_stm32f10x.h
#endif
1.2.1.4 xxxx.h和xxxx.c的说明
xxxx.h和xxxx.c成对出现,xxxx.h中定义变量和函数声明,而xxxx.c中则为xxxx.h中声明函数的实现体
注意:
- 在xxxx.c中 “#include xxxx.h”
- 要将xxxx.c文件添加到工程中,(xxxx.h不用添加,因为xxxx.c中已经#include进去了,编译时系统会自动查找xxxx.h并将其导入工程中)
- 当yyyy.c要调用xxxx.c中所定义的函数时,只需要在yyyy.c中#include "xxxx.h"即可(不是xxxx.c !!!)
所以:
- 要先将 system_stm32f10x.c 文件添加到工程中
- system_stm32f10x.h不用添加,只需要在stm32f10x.h中#include "system_stm32f10x.h"即可
1.2 建立stm32f10x.h 文件 (核心文件之一!!!!但是不用添加到工程中)
#ifndef __STM32F10X_H
#define __STM32F10X_H
#include "core_cm3.h" // #define __IO volatile
#include "stdint.h"
#include "system_stm32f10x.h" // 这里包含来SystemInit()函数,默认将时钟配置为72M,即此时AHB时钟为72M,APB2为72MHz,APB1为36MHz。
// 当STM32上电后,执行xxxx.S启动文件时,会调用SystemInit()函数,将系统时钟配置为以上状态
/// 1、 每个外设的寄存器结构体定义
typedef struct
{
uint32_t CRL;
uint32_t CRH;
uint32_t IDR;
uint32_t ODR;
uint32_t BSRR;
uint32_t BRR;
uint32_t LCKR;
}GPIO_TypeDef;
typedef struct
{
uint32_t CR;
uint32_t CFGR;
uint32_t CIR;
uint32_t APB2RSTR;
uint32_t APB1RSTR;
uint32_t AHBENR;
uint32_t APB2ENR;
uint32_t APB1ENR;
uint32_t BDCR;
uint32_t CSR;
}RCC_TypeDef;
/// 2、 总线及外设基地址映射
/*!< Peripheral memory map */
#define PERIPH_BASE ((unsigned int)0x40000000)
#define APB1PERIPH_BASE PERIPH_BASE
#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)
#define AHBPERIPH_BASE (PERIPH_BASE + 0x20000)
#define RCC_BASE (AHBPERIPH_BASE + 0x1000) // RCC寄存器的基地址
#define GPIOA_BASE (APB2PERIPH_BASE + 0x0800)
#define GPIOB_BASE (APB2PERIPH_BASE + 0x0C00)
#define GPIOC_BASE (APB2PERIPH_BASE + 0x1000)
#define GPIOD_BASE (APB2PERIPH_BASE + 0x1400)
#define GPIOE_BASE (APB2PERIPH_BASE + 0x1800)
#define GPIOF_BASE (APB2PERIPH_BASE + 0x1C00)
#define GPIOG_BASE (APB2PERIPH_BASE + 0x2000)
/// 3、 声明指向该外设基地址的结构体指针
#define RCC ((RCC_TypeDef*)RCC_BASE)
#define GPIOA ((GPIO_TypeDef*) GPIOA_BASE)
#define GPIOB ((GPIO_TypeDef*) GPIOB_BASE)
#define GPIOC ((GPIO_TypeDef*) GPIOC_BASE)
#define GPIOD ((GPIO_TypeDef*) GPIOD_BASE)
#define GPIOE ((GPIO_TypeDef*) GPIOE_BASE)
#define GPIOF ((GPIO_TypeDef*) GPIOF_BASE)
#define GPIOG ((GPIO_TypeDef*) GPIOG_BASE)
#endif /* __STM32F10X_H */
1.3. 建立外设驱动文件: GPIO外设
1.3.1 建立stm32f10x_gpio.h 头文件(不用添加到工程中)
#ifndef __STM32F10X_GPIO_H__
#define __STM32F10X_GPIO_H__
// 本头文件要用到stm32f10x.h中的如下定义: uint16_t等 数据类型, GPIO_TypeDef等外设结构体定义, GPIOx等外设结构体指针声明
#include "stm32f10x.h" //
// 1. GPIO 的引脚定义,即宏定义 1<<n
#define GPIO_Pin_0 ((uint16_t)0x0001) /*!< 选择Pin0 */ //(00000000 00000001)b
#define GPIO_Pin_1 ((uint16_t)0x0002) /*!< 选择Pin1 */ //(00000000 00000010)b
#define GPIO_Pin_2 ((uint16_t)0x0004) /*!< 选择Pin2 */ //(00000000 00000100)b
#define GPIO_Pin_3 ((uint16_t)0x0008) /*!< 选择Pin3 */ //(00000000 00001000)b
#define GPIO_Pin_4 ((uint16_t)0x0010) /*!< 选择Pin4 */ //(00000000 00010000)b
#define GPIO_Pin_5 ((uint16_t)0x0020) /*!< 选择Pin5 */ //(00000000 00100000)b
#define GPIO_Pin_6 ((uint16_t)0x0040) /*!< 选择Pin6 */ //(00000000 01000000)b
#define GPIO_Pin_7 ((uint16_t)0x0080) /*!< 选择Pin7 */ //(00000000 10000000)b
#define GPIO_Pin_8 ((uint16_t)0x0100) /*!< 选择Pin8 */ //(00000001 00000000)b
#define GPIO_Pin_9 ((uint16_t)0x0200) /*!< 选择Pin9 */ //(00000010 00000000)b
#define GPIO_Pin_10 ((uint16_t)0x0400) /*!< 选择Pin10 */ //(00000100 00000000)b
#define GPIO_Pin_11 ((uint16_t)0x0800) /*!< 选择Pin11 */ //(00001000 00000000)b
#define GPIO_Pin_12 ((uint16_t)0x1000) /*!< 选择Pin12 */ //(00010000 00000000)b
#define GPIO_Pin_13 ((uint16_t)0x2000) /*!< 选择Pin13 */ //(00100000 00000000)b
#define GPIO_Pin_14 ((uint16_t)0x4000) /*!< 选择Pin14 */ //(01000000 00000000)b
#define GPIO_Pin_15 ((uint16_t)0x8000) /*!< 选择Pin15 */ //(10000000 00000000)b
#define GPIO_Pin_All ((uint16_t)0xFFFF) /*!< 选择全部引脚*/ //(11111111 11111111)b
// 2. 定义引脚模式和速度的枚举类型
typedef enum
{
GPIO_Speed_10MHz = 1, // 10MHZ (01)b
GPIO_Speed_2MHz, // 2MHZ (10)b
GPIO_Speed_50MHz // 50MHZ (11)b
}GPIOSpeed_TypeDef;
typedef enum
{ GPIO_Mode_AIN = 0x0, // 模拟输入 (0000 0000)b
GPIO_Mode_IN_FLOATING = 0x04, // 浮空输入 (0000 0100)b
GPIO_Mode_IPD = 0x28, // 下拉输入 (0010 1000)b
GPIO_Mode_IPU = 0x48, // 上拉输入 (0100 1000)b
GPIO_Mode_Out_OD = 0x14, // 开漏输出 (0001 0100)b
GPIO_Mode_Out_PP = 0x10, // 推挽输出 (0001 0000)b
GPIO_Mode_AF_OD = 0x1C, // 复用开漏输出 (0001 1100)b
GPIO_Mode_AF_PP = 0x18 // 复用推挽输出 (0001 1000)b
}GPIOMode_TypeDef;
//3. 定义初始化结构体
typedef struct
{
uint16_t GPIO_Pin; /*要配置的引脚号*/
GPIOSpeed_TypeDef GPIO_Speed; /* 引脚的输出速度 */
GPIOMode_TypeDef GPIO_Mode; /* 引脚的输入/输出模式*/
}GPIO_InitTypeDef;
// 4. GPIO各操作函数的声明
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct); // GPIOx端口引脚初始化
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); // GPIOx端口的GPIO_Pin引脚置高, = 1
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); // GPIOx端口的GPIO_Pin引脚置低, = 0
#endif
1.3.2. 建立stm32f10x_gpio.c文件(需要添加到工程中)
#include "stm32f10x.h" //
#include "stm32f10x_gpio.h"
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
GPIOx->BSRR |= GPIO_Pin;
}
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
GPIOx->BRR |= GPIO_Pin;
}
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)
{
uint32_t currentmode = 0x00, currentpin = 0x00, pinpos = 0x00, pos = 0x00;
uint32_t tmpreg = 0x00, pinmask = 0x00;
/*---------------------- GPIO 模式配置 --------------------------*/
// 把输入参数GPIO_Mode的低四位暂存在currentmode
currentmode = ((uint32_t)GPIO_InitStruct->GPIO_Mode) & ((uint32_t)0x0F);
// bit4是1表示输出,bit4是0则是输入
// 判断bit4是1还是0,即首选判断是输入还是输出模式
if ((((uint32_t)GPIO_InitStruct->GPIO_Mode) & ((uint32_t)0x10)) != 0x00)
{
// 输出模式则要设置输出速度
currentmode |= (uint32_t)GPIO_InitStruct->GPIO_Speed;
}
/*-------------GPIO CRL 寄存器配置 CRL寄存器控制着低8位IO- -------*/
// 配置端口低8位,即Pin0~Pin7
if (((uint32_t)GPIO_InitStruct->GPIO_Pin & ((uint32_t)0x00FF)) != 0x00)
{
// 先备份CRL寄存器的值
tmpreg = GPIOx->CRL;
// 循环,从Pin0开始配对,找出具体的Pin
for (pinpos = 0x00; pinpos < 0x08; pinpos++)
{
// pos的值为1左移pinpos位
pos = ((uint32_t)0x01) << pinpos;
// 令pos与输入参数GPIO_PIN作位与运算,为下面的判断作准备
currentpin = (GPIO_InitStruct->GPIO_Pin) & pos;
//若currentpin=pos,则找到使用的引脚
if (currentpin == pos)
{
// pinpos的值左移两位(乘以4),因为寄存器中4个寄存器位配置一个引脚
pos = pinpos << 2;
//把控制这个引脚的4个寄存器位清零,其它寄存器位不变
pinmask = ((uint32_t)0x0F) << pos;
tmpreg &= ~pinmask;
// 向寄存器写入将要配置的引脚的模式
tmpreg |= (currentmode << pos);
// 判断是否为下拉输入模式
if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD)
{
// 下拉输入模式,引脚默认置0,对BRR寄存器写1可对引脚置0
GPIOx->BRR = (((uint32_t)0x01) << pinpos);
}
else
{
// 判断是否为上拉输入模式
if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU)
{
// 上拉输入模式,引脚默认值为1,对BSRR寄存器写1可对引脚置1
GPIOx->BSRR = (((uint32_t)0x01) << pinpos);
}
}
}
}
// 把前面处理后的暂存值写入到CRL寄存器之中
GPIOx->CRL = tmpreg;
}
/*-------------GPIO CRH 寄存器配置 CRH寄存器控制着高8位IO- -----------*/
// 配置端口高8位,即Pin8~Pin15
if (GPIO_InitStruct->GPIO_Pin > 0x00FF)
{
// // 先备份CRH寄存器的值
tmpreg = GPIOx->CRH;
// 循环,从Pin8开始配对,找出具体的Pin
for (pinpos = 0x00; pinpos < 0x08; pinpos++)
{
pos = (((uint32_t)0x01) << (pinpos + 0x08));
// pos与输入参数GPIO_PIN作位与运算
currentpin = ((GPIO_InitStruct->GPIO_Pin) & pos);
//若currentpin=pos,则找到使用的引脚
if (currentpin == pos)
{
//pinpos的值左移两位(乘以4),因为寄存器中4个寄存器位配置一个引脚
pos = pinpos << 2;
//把控制这个引脚的4个寄存器位清零,其它寄存器位不变
pinmask = ((uint32_t)0x0F) << pos;
tmpreg &= ~pinmask;
// 向寄存器写入将要配置的引脚的模式
tmpreg |= (currentmode << pos);
// 判断是否为下拉输入模式
if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD)
{
// 下拉输入模式,引脚默认置0,对BRR寄存器写1可对引脚置0
GPIOx->BRR = (((uint32_t)0x01) << (pinpos + 0x08));
}
// 判断是否为上拉输入模式
if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU)
{
// 上拉输入模式,引脚默认值为1,对BSRR寄存器写1可对引脚置1
GPIOx->BSRR = (((uint32_t)0x01) << (pinpos + 0x08));
}
}
}
// 把前面处理后的暂存值写入到CRH寄存器之中
GPIOx->CRH = tmpreg;
}
}
1.4 . 建立main.c主函数 (需要添加到工程中)
#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
void Delay_ms(uint32_t timeMs)
{
uint32_t i = 0;
while(timeMs--)
{
i = 1200;
while(i--);
}
}
int main (void)
{
GPIO_InitTypeDef GPIO_InitStructure;
// 打开 GPIOB 端口的时钟
RCC->APB2ENR |= ( (1) << 3 );
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; // GPIO_Pin_12
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //输出速度为50M
GPIO_Init(GPIOB, &GPIO_InitStructure); // PB12 引脚初始化
while(1)
{
GPIO_SetBits(GPIOB,GPIO_Pin_12); // PB12置高, = 1, 灭灯
Delay_ms(1000);
GPIO_ResetBits(GPIOB,GPIO_Pin_12); // PB12置低, = 0, 亮灯
Delay_ms(1000);
}
}
1.5 将工程所需要的文件添加到工程中
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AZ9KDSzm-1635738492280)(%E5%BB%BA%E7%AB%8B%E8%87%AA%E5%B7%B1%E7%9A%84STM32%E5%BA%93%E5%87%BD%E6%95%B0%E5%B7%A5%E7%A8%8B%EF%BC%881%EF%BC%89–%E8%87%AA%E5%BB%BAstm32f10x.h.assets/1111-16356986004072-16356986269583.png)]
2. 改进:定义自定义的文件,保存自定义的变量和函数,如延时函数等
2.1 定义myfun.h(不用添加到工程中)
#ifndef __MYFUN_H
#define __MYFUN_H
#include "stm32f10x.h" // 要用到 uint32_t
void Delay_ms(uint32_t timeMs);
void Delay_us(uint32_t count);
#endif
2.2 定义myfun.c(需要添加到工程中)
#include "myfun.h"
void Delay_us(uint32_t count)
{
for( ; count !=0; count-- );
}
void Delay_ms(uint32_t timeMs)
{
uint32_t i = 0;
while(timeMs--)
{
i = 1200;
while(i--);
}
}
2.3 修改main.c函数
- 删除main.c中的Delay()函数,并在main.c中添加:#include “myfun.h”
- 将GPIOB、GPIO_Pin_12、开端口时钟 进一步用宏“封装”
#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
#include "myfun.h"
int main (void)
{
GPIO_InitTypeDef GPIO_InitStructure;
// 打开 GPIOB 端口的时钟
RCC->APB2ENR |= ( (1) << 3 );
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; // GPIO_Pin_12
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //输出速度为50M
GPIO_Init(GPIOB, &GPIO_InitStructure); // PB12 引脚初始化
while(1)
{
GPIO_SetBits(GPIOB,GPIO_Pin_12); // PB12置高, = 1, 灭灯
Delay_ms(1000);
GPIO_ResetBits(GPIOB,GPIO_Pin_12); // PB12置低, = 0, 亮灯
Delay_ms(1000);
}
}
2.4 进一步封装LED初始化函数
2.4.1 新建bsp_led.h
#ifndef __BSP_LED_H__
#define __BSP_LED_H__
#define LED_D3_GPIO_PORT GPIOB
#define LED_D3_GPIO_CLK_ENABLE (RCC->APB2ENR |= ( (1) << 3 ))
#define LED_D3_GPIO_PIN GPIO_Pin_12
void LED_Init(void);
#endif
2.4.2 新建bsp_led.c
#include "bsp_led.h"
#include "stm32f10x_gpio.h" //注意添加,注意该头文件已经添加了#include "stm32f10x.h",意味着我们可以直接用数据类型、外设寄存器
//uint32_t time;
//GPIOC->RHL = 0xff;
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
// 打开 GPIOB 端口的时钟
LED_D3_GPIO_CLK_ENABLE;
GPIO_InitStructure.GPIO_Pin = LED_D3_GPIO_PIN; // GPIO_Pin_12
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //输出速度为50M
GPIO_Init(LED_D3_GPIO_PORT, &GPIO_InitStructure); // PB12 引脚初始化
}
2.4.3 封装后后的main.c
- 在main.c中添加:#include “bsp_led.h”
- 将bsp_led.c添加到工程中去
#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
#include "myfun.h"
#include "bsp_led.h"
int main (void)
{
LED_Init();
while(1)
{
GPIO_SetBits(LED_D3_GPIO_PORT,LED_D3_GPIO_PIN); // PB12置高, = 1, 灭灯
Delay_ms(1000);
GPIO_ResetBits(LED_D3_GPIO_PORT,LED_D3_GPIO_PIN); // PB12置低, = 0, 亮灯
Delay_ms(1000);
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Qk5FDUa3-1635738492282)(%E5%BB%BA%E7%AB%8B%E8%87%AA%E5%B7%B1%E7%9A%84STM32%E5%BA%93%E5%87%BD%E6%95%B0%E5%B7%A5%E7%A8%8B%EF%BC%881%EF%BC%89–%E8%87%AA%E5%BB%BAstm32f10x.h.assets/%5BD1ME@P%7D1$8(3EF)]O4B%7D8H-16357006028724.png)
3. 尝试用库中的stm32f10x.h
在需要用到数据类型、外设寄存器结构体定义、外设寄存器基地址映射、指向外设寄存器基地址的指针声明的时候,在该文件中#include “stm32f10x.h”即可
注意,如果是xxx.h 和xxx.c 成对出现时,只需要在xxx.h文件中 #include “stm32f10x.h”即可,而xxx.c文件中不需要,否则出现重定义错误。
4. 继续封装stm32f10x_xxx.h
例如:要用到gpio、rcc、spi、tim、usart外设,则需要分别将各外设的配置头文件#include stm32f10x_xxx.h进来。当工程中要用到的外设比较多时,则需要包含很多文件。所以,
为了简单,直接用stm32f10x_conf.h 对所有外设的头文件进行来封装,所以直接# include "stm32f10x_conf.h"后,就自动把所有外设的头文件包括进来了
。当然为了简化代码,可以手动将不用的外设头文件从stm32f10x_conf.h中暂时注释掉。
例如:LED点灯时,只需要用到stm32f10x_gpio.h,则在 **#include “stm32f10x.h” **中将 其他的都注释掉。
#ifndef __STM32F10X_CONF_H
#define __STM32F10X_CONF_H
#include "stm32f10x_gpio.h"
//#include "stm32f10x_adc.h"
//#include "stm32f10x_bkp.h"
//#include "stm32f10x_can.h"
//#include "stm32f10x_cec.h"
//#include "stm32f10x_crc.h"
//#include "stm32f10x_dac.h"
//#include "stm32f10x_dbgmcu.h"
//#include "stm32f10x_dma.h"
//#include "stm32f10x_exti.h"
//#include "stm32f10x_flash.h"
//#include "stm32f10x_fsmc.h"
//#include "stm32f10x_i2c.h"
//#include "stm32f10x_iwdg.h"
//#include "stm32f10x_pwr.h"
//#include "stm32f10x_rcc.h"
//#include "stm32f10x_rtc.h"
//#include "stm32f10x_sdio.h"
//#include "stm32f10x_spi.h"
//#include "stm32f10x_tim.h"
//#include "stm32f10x_usart.h"
// #include "stm32f10x_wwdg.h"
// #include "misc.h" /* High level functions for NVIC and SysTick (add-on to CMSIS functions) */
#endif
stm32f10x_conf.h中包含了所有外设的头文件,因此任意源文件只要包含了stm32f10x.h,就可以在源文件调用任意外设的函数。
若有外设未使用到,在stm32f10x_conf.h注释相应部分,项目编译时就不会在编译去掉的外设。
4.1 如何使用
方法1:直接在main.c中 #include “stm32f10x_conf.h”
方法2:使用固件库时,配置keil编译器---->魔法棒—> 在Define处添加:USE_STDPERIPH_DRIVER
解释,编译器中如上配置好后,stm32f10x.h中的如下代码起作用,会把stm32f10x_conf.h包含进来
#ifdef USE_STDPERIPH_DRIVER
#include "stm32f10x_conf.h"
#endif