STM32- build the library function prototype

Construction of the prototype library functions

Modifying the register address encapsulation

Register List Package Listing 8-1

//volatile 表示易变的变量,防止编译器优化
#define __IO volatile
typedef unsigned int uint32_t;
typedef unsigned short uint16_t;

/* GPIO 寄存器列表 */
typedef struct {
    __IO uint32_t MODER; /*GPIO 模式寄存器 地址偏移: 0x00 */
    __IO uint32_t OTYPER; /*GPIO 输出类型寄存器 地址偏移: 0x04 */
    __IO uint32_t OSPEEDR; /*GPIO 输出速度寄存器 地址偏移: 0x08 */
    __IO uint32_t PUPDR; /*GPIO 上拉/下拉寄存器 地址偏移: 0x0C */
    __IO uint32_t IDR; /*GPIO 输入数据寄存器 地址偏移: 0x10 */
    __IO uint32_t ODR; /*GPIO 输出数据寄存器 地址偏移: 0x14 */
    __IO uint16_t BSRRL; /*GPIO 置位/复位寄存器低 16 位部分 地址偏移: 0x18 */
    __IO uint16_t BSRRH; /*GPIO 置位/复位寄存器 高 16 位部分地址偏移: 0x1A */
    __IO uint32_t LCKR; /*GPIO 配置锁定寄存器 地址偏移: 0x1C */
    __IO uint32_t AFR[2]; /*GPIO 复用功能配置寄存器 地址偏移: 0x20-0x24 */
} GPIO_TypeDef;

/*RCC 寄存器列表*/
typedef struct {
    __IO uint32_t CR; /*!< RCC 时钟控制寄存器,地址偏移: 0x00 */
    __IO uint32_t PLLCFGR; /*!< RCC PLL 配置寄存器,地址偏移: 0x04 */
    __IO uint32_t CFGR; /*!< RCC 时钟配置寄存器,地址偏移: 0x08 */
    __IO uint32_t CIR; /*!< RCC 时钟中断寄存器,地址偏移: 0x0C */
    __IO uint32_t AHB1RSTR; /*!< RCC AHB1 外设复位寄存器,地址偏移: 0x10 */
    __IO uint32_t AHB2RSTR; /*!< RCC AHB2 外设复位寄存器,地址偏移: 0x14 */
    __IO uint32_t AHB3RSTR; /*!< RCC AHB3 外设复位寄存器,地址偏移: 0x18 */
    __IO uint32_t RESERVED0; /*!< 保留, 地址偏移: 0x1C */
    __IO uint32_t APB1RSTR; /*!< RCC APB1 外设复位寄存器,地址偏移: 0x20 */
    __IO uint32_t APB2RSTR; /*!< RCC APB2 外设复位寄存器,地址偏移: 0x24*/
    __IO uint32_t RESERVED1[2]; /*!< 保留,地址偏移: 0x28-0x2C*/
    __IO uint32_t AHB1ENR; /*!< RCC AHB1 外设时钟寄存器,地址偏移: 0x30 */
    __IO uint32_t AHB2ENR; /*!< RCC AHB2 外设时钟寄存器,地址偏移: 0x34 */
    __IO uint32_t AHB3ENR; /*!< RCC AHB3 外设时钟寄存器,地址偏移: 0x38 */
/*RCC 后面还有很多寄存器,此处省略*/
} RCC_TypeDef;

Each member of the structure before the addition of a "__IO" prefix, on behalf of the C language keyword "volatile", in the C language keyword used to indicate variable is variable, ask the compiler not to optimize. Members of these structures in the body, represents the register, and the register is often modified by the peripheral or STM32 chip state, that even if the CPU does not execute the code modify these variables, the values ​​of variables peripherals may also be modified, updated, so every time the use of these variables, we require the CPU to the address of the variable revisit. Without this keyword modification, in some cases, the compiler sees no code changes the variable, the variable will get the value from a cache of the CPU, then you can speed up the execution speed, but cache data is stale , and we ask for the latest status register may be different.

Structure pointer defining access peripherals

Structure pointer first address code in Listing 8-2 points peripherals

/*定义 GPIOA-H 寄存器结构体指针*/
#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)
#define GPIOH ((GPIO_TypeDef *) GPIOH_BASE)

/*定义 RCC 外设 寄存器结构体指针*/
#define RCC ((RCC_TypeDef *) RCC_BASE)

Defines the initialization structured GPIO_InitTypeDef

Listing 8-10 defined GPIO initialization structure

