STM32学习笔记----寄存器的操作与定义

寄存器的操作

1、如何写入寄存器

1)RCC_APB2ENR |= 1<<3;//该句可以对第3位置1,只能置1时使用,且只能操作一位。
2)RCC_APB2ENR &= ~(1<<2); //该句可以对第2位置0,只能操作一位。
3)RCC->CR = 0x01000000; //这种句式给所有位赋值,不推荐使用
4)RCC->CR |= 0x01000000; // 这种句式只给非0位赋值,0位对的数据不变
5)

	*GPIOE_CRL&= 0xFF0F0FFF;//清除第3、5位,不影响其它位
	*GPIOE_CRL|= 0x00308000;//为第3、5位写入数值

 该段代码用于对寄存器多位同时操作,用于写入数据,不可读取数据。

2、如何读取寄存器

1)(RCC->CR>>17)&0x01; 这种句式能够读取寄存器的第17位,只能读取一位
2)while((USART1->SR & 0X40)==0);这种句式可以直接判断 USART1->SR 的第6位是1还是0,仅判断一位
3)

    unsigned char temp=0; 
    RCC->CFGR = 0x0000000a;
    while(temp!=0x02)    
    {   
    	temp=RCC->CFGR>>2;//获取寄存器低位数据
    	temp&=0x03;//清除其它位的干扰
    }   

 上述代码利用了temp的短长度,先把寄存器的需要读取位(第2,3位)放在最低位,而后给temp这个长度短的赋值,由此寄存器把低位数据给temp,temp装满后寄存器其余值不再赋值。

3、对寄存器的位能读能写(位带别名法)

    #define APB2 0x40000000
    #define GPIO APB2+0x10000
    #define GPIOE GPIO+0x1800
    #define A (GPIOE+0x08)
    
    #define BIT(addr, num) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(num<<2)) 
    #define BIT(addr, num) ((addr & 0xF0000000)+0x2000000+(addr-(addr & 0xF0000000))*32+num*4)
    
    #define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr)) 
    #define BIT_ADDR(addr, bitnum)   MEM_ADDR(BIT(addr, bitnum)) 
    #define PEin(n)    BIT_ADDR(A,n)  

 该段代码也可以实现位操作,它既可以读也可以写,既可以置1也可以置0,具体如何看A的地址。
 此段代码源于《Cortex-M3权威指南》第五章的位带操作,在 CM3中,有两个区中实现了位带。其中一个是 SRAM 区的最低 1MB 范围,第二个则是片内外设区的最低 1MB 范围,两个内存区的范围是:
0x2000_0000‐0x200F_FFFF(SRAM 区中的最低 1MB)
0x4000_0000‐0x400F_FFFF(片上外设区中的最低 1MB)
这两个区域的地址的每个位被膨胀成为32位的字,对这些字有了个新的地址名,称位带别名,对别名的操作等同于对该地址的操作。获取别名地址的方式有两种在上述代码中体现。

其中*((volatile unsigned long *)(addr)) 的解释如下:
(unsigned long *)(addr),代表“addr”是一个unsigned long类型的指针;
volatile是一个修饰符,告诉编译器此段代码不要优化;因此,(volatile unsigned long *)(addr),意思是未优化指针类型的addr;
(volatile unsigned long *) (addr),意思是(volatile unsigned long *)指针指向固定的地址 (addr)
*(volatile unsigned long *) (addr)代表 (addr)是一个地址变量,我们既可以给固定地址中赋值,也可以从固定地址中取值。

寄存器的定义

我们知道STM32的功能基本上就是运算+寄存器控制实现的,运算就是算法,寄存器控制是对STM32的所有外设的直接控制,设定不同的寄存器值可以设定外设进行不同的动作。对寄存器操作前,需要对所有相关寄存器进行定义,即给寄存器的地址定义一个名称,使用时使用名称即可。

1、普通定义-----适用于独立的不可分组的寄存器

