找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1255|回复: 4
收起左侧

关于STM32F103RC单片机的GPIO初始化封装(寄存器)

[复制链接]
回帖奖励 1 黑币 回复本帖可获得 1 黑币奖励! 每人限 1 次
ID:728915 发表于 2023-2-10 10:04 | 显示全部楼层 |阅读模式
接触单片机也有两年了,之前是一直使用库函数的操作方式,然后逐渐有,提高封装函数通用性稍微强一点的想法。库函数因为是有别人写好的一系列封装函数,所以库不变的情况下,还是比较方便的。参考了各位大佬们分享的帖子,后面自己再处理了一下。   

上内容:(用枚是为了收纳方便)
/**************GPIO.H文件**************/
#ifndef __GPIO_H
#define __GPIO_H

#include "stm32f10x.h"                  // Device header

typedef enum        //枚举:PIN脚
{
         PIN0        =        1<<0        ,        PIN1        =        1<<1    ,
         PIN2        =        1<<2    ,        PIN3        =        1<<3    ,
         PIN4        =        1<<4    ,        PIN5        =        1<<5    ,
         PIN6        =        1<<6    ,        PIN7        =        1<<7    ,
         PIN8        =        1<<8    ,        PIN9        =        1<<9    ,
         PIN10        =        1<<10   ,        PIN11        =        1<<11   ,
         PIN12        =        1<<12   ,        PIN13        =        1<<13   ,
         PIN14        =        1<<14   ,        PIN15        =        1<<15   ,
}GPIO_PIN_TypeDef;

typedef enum        //枚举:引脚输入/输出模式
{
         GPIO_MODE_IN_ANALOG         =        0        ,        //模拟输入模式
         GPIO_MODE_IN_FLOAT                =        1          ,        //浮空输入模式
         GPIO_MODE_IN_PUPD                =        2          ,   //上拉下拉输入模式
        
         GPIO_MODE_OUT_PP                  =        0          ,        //推挽输出
         GPIO_MODE_OUT_OD                =        1          ,        //开漏输出
         GPIO_MODE_OUT_AFPP                =        2          ,        //复用推挽输出
         GPIO_MODE_OUT_APOD                =        3          ,        //复用开漏输出
}GPIO_MODE_TypeDef;

typedef enum        //枚举:引脚输出速度
{
        GPIO_SPEED_IN        =        0        ,        //GPIO输入模式
        GPIO_SPEED_10M        =        1         ,        //GPIO输出速度10Mhz
        GPIO_SPEED_20M        =        2         ,   //GPIO输出速度20Mhz
        GPIO_SPEED_50M        =   3        ,   //GPIO输出速度50Mhz
}GPIO_SPEED_TypeDef;

typedef struct {        //结构体:GPIO引脚配置项目
        GPIO_TypeDef*         GPIO_x;
        uint32_t                   GPIO_PIN_X;
        uint32_t                   GPIO_MODE;
        uint32_t                   GPIO_SPEED;
        uint8_t                        GPIO_InitState;
}GPIO_InitList;

static GPIO_InitList GPIO_Init_List[ 120 ] =   //添加、修改需要配置的GPIO口
{// GPIO_X, PIN脚,引脚输入/输出模式,引脚输出速度 ,初始输出状态(高低电平)
        {GPIOC, PIN1 , GPIO_MODE_OUT_PP ,GPIO_SPEED_50M,         1        },
        {},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},
        {},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},
        {},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},
        {},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},
        {},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},
        {},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},
    {GPIOC, PIN12, GPIO_MODE_OUT_PP ,GPIO_SPEED_50M,         0        },
};


