STM32(8)-- 自己创建库函数

复制寄存器版本的项目进行修改

1. STM32函数库

2. 自己创建库函数

2.1 修改寄存器地址封装

GPIO这个外设共10个寄存器,GPIOA有10个,GPIOB有10个。。。。。

首先要进行条件编译,防止头文件被重复包含

因为 C/C++ 的 #include 本质是"把头文件内容原封不动复制粘贴到当前位置" 。一旦同一个头文件在同一个 .c/.cpp 编译单元里被展开了两次,里面如果有类型定义、变量定义、某些宏定义 等,就可能出现 重复定义语义冲突

头文件为什么会被重复包含?

最常见是"间接包含":

场景:A.h 和 B.h 都包含了 C.h

cpp 复制代码
// A.h
#include "C.h"

// B.h
#include "C.h"

// main.c
#include "A.h"
#include "B.h"

编译 main.c 时,预处理会展开成(示意):

cpp 复制代码
// main.c 展开后的样子(示意)
... A.h 的内容 ...
... C.h 的内容 ...   // 第一次来自 A.h

... B.h 的内容 ...
... C.h 的内容 ...   // 第二次来自 B.h

所以 你明明只写了一次 #include "C.h"

不,你写的是 #include A.h#include B.h,它们内部都把 C.h 又带进来了,于是 C.h 被"复制粘贴"了两遍。

每一种相同的外设所涉及的寄存器基本都是完全一样的,如GPIOA/B/C,USART1/2。。。。

外设的每个寄存器都是32位的,而且地址都是连续的,都是基于基地址的偏移,也就是说是一块连续的内存空间。那就可以为这个外设的寄存器们创建一个结构体,成员的顺序就是按照地址由小到大的各个寄存器。

知道了这个结构体的首地址(也就是这个外设的基地址/此外设的第一个寄存器的地址),就可以访问这个结构体的所有成员,注意地址要为结构体指针类型的

cpp 复制代码
typedef unsigned int  			uint32_t;
typedef unsigned short int      uint16_t;

关于类型名的重命名,也可以包含  stdint.h
这是keil的安装目录下自带的

//GPIO外设寄存器结构体定义
typedef struct
{
	uint32_t MODER;
	uint32_t OTYPER;
	uint32_t OSPEEDR;
	uint32_t PUPDR;
	uint32_t IDR;
	uint32_t ODR;
	uint16_t BSRRL;
	uint16_t BSRRH;
	uint32_t LCKR;
	uint32_t AFRL;
	uint32_t AFRH;
}	GPIO_TypeDef;

#define GPIOF  ((GPIO_TypeDef*)GPIOF_BASE)

经过以上定义后,就可将main函数中的GPIO配置的寄存器操作进行修改,通过访问结构体的成员来操作寄存器

修改前

修改后

cpp 复制代码
#include "stm32f4xx.h"
int main()
{
	//开启GPIOF时钟
	RCC_AHB1ENR |= (1<<5);
	//GPIOF MODER6 清空
	GPIOF->MODER &= ~(0x03<<(2*6));
	//PF6 输出模式
	GPIOF->MODER |= (1<<2*6);
	//GPIOF OTYPER6清空
	GPIOF->OTYPER &= ~(1<<1*6);
	//推挽模式
	GPIOF->OTYPER |= (0<<1*6);
	//GPIOF_OSPEEDR6清空
	GPIOF->OSPEEDR &= ~(0x03<<2*6);
	//2MHz
	GPIOF->OSPEEDR |= (0<<2*6);
	//清空
	GPIOF->PUPDR &= ~(0x03<<2*6);
	//上拉
	GPIOF->PUPDR |= (1<<2*6);
	//控制引脚输出低电平
	GPIOF->BSRRL |= (1<<16<<6);
	//控制引脚输出高电平
	GPIOF->BSRRH |= (1<<6);
	while(1)
	{
		
	}
}

2.2 定义GPIO的位操作函数

因为是操作GPIO外设的,所以新增一个关于gpio的.c和.h文件

并在.c文件中包含自己的头文件,在.h文件中进行条件编译

在gpio.c中一定会用到stm32f4xx.h中映射的各种寄存器,需在gpio.h中包含,所以说就是在.c中想用到哪个.h文件,在自己的.h文件中包含这个.h就行了

编写GPIO置位/复位的函数

gpio.c文件:

cpp 复制代码
#include "gpio.h"

void GPIO_SetBits(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin)//置高电平
{
	GPIOx->BSRRL = GPIO_Pin;
}

void GPIO_ReSetBits(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin)//置低电平
{
	GPIOx->BSRRH = GPIO_Pin;
}

gpio.h文件:

cpp 复制代码
#include "stm32f4xx.h"
#define GPIO_Pin0   (uint16_t)(1<<0)
#define GPIO_Pin1   (uint16_t)(1<<1)
#define GPIO_Pin2   (uint16_t)(1<<2)
#define GPIO_Pin3   (uint16_t)(1<<3)
#define GPIO_Pin4   (uint16_t)(1<<4)
#define GPIO_Pin5   (uint16_t)(1<<5)
#define GPIO_Pin6   (uint16_t)(1<<6)
#define GPIO_Pin7   (uint16_t)(1<<7)
#define GPIO_Pin8   (uint16_t)(1<<8)
#define GPIO_Pin9   (uint16_t)(1<<9)
#define GPIO_Pin10  (uint16_t)(1<<10)
#define GPIO_Pin11  (uint16_t)(1<<11)
#define GPIO_Pin12  (uint16_t)(1<<12)
#define GPIO_Pin13  (uint16_t)(1<<13)
#define GPIO_Pin14  (uint16_t)(1<<14)
#define GPIO_Pin15  (uint16_t)(1<<15)

void GPIO_SetBits(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin);
void GPIO_ReSetBits(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin);

#endif //_GPIO_H

经过如上定义,操作寄存器的语句和被替换为自己写的两个函数

相关推荐
俊基科技1 小时前
A-59U工业级多模语音处理模块在矿山矿井通信与呼叫报警系统中的应用
嵌入式硬件·嵌入式开发·硬件开发·ai降噪·回音消除·拾音降噪
周周记笔记3 小时前
GD32F450xx MCU Datasheet 解读:硬件测试工程师的测试方法论
单片机·嵌入式硬件
潘潘的嵌入式日记5 小时前
I²C 从机接收总被覆盖?双缓冲要在 STOP 时交接
c语言·开发语言·单片机
AOI小白新手上路6 小时前
江科协51单片机16-1 AD/DA ADC 三通道综合显示(LCD1602 版)改造说明
单片机·嵌入式硬件·51单片机
HUI-4747 小时前
EG1135|SSOP‑16 同步整流降压控制器,大功率外置 MOS 降压优选
单片机·嵌入式硬件·硬件工程
单片机仿真设计8 小时前
【proteus仿真】基于 STM32 单片机恒温箱控制系统设计(仿真图+程序)
stm32·单片机·嵌入式硬件·proteus·毕设
国科安芯8 小时前
星载CAN总线通信网络中抗辐射MCU的通信可靠性设计分析
网络·人工智能·分布式·单片机·嵌入式硬件·架构
新晨单片机设计9 小时前
S003A-基于STM32单片机温度计(数码管显示)【Proteus仿真+Keil程序+原理图】
stm32·单片机·stm32单片机功能定制
一条破秋裤10 小时前
TIM 输入捕获与 PWMI:从边沿到频率、占空比
笔记·stm32·学习
AOI小白新手上路10 小时前
江科协51单片机16-1 DA数模转换实验(PWM 呼吸灯)
单片机·嵌入式硬件·51单片机