1、GPIO寄存器映射代码的优化
这是GPIO寄存器的映射,看起来不多,但是如果你遇到的寄存器很多的情况下,你就需要写多行的这样的代码,那么有没有什么办法可以对这段代码进行优化呢?
#define GPIOE_CRL *(unsigned int *)(GPIOE_BASE+0x00)
#define GPIOE_CRH *(unsigned int *)(GPIOE_BASE+0x04)
#define GPIOE_IDR *(unsigned int *)(GPIOE_BASE+0x08)
#define GPIOE_ODR *(unsigned int *)(GPIOE_BASE+0x0C)
#define GPIOE_BSRR *(unsigned int *)(GPIOE_BASE+0x10)
#define GPIOE_BRR *(unsigned int *)(GPIOE_BASE+0x14)
#define GPIOE_LCKR *(unsigned int *)(GPIOE_BASE+0x18)
优化思路:采用结构体的方式。因为每个寄存器之间间隔了4个字节是有规律可寻的。通过指针来访问。相当于只需要知道这个寄存器的基地址就行。最后再通过强制类型转换成指针类型,通过操作指针来完成功能。
typedef unsigned int u32;
typedef unsigned short u16;
//代码优化
typedef struct
{
u32 CRL;
u32 CRH;
u32 IDR;
u32 ODR;
u32 BSRR;
u32 BRR;
u32 LCKR;
}GPIO_TypeDef;
#define GPIOE ((GPIO_TypeDef*)GPIOE_BASE)
//库函数雏形
RCC_APB2ENR |= (1<<6);
GPIOE->CRL &=~(0x0F<<(4*5));
GPIOE->CRL |= (3<<(5*4));
GPIOE->ODR |= (1<<5);
while(1)
{
GPIOE->ODR |= (1<<5);
delay(0xFFFFF);
GPIOE->ODR &= ~(1<<5);
delay(0xFFFFF);
}
2、RCC结构体
//RCC
typedef struct
{
u32 CR;
u32 CFGR;
u32 CIR;
u32 APB2RSTR;
u32 APB1RSTR;
u32 AHBENR;
u32 APB2ENR;
u32 APB1ENR;
u32 BDCR;
u32 CSR;
}RCC_TypeDef;
#define RCC ((RCC_TypeDef*)RCC_BASE)
3、端口置位和复位函数
引脚定义
#ifndef __STM32F10X_GPIO_H
#define __STM32F10X_GPIO_H
#include "stm32f10x.h"
//引脚宏定义
#define GPIO_Pin_0 ((u16)0x0001)
#define GPIO_Pin_1 ((u16)0x0002)
#define GPIO_Pin_2 ((u16)0x0004)
#define GPIO_Pin_3 ((u16)0x0008)
#define GPIO_Pin_4 ((u16)0x0010)
#define GPIO_Pin_5 ((u16)0x0020)
#define GPIO_Pin_6 ((u16)0x0040)
#define GPIO_Pin_7 ((u16)0x0080)
#define GPIO_Pin_8 ((u16)0x0100)
#define GPIO_Pin_9 ((u16)0x0200)
#define GPIO_Pin_10 ((u16)0x0400)
#define GPIO_Pin_11 ((u16)0x0800)
#define GPIO_Pin_12 ((u16)0x1000)
#define GPIO_Pin_13 ((u16)0x2000)
#define GPIO_Pin_14 ((u16)0x4000)
#define GPIO_Pin_15 ((u16)0x8000)
#define GPIO_Pin_All ((u16)0xFFFF)
void GPIO_SetBits(GPIO_TypeDef *GPIOx,u16 GPIO_PIN);
void GPIO_ReSetBits(GPIO_TypeDef *GPIOx,u16 GPIO_PIN);
#endif
置位和复位函数
#include "stm32f10x_gpio.h"
void GPIO_SetBits(GPIO_TypeDef *GPIOx,u16 GPIO_PIN)
{
GPIOx->BSRR |= GPIO_PIN;
}
void GPIO_ReSetBits(GPIO_TypeDef *GPIOx,u16 GPIO_PIN)
{
GPIOx->BRR |= GPIO_PIN;
}
函数实现
//库函数雏形
RCC->APB2ENR |= (1<<6);
GPIOE->CRL &=~(0x0F<<(4*5));
GPIOE->CRL |= (3<<(5*4));
GPIO_SetBits(GPIOE,GPIO_Pin_5);
while(1)
{
GPIO_SetBits(GPIOE,GPIO_Pin_5);
delay(0xFFFFF);
GPIO_ReSetBits(GPIOE,GPIO_Pin_5);
delay(0xFFFFF);
}
4、初始化结构体函数
void GPIO_Init(GPIO_TypeDef*GPIOx,GPIO_InitTypeDef* GPIO_Initstruct)
{
u32 currentmode = 0x00,currentpin = 0x00,pinpos = 0x00,pos = 0x00;
u32 tmpreg = 0x00,pinmask = 0x00;
//读取GPIO的第四位模式
currentmode = ((u32)GPIO_Initstruct->GPIO_Mode ) & ((u32)0x0F);
//判断bit4是1还是0,1是输入,0是输出
if((((u32)GPIO_Initstruct->GPIO_Mode) & ((u32)0x10)) != 0x00)
{
//输出模式,设置输出速度
currentmode |= (u32)GPIO_Initstruct->GPIO_Speed;
}
//GPIO_CRL寄存器配置,低八位
if(((u32)GPIO_Initstruct->GPIO_Pin &((u32)0x00FF))!=0x00)
{
//先备份CRL寄存器的值
tmpreg = GPIOx->CRL;
//循环,从Pin0开始配对,找出具体的Pin
for(pinpos = 0x00;pinpos<0x08;pinpos++)
{
//将pos位pinpos左移一位
pos = ((u32)0x01)<<pinpos;
//将pos和GPIO_PIN相与
currentpin = ((GPIO_Initstruct->GPIO_Pin)&pos);
//如果pos == currentpin则找到pin
if(currentpin == pos)
{
//pinpos的值左移两位(乘以4),因为寄存器中4个寄存器位置配置一个引脚
pos = pinpos<<2;
//把控制这个引脚的4个寄存器位清零,其他寄存器不变
pinmask = ((u32)0x0F)<<pos;
tmpreg &= ~pinmask;
//向寄存器写入要配置的引脚的模式
tmpreg |= (currentmode<<pos);
//判断是否位下拉输入模式
if(GPIO_Initstruct->GPIO_Mode == GPIO_Mode_IPD)
{
//下拉模式,引脚置0
GPIOx->BRR = (((u32)0x01)<<pinpos);
}
else
{
if(GPIO_Initstruct->GPIO_Mode == GPIO_Mode_IPU)
{
//上拉模式,引脚默认为1
GPIOx->BSRR = (((u32)0x01)<<pinpos);
}
}
}
}
//把前面暂存的值写入
GPIOx->CRL = tmpreg;
}
//配置高八位
if(GPIO_Initstruct->GPIO_Pin>0X00FF)
{
tmpreg = GPIOx->CRH;
//循环,从pin8开始
for(pinpos = 0x00;pinpos<0x08;pinpos++)
{
pos = ((u32)0x01)<<(pinpos+0x08);
将pos和GPIO_PIN相与
currentpin = ((GPIO_Initstruct->GPIO_Pin)&pos);
//如果pos == currentpin则找到pin
if(currentpin == pos)
{
//pinpos的值左移两位(乘以4),因为寄存器中4个寄存器位置配置一个引脚
pos = pinpos<<2;
//把控制这个引脚的4个寄存器位清零,其他寄存器不变
pinmask = ((u32)0x0F)<<pos;
tmpreg &= ~pinmask;
//向寄存器写入要配置的引脚的模式
tmpreg |= (currentmode<<pos);
//判断是否位下拉输入模式
if(GPIO_Initstruct->GPIO_Mode == GPIO_Mode_IPD)
{
//下拉模式,引脚置0
GPIOx->BRR = (((u32)0x01)<<(pinpos+0x08));
}
else
{
if(GPIO_Initstruct->GPIO_Mode == GPIO_Mode_IPU)
{
//上拉模式,引脚默认为1
GPIOx->BSRR = (((u32)0x01)<<(pinpos+0x08));
}
}
}
}
GPIOx->CRH = tmpreg;
}
}
修改后的代码
//库函数雏形
RCC->APB2ENR |= (1<<6);
// GPIOE->CRL &=~(0x0F<<(4*5));
// GPIOE->CRL |= (3<<(5*4));
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHZ;
GPIO_Init(GPIOE,&GPIO_InitStruct);
GPIO_SetBits(GPIOE,GPIO_Pin_5);
while(1)
{
GPIO_SetBits(GPIOE,GPIO_Pin_5);
delay(0xFFFFF);
GPIO_ReSetBits(GPIOE,GPIO_Pin_5);
delay(0xFFFFF);
}
}
5、提高代码的可移植性
可以将变量设置成宏定义,移植代码时就可以直接修改宏定义的部分。