C语言对寄存器封装

一、封装外设
用C语言代码把外设地址映射用宏定义封装

/* 外设基地址 */
#define  PERIPH_BASE    ((unsigned int)0x40000000)

/* 总线基地址 */
#define APB1PERIPH_BASE   PERIPH_BASE
#define APB2PERIPH_BASE   (PERIPH_BASE + Ox00010000)
.
.

/* GPIO外设基地址 */
#define GPIOA_BASE     (AHB1PERIPH_BASE + 0x0000)
#defien GPIOB_BAAE     (AHB1PERIPH_BASE + 0x0400)
.
.

/* 寄存器基地址,以GPIOA为例 */
#define GPIOA_MODER    (GPIOA_BASE+0x00)
#define GPIOA_OTYPER   (GPIOA_BASE+0x04)
.
.

总结:定义“片上外设”基地址PERIPH_BASE,接着在PERIPH_BASE上加上各个总线的地址偏移,得到总线的相应地址,然后在加上各寄存器的地址偏移就得到特定寄存器的地址。

二、封装寄存器

typedef unsigned          int uint32_t;   //无符号32位变量
typedef unsigned short    int uint16_t;   //无符号16位变量


/* GPIO寄存器列表 */
typedef struct{
    uint32_t MODER;       /*GPIO模式寄存器      地址偏移:0x00*/
    uint32_t OTYPER;      /*GPIO输出类型寄存器   地址偏移:0x04*/
    uint32_t OSPEEDR;     /*GPIO输出速度寄存器   地址偏移:0x08*/
    uint32_t PUPDR;       /*GPIO上拉/下拉寄存器  地址偏移:0x0C*/
    .
    .
    .
}GPIO_TypeDef;

上面这段代码用typedef关键字声明了名为 GPIO_TypeDef的结构体类型。

使用宏定义定义各个GPIO端口的首地址

/* 使用GPIO_TypeDef把地址强制转换成指针 */
#define GPIOA              ((GPIO_TypeDef *) GPIOA_BASE)
#define GPIOB              ((GPIO_TypeDef *) GPIOB_BASE)
.
.

/* 使用定义好评的宏直接访问 */
/* 访问GPIOA端口的寄存器*/
GPIOA->BSRRL = 0XFFFF;    //通过指针访问并修改GPIOA_BSRRL寄存器
GPIOA->MODER = OxFFFFFFF; //修改GPIOA_MODER寄存器

总结:用结构体封装一类寄存器,然后强制转换成指针,通过宏定义执行端口基地址,再加上相应的偏移地址就可以直接访问相应的寄存器。

修改寄存器的某一位
在51单片机中通过关键字sbit来实现位定义,但是M4中没有这个关键字。下面先说说C语言如何操作某一位。
1、把变量的某位清零

//定义一个变量a = 1001 1111b (二进制)
unsigned char a = 0x9F;

//对bit2清零
a  &= ~(1<<2);
//括号中的1左移两位,(1<<2)得二进制:0000 0100b
//按位取反,~(1<<2)得1111 1011b
//假如a中原来的值为二进制:a=1001 1111b
//所有的数与a作“位与&”运算,a=(1001 1111b) & (1111 1011b)
//运算后,a = 1001 1011b

2、把变量的某几个连续位清零

//若把a中的二进制位分为2个一组
a &= ~(3<<2*1);
//括号中的3左移两位, 然后在取反,得到1111 0011b
//然后“位与&”,得到 1001 0011b

这里面涉及到运算符的优先级*的优先级高于<<,所以(3<<2*1)是把3左移3位。
下次在学习M4中的位带操作,因为里面涉及的知识比较多。

你可能感兴趣的:(橙子软件)