当前位置:   article > 正文

寄存器1、怎么操作stm32寄存器/操作单片机寄存器_stm32的系统控制寄存器

stm32的系统控制寄存器

学习单片机时经常听说学会操作寄存器很重要,情况也确实如此,比如某些功能库函数不能实现,或者库函数效率很低时,就只能直接操作寄存器实现。

通过3个问题就能理解寄存器及其操作。

什么是寄存器(就是个数字)?

简单可以理解为能够通过软件改写数值、控制硬件的一个32bit的数字。多个数字一起控制一个外设。

这个数值在哪?

这个数字要被存起来,就一定有一个存储的地址,地址可以通过单片机的数据手册查到。

如何改写这个数值?

 有了地址,可以设置一个指针指向此地址,然后写入数据。有库可以直接写寄存器名字进行操作。

详细解读:

1、什么是寄存器(就是个数字)?

寄存器是软件控制硬件的接口,几乎所有的硬件功能控制都是通过操作寄存器来实现的,库函数也只是将寄存器操作封装成函数,方便调用,一些复杂操作库函数可能无法实现,就只能直接操作寄存器。

一个寄存器32bit,按规则修改这个32bit数值就能控制硬件,通常一个外设需要多个寄存器控制。

2、这个数值在哪?

因为ARM单片机是统一编址的,寄存器像内存一样,内存中每个数据都有一个存储的地址,寄存器也是,只是寄存器的地址是固定的,你只能修改指定地址存储的数字才能控制硬件。

如何查找寄存器:以控制GPIO的寄存器为例。

(1)首先要有《stm32中文参考手册》这个网上很多,随便一搜就有。

(2)在目录中可以看到各种外设,比如下面这些有RCC、GPIO、DMA、ADC等

(3)展开目录,基本每一个外设的章节都有一个寄存器描述

(4)查看寄存器详细描述这一小节。

这里有三个关键点,了解这三点就知道改寄存器的规则了,如下图的①②③所示。

①偏移地址

这个寄存器叫CRL(全称应该是control register low),但具体地址并没有直接给出,而是以具体地址=基地址+偏移地址的形式计算的。其中基地址可以在2.3存储器映像这一章找到,如图:

         如果我们要控制GPIOA的CRL寄存器那么,CRL的地址就是0x40010800+0x00=0x40010800;在它后面的CRH寄存器偏移量为0x04,那么GPIOA的CRH地址为0x40010800+0x04=0x40010804;

手册里为什么要这样写?因为GPIO有多组,GPIOA、GPIOB。。。。每一组都有这个寄存器,且功能相同,只是位置不一样。

这样就比较方便在程序上的定义与使用,定义一个结构体,结构体数据形式和寄存器一样,只需要指定结构体基地址,就比较容易进行寄存器读写,而不用指定每个寄存器地址。

  1. ----------|----------|----------|----------|----------|
  2. GPIOA | GPIOB | GPIOx | GPIOF | .... | |
  3. ----------|----------|----------|----------|----------| |
  4. CRL | CRL | CRL | CRL | CRL | |
  5. ----------|----------|----------|----------|----------| |
  6. CRH | CRH | CRH | CRH | CRH | |
  7. ----------|----------|----------|----------|----------| |
  8. IDR | IDR | IDR | IDR | IDR | ↓
  9. ----------|----------|----------|----------|----------| 地址4字节递增
  10. ... | | | | |
  11. typedef struct
  12. {
  13. vu32 CRL;
  14. vu32 CRH;
  15. vu32 IDR;
  16. ...
  17. } GPIO_TypeDef;

②这两条方框是干嘛的

仔细看方框上有数字1-15和16-31这就是之前说的,每个寄存器是一个32bit数字。

1bit或几个bit组合在一起用于设置功能,比如③号框圈起来的30和31bit,这2bit一起决定一个功能。

③每bit数字具体功能

那么③里的2bit是什么功能,就要看下面的具体描述,这些描述功能的文字应该很熟悉了吧。

3、怎么修改这些寄存器

现在我们知道了这些寄存器的功能和地址,那么下一步就是修改它的数值了。做开发时我们主要还是使用固件库(只是掺杂一点直接修改寄存器操作),而库文件中定义了这些寄存器的地址,我们只需要通过他的名字访问他就行。

就比如上图中的GPIOx_CRL,这是一个通用名,比如要控制GPIOA的这个寄存器那么具体操作如下

GPIOA->CRL = 0x44444444;

 其实操作寄存器并不难,难点是了解每个外设各个寄存器的作用。要完全了解一个外设的寄存器,可以通过寄存器例程手册中的寄存器描述,结合实践加深对外设控制的理解。

扩展:

1、stm32固件库库是如何实通过寄存器名字操作寄存器的?

要理解这个问题需要有良好的C语言基础,理解起来还是比较简单的。

每一组控制GPIO的几个寄存器地址是连续的,按4字节递增(每个寄存器占4字节)。

那么我们只需要定义一个结构体,成员变量都定义为32位无符号整形变量,成员的数量就是寄存器的数量。以GPIO为例

  1. typedef struct
  2. {
  3. __IO uint32_t CRL;
  4. __IO uint32_t CRH;
  5. __IO uint32_t IDR;
  6. __IO uint32_t ODR;
  7. __IO uint32_t BSRR;
  8. __IO uint32_t BRR;
  9. __IO uint32_t LCKR;
  10. } GPIO_TypeDef;
  11. GPIO_TypeDef *GPIOA;
  12. GPIOA = GPIOA的基地址;
  13. GPIOA->ODR = 0x11114444;
  14. 通过GPIOA这个指针访问对应的寄存器地址。
  15. 编译器会自动计算ODR相对GPIOA基地址的具体地址。

2、一些给寄存器赋值的小技巧。

通常我们只想修改32bit中的某一位,清零或者置1

  1. GPIOA->CRL |= 1<<6; 将bit6设为1
  2. GPIOA->CRL |= (1<<6+1<<7);GPIOA->CRL |= (0x3<<6); 将bit6和7设为1
  3. GPIOA->CRL &= ~(1<<6); 将bit6清零
  4. GPIOA->CRL &= ~(1<<6+1<<7);GPIOA->CRL &= ~(0x3<<6); 将bit6和7清零

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/565927
推荐阅读
相关标签
  

闽ICP备14008679号