//位带操作,实现51类似的GPIO控制功能
//具体实现思想,参考<<CM3权威指南>>第五章(87页~92页)。M4同M3类似,只是寄存器地址变了。
typedef enum        //GPIO宏定义及地址映射
{


        //IO口操作宏定义
        #define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2))
        #define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr))
        #define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum))

        //IO口地址映射
        #define GPIOA_ODR_Addr    (GPIOA_BASE+12) //0x4002000C
        #define GPIOB_ODR_Addr    (GPIOB_BASE+12) //0x4002040C
        #define GPIOC_ODR_Addr    (GPIOC_BASE+12) //0x4002080C
        #define GPIOD_ODR_Addr    (GPIOD_BASE+12) //0x40020C0C
        #define GPIOE_ODR_Addr    (GPIOE_BASE+12) //0x4002100C
        #define GPIOF_ODR_Addr    (GPIOF_BASE+12) //0x4002140C   
        #define GPIOG_ODR_Addr    (GPIOG_BASE+12) //0x4002180C   
        #define GPIOH_ODR_Addr    (GPIOH_BASE+12) //0x40021C0C   
        #define GPIOI_ODR_Addr    (GPIOI_BASE+12) //0x4002200C     

        #define GPIOA_IDR_Addr    (GPIOA_BASE+8) //0x40020008
        #define GPIOB_IDR_Addr    (GPIOB_BASE+8) //0x40020408
        #define GPIOC_IDR_Addr    (GPIOC_BASE+8) //0x40020808
        #define GPIOD_IDR_Addr    (GPIOD_BASE+8) //0x40020C08
        #define GPIOE_IDR_Addr    (GPIOE_BASE+8) //0x40020808
        #define GPIOF_IDR_Addr    (GPIOF_BASE+8) //0x40021408
        #define GPIOG_IDR_Addr    (GPIOG_BASE+8) //0x40021808
        #define GPIOH_IDR_Addr    (GPIOH_BASE+8) //0x40021C08
        #define GPIOI_IDR_Addr    (GPIOI_BASE+8) //0x40022008
         
        //IO口操作,只对单一的IO口!
        //确保n的值小于16!
        #define PAout(n)   BIT_ADDR(GPIOA_ODR_Addr,n)  //输出
        #define PAin(n)    BIT_ADDR(GPIOA_IDR_Addr,n)  //输入

        #define PBout(n)   BIT_ADDR(GPIOB_ODR_Addr,n)  //输出
        #define PBin(n)    BIT_ADDR(GPIOB_IDR_Addr,n)  //输入

        #define PCout(n)   BIT_ADDR(GPIOC_ODR_Addr,n)  //输出
        #define PCin(n)    BIT_ADDR(GPIOC_IDR_Addr,n)  //输入

        #define PDout(n)   BIT_ADDR(GPIOD_ODR_Addr,n)  //输出
        #define PDin(n)    BIT_ADDR(GPIOD_IDR_Addr,n)  //输入

        #define PEout(n)   BIT_ADDR(GPIOE_ODR_Addr,n)  //输出
        #define PEin(n)    BIT_ADDR(GPIOE_IDR_Addr,n)  //输入

        #define PFout(n)   BIT_ADDR(GPIOF_ODR_Addr,n)  //输出
        #define PFin(n)    BIT_ADDR(GPIOF_IDR_Addr,n)  //输入

        #define PGout(n)   BIT_ADDR(GPIOG_ODR_Addr,n)  //输出
        #define PGin(n)    BIT_ADDR(GPIOG_IDR_Addr,n)  //输入

        #define PHout(n)   BIT_ADDR(GPIOH_ODR_Addr,n)  //输出
        #define PHin(n)    BIT_ADDR(GPIOH_IDR_Addr,n)  //输入

        #define PIout(n)   BIT_ADDR(GPIOI_ODR_Addr,n)  //输出
        #define PIin(n)    BIT_ADDR(GPIOI_IDR_Addr,n)  //输出
        
        GPIO_Init_Base_END  = 0,        //结束,防止枚举内容为空,无实际意义
        
}GPIO_Init_Base_;

void GPIO_Set(GPIO_TypeDef* GPIOx, uint32_t BITx, uint32_t MODE, uint32_t OSPEED_MODE);
void GPIO_Init_(void);

#endif

/**************GPIO.C文件**************/

#include "GPIO.h"  