typedef uint8_t unsigned char;
/**
* GPIO 初始化结构体类型定义
*/
typedef struct {
    uint32_t GPIO_Pin; /*!< 选择要配置的 GPIO 引脚可输入 GPIO_Pin_ 定义的宏 */
    uint8_t GPIO_Mode; /*!< 选择 GPIO 引脚的工作模式可输入二进制值:00 、01、10、11表示输入/输出/复用/模拟 */
    uint8_t GPIO_Speed; /*!< 选择 GPIO 引脚的速率可输入二进制值:00 、01、10、11表示2/25/50/100MHz */
    uint8_t GPIO_OType; /*!< 选择 GPIO 引脚输出类型可输入二进制值:0 、1表示推挽/开漏 */
    uint8_t GPIO_PuPd; /*!<选择 GPIO 引脚的上/下拉模式可输入二进制值:00 、01、10表示浮空/上拉/下拉*/
} GPIO_InitTypeDef;

Defined enumerated type pin mode

Listing 8-11 GPIO enumeration defines the configuration parameters

/**
* GPIO 端口配置模式的枚举定义
*/
typedef enum {
    GPIO_Mode_IN = 0x00, /*!< 输入模式 */
    GPIO_Mode_OUT = 0x01, /*!< 输出模式 */
    GPIO_Mode_AF = 0x02, /*!< 复用模式 */
    GPIO_Mode_AN = 0x03 /*!< 模拟模式 */
} GPIOMode_TypeDef;

/**
* GPIO 输出类型枚举定义
*/
typedef enum {
    GPIO_OType_PP = 0x00, /*!< 推挽模式 */
    GPIO_OType_OD = 0x01 /*!< 开漏模式 */
} GPIOOType_TypeDef;

/**
* GPIO 输出速率枚举定义
*/
typedef enum {
    GPIO_Speed_2MHz = 0x00, /*!< 2MHz */
    GPIO_Speed_25MHz = 0x01, /*!< 25MHz */
    GPIO_Speed_50MHz = 0x02, /*!< 50MHz */
    GPIO_Speed_100MHz = 0x03 /*!<100MHz */
} GPIOSpeed_TypeDef;

/**
*GPIO 上/下拉配置枚举定义
*/
typedef enum {
    GPIO_PuPd_NOPULL = 0x00,/*浮空*/
    GPIO_PuPd_UP = 0x01, /*上拉*/
    GPIO_PuPd_DOWN = 0x02 /*下拉*/
} GPIOPuPd_TypeDef;

Listing 8-12 using GPIO_InitTypeDef structure members of an enumeration type definition

/**
* GPIO 初始化结构体类型定义
*/

typedef struct {
    uint32_t GPIO_Pin; /*!<选择要配置的GPIO引脚可输入GPIO_Pin_定义的宏 */
    GPIOMode_TypeDef GPIO_Mode; /*!<选择GPIO引脚的工作模式可输入 GPIOMode_TypeDef 定义的枚举值*/
    GPIOSpeed_TypeDef GPIO_Speed; /*!<选择GPIO引脚的速率可输入 GPIOSpeed_TypeDef 定义的枚举值 */
    GPIOOType_TypeDef GPIO_OType; /*!< 选择GPIO引脚输出类型可输入 GPIOOType_TypeDef 定义的枚举值*/
    GPIOPuPd_TypeDef GPIO_PuPd; /*!<选择GPIO引脚的上/下拉模式可输入 GPIOPuPd_TypeDef 定义的枚举值*/
} GPIO_InitTypeDef;

Listing 8-13 to GPIO_InitTypeDef initialization structure assignment example

GPIO_InitTypeDef InitStruct;

/* LED 端口初始化 */
/*选择要控制的 GPIO 引脚*/
InitStruct.GPIO_Pin = GPIO_Pin_10;
/*设置引脚模式为输出模式*/
InitStruct.GPIO_Mode = GPIO_Mode_OUT;
/*设置引脚的输出类型为推挽输出*/
InitStruct.GPIO_OType = GPIO_OType_PP;
/*设置引脚为上拉模式*/
InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
/*设置引脚速率为 2MHz */
InitStruct.GPIO_Speed = GPIO_Speed_2MHz;

Defined initialization function

Listing 8-14 GPIO initialization function