以RTC为例,寄存器相互独立,且不可分组,于是,可以单独定义。
STM32学习笔记----寄存器的操作与定义_第1张图片
STM32学习笔记----寄存器的操作与定义_第2张图片
具体定义如下,定义一个结构体,结构体内包含所有独立寄存器,__IO表示静态定义,类似与static,uint32_t是因为一个独立寄存器有32位,这里把保留位也算进来了。如此定义,后只需加上开头的两个define就可以实现对寄存器的访问。(mRCC_Type *)意味着把变量 mRCC 转变为指针,指针类型为 mRCC_Type 结构体,指向地址 mRCC_BASE。

#define mRCC_BASE    0x40021000
#define mRCC ((mRCC_Type *)mRCC_BASE)

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

2、数组定义-----适用于独立的不可分组的寄存器按顺序排列时,可以使用数组同时定义多个寄存器。

以AFIO为例,寄存器同名且按顺序排列。
STM32学习笔记----寄存器的操作与定义_第3张图片
STM32学习笔记----寄存器的操作与定义_第4张图片

typedef struct
{
  __IO uint32_t EVCR;
  __IO uint32_t MAPR;
  __IO uint32_t EXTICR[4];
} mAFIO_Type;

3、外分组定义-----适用于需要外分组的寄存器

以GPIO为例,多个GPIO使用同名寄存器(但是寄存器地址不一样);TIM也是如此。
STM32学习笔记----寄存器的操作与定义_第5张图片
STM32学习笔记----寄存器的操作与定义_第6张图片
具体定义如下,如此这般,所有的GPIO组共用一个结构体 mGPIO_Type ,但是在指针定义时不同GPIO组,使用不同的指针变量名,指向不同地址。

#define mGPIOG_BASE  0x40012000
#define mGPIOF_BASE  0x40011C00
#define mGPIOE_BASE  0x40011800
#define mGPIOD_BASE  0x40011400
#define mGPIOC_BASE  0x40011000
#define mGPIOB_BASE  0X40010C00
#define mGPIOA_BASE  0x40010800

#define mGPIOA ((mGPIO_Type *)mGPIOA_BASE)
#define mGPIOB ((mGPIO_Type *)mGPIOB_BASE)
#define mGPIOC ((mGPIO_Type *)mGPIOC_BASE)
#define mGPIOD ((mGPIO_Type *)mGPIOD_BASE)
#define mGPIOE ((mGPIO_Type *)mGPIOE_BASE)
#define mGPIOF ((mGPIO_Type *)mGPIOF_BASE)
#define mGPIOG ((mGPIO_Type *)mGPIOG_BASE)

typedef struct
{
	__IO uint32_t CRL;
	__IO uint32_t CRH;
	__IO uint32_t IDR;
	__IO uint32_t ODR;
	__IO uint32_t BSRR;
	__IO uint32_t BRR;
	__IO uint32_t LCKR;
}mGPIO_Type;

4、内分组定义-----适用于需要内分组的寄存器

以CAN为例,CAN的控制和状态寄存器、过滤器寄存器是独立的,不需要分组,但是邮箱寄存器有3个,虽然每个对应的寄存器是不同的,但是这些寄存器功能相同,名称相同,故而可以分组进行定义。
STM32学习笔记----寄存器的操作与定义_第7张图片
STM32学习笔记----寄存器的操作与定义_第8张图片
STM32学习笔记----寄存器的操作与定义_第9张图片
在定义控制和状态寄存器、过滤器寄存器之后,对邮箱寄存器 mCAN_TxMailBox_Type 和 mCAN_FIFOMailBox_Type 进行单独定义,并在主定义中添加指针数组,指针类型为 mCAN_TxMailBox_Type 和 mCAN_FIFOMailBox_Type。

  mCAN_TxMailBox_Type sTxMailBox[3];
  mCAN_FIFOMailBox_Type sFIFOMailBox[2];

  可以看作如下代码:
  __IO uint32_t TIR[0];
  __IO uint32_t TDTR[0];
  __IO uint32_t TDLR[0];
  __IO uint32_t TDHR[0];
  __IO uint32_t TIR[1];
  __IO uint32_t TDTR[1];
  __IO uint32_t TDLR[1];
  __IO uint32_t TDHR[1];
  __IO uint32_t TIR[2];
  __IO uint32_t TDTR[2];
  __IO uint32_t TDLR[2];
  __IO uint32_t TDHR[2];
  
  __IO uint32_t RIR[0];
  __IO uint32_t RDTR[0];
  __IO uint32_t RDLR[0];
  __IO uint32_t RDHR[0];
  __IO uint32_t RIR[1];
  __IO uint32_t RDTR[1];
  __IO uint32_t RDLR[1];
  __IO uint32_t RDHR[1];
