【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; 
    } 
}


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

相关推荐
ACP广源盛139246256732 小时前
GSV6701A@ACP#6701A产品规格详解及产品应用分享
网络·嵌入式硬件·音视频
自由生长20242 小时前
构建 AI-Ready 软件:三层接口模型与智能调度架构
架构
喜欢吃豆2 小时前
大语言模型混合专家(MoE)架构深度技术综述
人工智能·语言模型·架构·moe
国科安芯2 小时前
商业卫星光电载荷控制系统中MCU抗辐照性能评估方法研究
单片机·嵌入式硬件·数码相机·性能优化·架构·risc-v
Mr_chiu2 小时前
微前端从入门到精通:Vue开发者的大型应用架构演进指南
前端·架构
七夜zippoe2 小时前
轻量级多模态模型实战:从Qwen3-VL-4B到企业级应用
架构·大模型·多模态·轻量·qwen3
Terasic友晶科技3 小时前
5-DE10-Nano的HDMI方块移动案例——基于FPGA的I2C控制模块设计
单片机·嵌入式硬件·fpga开发·时钟分频·hdmi方块移动·i2c控制模块设计·配置寄存器
v先v关v住v获v取3 小时前
杨柳絮收集装置设计cad1张总图+三维图+设计说明书
科技·单片机·51单片机
切糕师学AI3 小时前
ARM 汇编指令:PUSH 和 POP
汇编·arm开发·assembly