/**
  * @brief  通用GPIO设置函数
        *                                       
  * @param  @arg GPIOx:GPIOA~GPIOI.
                        @arg BITx:0X0000~0XFFFF.位设置,每个位代表一个IO,第0位代表Px0,第1位代表Px1,依次类推.比如0X0101,代表同时设置Px0和Px8.
                        @arg MODE:模式选择0~3:输入模式下,0,模拟输入;1,浮空输入(复位状态);2,上拉/下拉输入模式;3,保留;
                                                                   输出模式下,0,通用推挽输出;1,通用开漏输出;2,复用推挽输出;3,复用开漏输出;        
                        @arg OSPEED_MODE:速度模式选择0~3:0,输入(系统复位默认状态);1:10M输出;2:20M输出;3:50M输出.
  * @retval 无
  */
void GPIO_Set(GPIO_TypeDef* GPIOx, uint32_t BITx, uint32_t MODE, uint32_t OSPEED_MODE)
{  
        u32 pinpos=0,pinposlh=0,pos=0,curpin=0;
        for(pinpos=0;pinpos<16;pinpos++)
        {
                pos=1<<pinpos;        //一个个位检查
                curpin=BITx&pos;//检查引脚是否要设置
                if(curpin==pos)        //需要设置
                {
                        if(pinpos < 8)//设置的管脚为0~7
                        {
                                pinposlh = pinpos;
                                GPIOx->CRL &= ~(0xF<<(4*pinposlh));//清除需要设置的位
                                GPIOx->CRL |= (OSPEED_MODE<<(4*pinposlh));//设置新的速度模式
                                GPIOx->CRL |= (MODE<<(4*pinposlh+2));//设置新的输入输出模式
                        }
                        else                 //设置的管脚为8~15
                        {
                                pinposlh = pinpos-8;
                                GPIOx->CRH &= ~(0xF<<(4*pinposlh));//清除需要设置的位
                                GPIOx->CRH |= (OSPEED_MODE<<(4*pinposlh));//设置新的速度模式
                                GPIOx->CRH |= (MODE<<(4*pinposlh+2));//设置新的输入输出模式
                        }
                }
        }
}
                        


void GPIO_Init_(void)  //GPIO引脚逐一初始化函数
{
        uint8_t GPIO_InitList_Len;
        
        RCC->APB2ENR |= 1<<2|1<<3|1<<4|1<<5|1<<6|1<<7|1<<8; //打开GPIOA-G的7个时钟,适用STM32F103RC系列单片机

        while(GPIO_InitList_Len <= 120)        //只放在主循环前,while()循环影响不大
        {
                if(GPIO_Init_List[GPIO_InitList_Len].GPIO_x != 0)
                {
                        GPIO_Set(GPIO_Init_List[GPIO_InitList_Len].GPIO_x, GPIO_Init_List[GPIO_InitList_Len].GPIO_PIN_X, GPIO_Init_List[GPIO_InitList_Len].GPIO_MODE, GPIO_Init_List[GPIO_InitList_Len].GPIO_SPEED);
                        if(GPIO_Init_List[GPIO_InitList_Len].GPIO_InitState)        //对初始状态为高电平的引脚配置,默认低电平。
                        {
                                GPIO_Init_List[GPIO_InitList_Len].GPIO_x -> ODR |= (GPIO_Init_List[GPIO_InitList_Len].GPIO_PIN_X);
                        }        
                        GPIO_InitList_Len ++;
                }
                else
                {
                        GPIO_InitList_Len ++;
                }
        }
}



/**************主函数**************/
#include "GPIO.h"                 

int main(void)
{

        GPIO_Init_();
        
        while (1)
        {
               
        }
        
}


希望各位大佬们不吝赐教,恳请各位大佬们提出宝贵意见与想法
,感谢! STM32F103RC单片机的GPIO初始化封装.zip (582.06 KB, 下载次数: 7)

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

ID:307150 发表于 2023-2-11 17:44 | 显示全部楼层
这个贴很好!!!
回复

使用道具 举报

ID:1034262 发表于 2023-2-12 11:22 | 显示全部楼层
我都是映射成51那种的操作,直接PA0=1; PA0=0;这样。
回复

使用道具 举报

ID:1062805 发表于 2023-2-12 13:48 | 显示全部楼层
可以,思路不错
回复

使用道具 举报

ID:728915 发表于 2024-6-27 00:09 | 显示全部楼层
这个方式,在用作模拟IIC的时候,配置成开漏输出,可能会有问题,自己踩坑了。。。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表