/**
*函数功能:初始化引脚模式
*参数说明: GPIOx,该参数为 GPIO_TypeDef 类型的指针,指向 GPIO 端口的地址
* GPIO_InitTypeDef:GPIO_InitTypeDef 结构体指针,指向初始化变量
*/
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)
{
    uint32_t pinpos = 0x00, pos = 0x00 , currentpin = 0x00;
    
    /*-- GPIO Mode Configuration --*/
    for (pinpos = 0x00; pinpos < 16; pinpos++) {
        /*以下运算是为了通过GPIO_InitStruct->GPIO_Pin算出引脚号0-15*/        
        /*经过运算后pos的pinpos位为1,其余为0,与GPIO_Pin_x宏对应。pinpos 变量每次循环加1*/
        pos = ((uint32_t)0x01) << pinpos;        

        /* pos与GPIO_InitStruct->GPIO_Pin做&运算,若运算结果currentpin == pos,则表示GPIO_InitStruct->GPIO_Pin的pinpos位也为1,从而可知pinpos 就是GPIO_InitStruct->GPIO_Pin对应的引脚号:0-15*/
        currentpin = (GPIO_InitStruct->GPIO_Pin) & pos;

        /*currentpin == pos 时执行初始化*/
        if (currentpin == pos) {
            /*GPIOx 端口, MODER寄存器的GPIO_InitStruct->GPIO_Pin对应的引脚,MODER位清空*/
            GPIOx->MODER &= ~(3 << (2 *pinpos));
            
            /*GPIOx 端口, MODER寄存器的GPIO_Pin引脚,MODER位设置"输入/输出/复用输出/模拟"模式*/
            GPIOx->MODER |= (((uint32_t)GPIO_InitStruct->GPIO_Mode) << (2 *pinpos));
           
            /*GPIOx端口,PUPDR寄存器的GPIO_Pin引脚,PUPDR位清空*/
            GPIOx->PUPDR &= ~(3 << ((2 *pinpos)));
            
            /*GPIOx端口,PUPDR寄存器的GPIO_Pin引脚,PUPDR位设置"上/下拉"模式*/
            GPIOx->PUPDR |= (((uint32_t)GPIO_InitStruct->GPIO_PuPd) << (2 *pinpos));
            
            /*若模式为"输出/复用输出"模式,则设置速度与输出类型*/
            if ((GPIO_InitStruct->GPIO_Mode == GPIO_Mode_OUT) ||(GPIO_InitStruct->GPIO_Mode == GPIO_Mode_AF)) {

                /*GPIOx端口,OSPEEDR寄存器的GPIO_Pin引脚,OSPEEDR位清空*/
                GPIOx->OSPEEDR &= ~(3 << (2 *pinpos));

                /*GPIOx端口, OSPEEDR寄存器的GPIO_Pin引脚,OSPEEDR位设置输出速度*/

                GPIOx->OSPEEDR |= ((uint32_t)(GPIO_InitStruct->GPIO_Speed)<<(2 *pinpos));
                
                /*GPIOx端口, OTYPER寄存器的GPIO_Pin引脚,OTYPER位清空*/
                GPIOx->OTYPER &= ~(1 << (pinpos)) ;

                /*GPIOx端口,OTYPER位寄存器的GPIO_Pin引脚,OTYPER位设置"推挽/开漏"输出类型*/
                GPIOx->OTYPER |= (uint16_t)(( GPIO_InitStruct->GPIO_OType)<< (pinpos));
            }
        }
    }
}

LED lamp is lit using the function

Listing 8-15 using the LED lighting function

/*
使用寄存器的方法点亮 LED 灯
*/
#include "stm32f4xx_gpio.h"

void Delay( uint32_t nCount);

/**
* 主函数,使用封装好的函数来控制 LED 灯
*/
int main(void)
{

    GPIO_InitTypeDef InitStruct;

    /*开启GPIOH 时钟,使用外设时都要先开启它的时钟*/
    RCC->AHB1ENR |= (1<<7);

    /* LED 端口初始化 */

    /*初始化 PH10 引脚*/
    /*选择要控制的 GPIO 引脚*/
    InitStruct.GPIO_Pin = GPIO_Pin_10;
    /*设置引脚模式为输出模式*/
    InitStruct.GPIO_Mode = GPIO_Mode_OUT;
    /*设置引脚的输出类型为推挽输出*/
    InitStruct.GPIO_OType = GPIO_OType_PP;
    /*设置引脚为上拉模式*/
    InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
    /*设置引脚速率为 2MHz */
    InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
    /*调用库函数,使用上面配置的 GPIO_InitStructure 初始化 GPIO*/
    GPIO_Init(GPIOH, &InitStruct);

    /*使引脚输出低电平,点亮 LED1*/
    GPIO_ResetBits(GPIOH,GPIO_Pin_10);
    
    /*延时一段时间*/
    Delay(0xFFFFFF);
    
    /*使引脚输出高电平,关闭 LED1*/
    GPIO_SetBits(GPIOH,GPIO_Pin_10);
    
    /*初始化 PH11 引脚*/
    InitStruct.GPIO_Pin = GPIO_Pin_11;
    GPIO_Init(GPIOH,&InitStruct);

    /*使引脚输出低电平,点亮 LED2*/
    GPIO_ResetBits(GPIOH,GPIO_Pin_11);

    while (1);
}

//简单的延时函数,让 cpu 执行无意义指令,消耗时间
//具体延时时间难以计算,以后我们可使用定时器精确延时
void Delay( uint32_t nCount)
{
    for (; nCount != 0; nCount--);
}

// 函数为空,目的是为了骗过编译器不报错
void SystemInit(void)
{
}

Guess you like

Origin www.cnblogs.com/luoxiao23/p/11209308.html