【ARM】从零封装STM32标准库

这篇文章是 STM32F10x系列 GPIO 外设的寄存器定义和操作函数。头文件stm32f10x.h 定义了 GPIO 和 RCC 外设的寄存器结构体、基地址映射、引脚编号枚举以及工作模式/速度配置类型。stm32f10x_gpio.h 声明了三个关键函数:GPIO_SetBits/ResetBits 用于控制引脚输出电平,GPIO_Init 函数实现引脚模式初始化,通过分析 GPIO_Mode 参数判断输入/输出模式,并配置 CRL/CRH 寄存器设置具体引脚的工作模式和速度。整个设计采用寄存器直接映射方式,通过结构体指针访问外设寄存器,实现了对 STM32 GPIO 外设的底层硬件控制。

stm32f10x.h

c 复制代码
#ifndef __STM32F10X_H__ 
#define __STM32F10X_H__ 
//volatile表⽰容易变得变量,防⽌编译器优化, 
#define __IO volatile 
typedef unsigned int uint32_t; 
typedef unsigned short uint16_t; 
// GPIO寄存器结构体定义 
typedef struct 
{ 
    __IO uint32_t CRL; //端⼝配置低寄存器,偏移地址0X00 
    __IO uint32_t CRH; //端⼝配置⾼寄存器,地址偏移0X04 
    __IO uint32_t IDR; //端⼝数据输⼊寄存器,地址偏移0X08 
    __IO uint32_t ODR; //端⼝数据输出寄存器,地址偏移0X0C 
    __IO uint32_t BSRR; //端⼝位设置、清除寄存器,地址偏移0X10 
    __IO uint32_t BRR; //端⼝位清除寄存器,地址偏移0X14 
    __IO uint32_t LCKR; //端⼝配置锁定寄存器,地址偏移0X18 
} GPIO_TypeDef; 

typedef struct 
{ 
    __IO uint32_t CR; 
    __IO uint32_t CFGR; 
    __IO uint32_t CIR; 
    __IO uint32_t APB2RSTR; 
    __IO uint32_t APB1RSTR; 
    __IO uint32_t AHBENR; 
    __IO uint32_t APB2ENR; 
    __IO uint32_t APB1ENR; 
    __IO uint32_t BDCR; 
    __IO uint32_t CSR; 
} RCC_TypeDef; 

/*⽚上外设基地址*/ 
#define PERIPH_BASE ((unsigned int)0x40000000) 
/*APB2总线基地址*/ 
#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000) 
/*AHB总线基地址*/ 
#define AHBPERIPH_BASE (PERIPH_BASE + 0x20000) 

/*RCC外设基地址*/
#define RCC_BASE (AHBPERIPH_BASE + 0x1000) 
#define RCC_APB2ENR *(unsigned int*)(RCC_BASE+0x18) 

/*GPIO外设基地址*/ 
#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) 

/* GPIOC寄存器地址*/ 
#define GPIOC_CRL *(unsigned int*)(GPIOC_BASE+0x00) 
#define GPIOC_CRH *(unsigned int*)(GPIOC_BASE+0x04) 
#define GPIOC_IDR *(unsigned int*)(GPIOC_BASE+0x08) 
#define GPIOC_ODR *(unsigned int*)(GPIOC_BASE+0x0C) 
#define GPIOC_BSRR *(unsigned int*)(GPIOC_BASE+0x10) 
#define GPIOC_BRR *(unsigned int*)(GPIOC_BASE+0x14) 
#define GPIOC_LCKR *(unsigned int*)(GPIOC_BASE+0x18) 

#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) 
// RCC 外设声明 
#define RCC ((RCC_TypeDef *) RCC_BASE) 

#define GPIO_Pin_0 (uint16_t)0x0001) 
#define GPIO_Pin_1 ((uint16_t)0x0002) 
#define GPIO_Pin_2 ((uint16_t)0x0004) 
#define GPIO_Pin_3 ((uint16_t)0x0008) 
#define GPIO_Pin_4 ((uint16_t)0x0010) 
#define GPIO_Pin_5 ((uint16_t)0x0020) 
#define GPIO_Pin_6 ((uint16_t)0x0040) 
#define GPIO_Pin_7 ((uint16_t)0x0080) 
#define GPIO_Pin_8 ((uint16_t)0x0100) 
#define GPIO_Pin_9 ((uint16_t)0x0200) 
#define GPIO_Pin_10 ((uint16_t)0x0400) 
#define GPIO_Pin_11 ((uint16_t)0x0800) 
#define GPIO_Pin_12 ((uint16_t)0x1000) 
#define GPIO_Pin_13 ((uint16_t)0x2000) 
#define GPIO_Pin_14 ((uint16_t)0x4000) 
#define GPIO_Pin_15 ((uint16_t)0x8000)

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, 
    GPIO_Mode_IN_FLOATING = 0x04, 
    GPIO_Mode_IPD = 0x28, 
    GPIO_Mode_IPU = 0x48, 
    GPIO_Mode_Out_OD = 0x14, 
    GPIO_Mode_Out_PP = 0x10, 
    GPIO_Mode_AF_OD = 0x1C, 
    GPIO_Mode_AF_PP = 0x18 
} GPIOMode_TypeDef; 

typedef struct 
{ 
    uint16_t GPIO_Pin; 
    GPIOSpeed_TypeDef GPIO_Speed; 
    GPIOMode_TypeDef GPIO_Mode; 
} GPIO_InitTypeDef; 

#endif

stm32f10x_gpio.h

c 复制代码
#ifndef __STM32F10X_GPIO__ 
#define __STM32F10X_GPIO__ 
#include "stm32f10x.h" 
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); 
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); 
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct); 
#endif
c 复制代码
#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; 
} 

/** 
*函数功能:初始化引脚模式 
*参数说明: GPIOx,该参数为 GPIO_TypeDef 类型的指针,指向 GPIO 端⼝的地址 
* GPIO_InitTypeDef:GPIO_InitTypeDef 结构体指针,指向初始化变量 
*/ 
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)); 
                } 
            } 
        } 
        GPIOx->CRH = tmpreg; 
    } 
}


以上,欢迎有从事同行业的电子信息工程、互联网通信、嵌入式开发的朋友共同探讨与提问,我可以提供实战演示或模板库。希望内容能够对你产生帮助!

相关推荐
守护安静星空2 小时前
esp32开发笔记-工程搭建
笔记·单片机·嵌入式硬件·物联网·visual studio code
ACP广源盛139246256733 小时前
破局 Type‑C 切换器痛点@ACP#GSV6155+LH3828/GSV2221+LH3828 黄金方案
c语言·开发语言·网络·人工智能·嵌入式硬件·计算机外设·电脑
时空自由民.4 小时前
ST7701S 3.5寸显示屏
单片机
Henb9294 小时前
# 大规模数据平台架构演进
架构
金戈鐡馬4 小时前
BetaFlight中的定时器引脚绑定详解
stm32·单片机·嵌入式硬件·无人机
小程故事多_805 小时前
从零吃透Transformer核心,多头注意力、残差连接与前馈网络(大白话完整版)
人工智能·深度学习·架构·aigc·transformer
Arenaschi5 小时前
国产麒麟X86结构和arm架构的区别
arm开发
Wave8455 小时前
FreeRTOS软件定时器详解
stm32·单片机·freertos
VBsemi-专注于MOSFET研发定制6 小时前
奶茶制作机器人功率MOSFET选型方案——高效、精准与可靠驱动系统设计指南
单片机·嵌入式硬件
Warren2Lynch6 小时前
AI 驱动的 UML 图表支持全景指南
人工智能·架构·uml