#define PERIPH_BASE           ((uint32_t)0x40000000)
#define APB1PERIPH_BASE       PERIPH_BASE

#define CAN1_BASE             (APB1PERIPH_BASE + 0x6400)
#define CAN2_BASE             (APB1PERIPH_BASE + 0x6800)

#define CAN1                ((mCAN_Type *) CAN1_BASE)
#define CAN2                ((mCAN_Type *) CAN2_BASE)

typedef struct
{
  __IO uint32_t TIR;
  __IO uint32_t TDTR;
  __IO uint32_t TDLR;
  __IO uint32_t TDHR;
} mCAN_TxMailBox_Type;

typedef struct
{
  __IO uint32_t RIR;
  __IO uint32_t RDTR;
  __IO uint32_t RDLR;
  __IO uint32_t RDHR;
} mCAN_FIFOMailBox_Type;

typedef struct
{
  __IO uint32_t MCR;
  __IO uint32_t MSR;
  __IO uint32_t TSR;
  __IO uint32_t RF0R;
  __IO uint32_t RF1R;
  __IO uint32_t IER;
  __IO uint32_t ESR;
  __IO uint32_t BTR;
  uint32_t  RESERVED0[88];
  mCAN_TxMailBox_Type sTxMailBox[3];
  mCAN_FIFOMailBox_Type sFIFOMailBox[2];
  uint32_t  RESERVED1[12];
  __IO uint32_t FMR;
  __IO uint32_t FM1R;
  uint32_t  RESERVED2;
  __IO uint32_t FS1R;
  uint32_t  RESERVED3;
  __IO uint32_t FFA1R;
  uint32_t  RESERVED4;
  __IO uint32_t FA1R;
  uint32_t  RESERVED5[8];
} mCAN_Type;

在这里有一个 uint32_t RESERVED0[88]; 与 uint32_t RESERVED1[12];这些仅起到占位符的作用,指针经过这些占位符时,指针地址会相应增加。具体加多少占位符看,寄存器中间保留的位数。占位符不仅限于32位,也可以是16位,如下所示,注意占位符的位置不同,占去的位不同。

typedef struct
{
  __IO uint16_t CRH;//低16位
  uint16_t  RESERVED0;//高16位
  __IO uint16_t CRL;
  uint16_t  RESERVED1;
  __IO uint16_t PRLH;
  uint16_t  RESERVED2;
  __IO uint16_t PRLL;
  uint16_t  RESERVED3;
  __IO uint16_t DIVH;
  uint16_t  RESERVED4;
  __IO uint16_t DIVL;
  uint16_t  RESERVED5;
  __IO uint16_t CNTH;
  uint16_t  RESERVED6;
  __IO uint16_t CNTL;
  uint16_t  RESERVED7;
  __IO uint16_t ALRH;
  uint16_t  RESERVED8;
  __IO uint16_t ALRL;
  uint16_t  RESERVED9;
} mRTC_Type;

STM32学习笔记----寄存器的操作与定义_第10张图片

你可能感兴趣的:(STM32笔记)