什么是寄存器

提到单片机,就不得不提到寄存器。根据百度百科介绍,寄存器是中央处理器内的组成部分。寄存器是有限存贮容量的高速存贮部件,它们可用来暂存指令、数据和地址

  简单来说,寄存器就是存放东西的东西。从名字来看,跟火车站寄存行李的地方好像是有关系的。只不过火车站行李寄存处,存放的行李;寄存器可能存放的是指令、数据或地址。
  存放数据的寄存器是最好理解的,如果你需要读取一个数据,直接到这个寄存器所在的地方来问问他,数据是多少就行了。问寄存器这个动作,叫做访问寄存器。不同的数据会存放在不同的寄存器,例如引脚PA2与PB8的高低电平数据(1或0)肯定放在不同的寄存器里,那么怎么区分不同的寄存器呢?通过地址,不同的寄存器有不同的地址,就像老张行李寄存处在101号店铺,老王行李寄存处在258号店铺。
  指令、地址寄存器与数据寄存器类似,里边存放的都是0和1,毕竟单片机也只认识机器码,机器码都是0或1,只是特别的规定下,数据寄存器里面存放的0和1表示数据,指令寄存器里存放的表示指令。
  个人理解:给CPU存储东西的地方。等CPU转到寄存器这个地方的时候,就拿出寄存器里存放的东西,或是根据寄存器里的命令做一些事情。比如厨房就是个寄存器,负责做饭。仓库也是个寄存器,负责存东西。需要某些功能的时候,就要操作某个寄存器。可以把寄存器类比为,有特殊功能的地方,既然是个地方当然就有地址了,所以,可以把寄存器想象为特殊的地址。

怎么找到某个寄存器的地址?查看数据手册。

手册中没有直接给出所有的寄存器的地址,需要读者稍加计算。STM32给不同的寄存器分配了不同的地址,有点像划分了片区。在《STM32中文参考手册_V10》的第28页,有不同寄存器的地址范围。
  现在,假如我们想读取PB3引脚的电平,该怎么找到相关的寄存器?
第一步,找到GPIOB的基地址
  也就是找到GPIOB的小区。结论是,所有GPIOB相关的寄存器,都住在0x4001 0C00到0x4001 0FFF范围内。

第二步,找到端口输入寄存器的地址偏移
  找到存储数据的那个屋子,结论是0x4001 0C00+8 = 0x4001 0C08

第三步,找到知道数据的那个人
  PB3的数据位于从右往左数第4个。

  而这个寄存器的位数是32位(虽然高16位没有用到),这就是32位的单片机的意思。每个寄存器都占据4字节,32位。而CPU的总线一次可以操作32位,所以比8位单片机厉害一点。
  经过这三步查找,我们可以做出以下结论:
PB3的输入数据位于0x4001 0C08这个地址上,这个地址上存放数据的右起第4个位就是PB3引脚对应的高低电平。
  我们可以简单粗暴地直接访问这个地址:

 unsigned int *pGPIOB_IDR = (unsigned int *)0x40010C08;unsigned char PB3 = *pGPIOB_IDR & 0x8;//取出从右往左数的第4位

直接访问的操作并不好用,每操作一个寄存器就必须去查看数据手册,然后找找这个寄存器的地址。
  意法半导体公司为了方便大家使用,就把这些寄存器都起了一目了然的名字,把寄存器与地址映射关系放在他们提供的头文件里。这个文件就是stm32f10x.h。

直接操作寄存器来点亮LED。

我的板子对应的LED是PB8。

  • 首先要配置时钟使能。

为什么配置时钟?为了省电,默认的时钟都是关闭的。配置STM32的任何资源前,都必须首先使能时钟。
  配置哪个时钟?
时钟的信息在参考手册里边,参考手册十分巨大,不用通读,就像一个字典,需要什么查什么。
  参考手册,搜索"时钟",在表1里可以看到。
时钟控制名字叫做RCC,属于AHB总线。GPIOB属于APB2。

  下图系统结构可以看到时钟的从属关系,此图位于手册P25页,十分重要。可以看出AHB总线包含RCC时钟控制,GPIO是属于APB2的。

  我们已经知道,GPIO端口B的地址从0x4001 0C00开始。接下来只寻找时钟使能寄存器的地址:
  复位和时钟控制RCC的地址从0x4002 1000开始;
  可以在6.3.7小节找到APB2外设时钟使能寄存器(RCC_APB2ENR),偏移地址是0x18,所以APB2的地址就是0x4002 1018。
  看手册RCC_APB2ENR,位3是IOPBEN,名字是IO端口B时钟使能,就是我们想要的。把RCC_APB2ENR的位3赋值为1,就是开启GPIOB时钟。

  • 配置为通用输出

既然叫做IO,那么肯定就是可以输入,可以输出,到底是输入还是输出呢?
  控制LED需要输出高电平或是低电平,所以需要配置为输出。
  由于STM32的每个IO都需要4个位来配置,所以一个32位的寄存器最大只能配置8个IO(32位的单片机的寄存器就是32位的)。STM32中,用端口配置低寄存器(GPIOx_CRL)来配置引脚Px0-Px7, 用端口配置高寄存器(GPIOx_CRH)来配置引脚Px8-Px15。
  配置引脚PB8,使用的寄存器是GPIOB_CRH。下面我们来寻找这个寄存器的地址。

  关于此寄存器的说明位于8.2.2小节。先看标题GPIOx,表示不管是PA,PB还是PE,都能用。
  偏移地址是0x04,意思是在基地址的基础上再加0x04,所以,对于GPIOB来说就是0x4001 0c04。如果配置PB0-PB7,那么需要的寄存器是低位的寄存器GPIOB_CRL,它的地址是0x4001 0c00。我们需要配置的寄存器是GPIOB_CRH。
  找到需要操作的寄存器后,把它配置为通用输出。
  复位值是0x4444 4444,并不是0x0000 0000。所谓的复位值,就是指如果没有操作这个寄存器时,寄存器存放的默认值。复位值按位拆分0x4 = 0b0100,0x表示16进制,0b表示二进制,也就是默认CNF 01,MODE 00,是浮空输入。
  我们需要的是输出高低电平,所以要设置为输出。输出模式又有好几种输出:

  推挽输出:可以输出高,低电平,连接数字器件;推挽结构一般是指两个三极管分别受两互补信号的控制,总是在一个三极管导通的时候另一个截止。
  开漏输出:输出端相当于三极管的集电极,要得到高电平状态需要上拉电阻才行,适合于做电流型的驱动,其吸收电流的能力相对强(一般20ma以内)。
  开漏是需要外接上拉电阻才可以输出高电平的,这里并不适合。所以需要设置为推挽输出。
  功能是否是复用呢?复用的意思是有别的功能在这个脚上,比如USB,CAN,串口等,所以这些个脚就可能有多个功能。暂时讲多了反而会迷惑,等用到了这些功能再讲解,我直接告诉大家,PB8没有复用。
  所以配置为输出模式,通用推挽输出。速度暂时不关注,随便填写一个50MHz吧,其它速度当然也可以。所以设置GPIOB_CRH的MODE8与CNF8为0b0011,即0x3。此寄存器中其它的位暂时不做修改,使用默认值,也就是GPIOB_CRH设置为:0x4444 4443。

  • 点亮LED需要输出低电平

在单片机的编程中,要想做某件事,必须寻找相应的寄存器。在8.2.4小节,可以找到端口输出数据寄存器,就是我们需要的。我们需要输出0。但是中文手册有一个小小的BUG,0x0C写成了0Ch,可以参考英文原版。得知地址的偏移是0x0C,所以这个数据寄存器的地址就是0x4001 0C0C,把第8位写为0就行。默认就是0,但是也得学一下怎么写,万一是高电平点亮呢。

  • 使用直接赋值的方式写寄存器的地址

在搞清楚我们要用的几个寄存器的地址,以及寄存器中需要装填的数值以后,现在用一个简单粗暴的方法来操作这些寄存器——直接操作。(注意,这段代码不是实用的代码,只是为了写出一个最简单的LED,有些部分是不可取的。)将main函数修改为:

    int main(void){unsigned int *pRCC_APB2ENR = (unsigned int *)0x40021018;unsigned int *pGPIOB_CRH = (unsigned int *)0x40010c04;unsigned int *pGPIOB_ODR = (unsigned int *)0x40010c0c;*pRCC_APB2ENR = 0x00000008;*pGPIOB_CRH = 0x44444443;*pGPIOB_ODR = 0x00000000;return 0;             }

C语言总是从main函数开始执行。
  定义几个指针,指向刚刚看到的地址。对于编译器来说,它并不知道0x40021018代表的是数据还是指针,所以用(unsigned int *)作强制的类型转换,告诉编译器0x40021018是个指针。指针可以理解为地址。操作指针,把这些地址存放的值修改。
  最后的return,代表main函数结束。

总结

我们写了一段另类的代码,直接操作寄存器的地址,就是想得到这么一个结论:不论代码怎么写,不论是寄存器,库函数,还是其他的操作系统,要在STM32F103这个单片机点亮LED灯,肯定需要把时钟和GPIO这几个相关的特殊地址,进行赋值或修改数值的操作。有点像打篮球,不论进攻时有怎样花哨的运球与传切配合,最后都要完成把球放入篮筐的动作,才能得分。

STM32寄存器的简介、地址查找,与直接操作寄存器相关推荐

  1. STM32 CAN控制器简介-寄存器简介

    1.CAN主控制寄存器(CAN_MCR) 该寄存器的我们仅介绍下INRQ位,该位用来控制初始化请求. 设置INRQ=0,可使CAN从初始化模式进入正常工作模式. 设置INRQ=1,可使CAN从正常工作 ...

  2. stm32地址偏移:为什么相邻寄存器的地址偏移量是0x04?

    前段时间第一次接触stm32地址偏移的概念时,非常的困惑,以GPIO寄存器为例,为什么相邻寄存器的偏移地址是0x04? 答:首先大家要弄明白两个概念 1. 寄存器地址 != 内存空间,寄存器地址只是内 ...

  3. ARM TTBR0TTBR1寄存器与ARM32页表复制。TTBR0TTBR1两寄存器在ARM,ARM32,ARM64linux中分页管理页表基地址的存放不同,CP15 CP2控制TTBR01附加协处理

    一,ARM TTBR0,TTBR1寄存器: 从ARMV6开始增加了TTBR1寄存器,但是在ARM32的时候,TTBR1寄存器未使用,原因如下: TTBR0和TTBR1寄存器只支持2G,1G,512M等 ...

  4. STM32 固件库外设 GPIO 讲解(关于 GPIO 寄存器讲解)

    GPIO 外设讲解 通过博主上一篇博客,相信大家已经初步了解到了对于 STM32 的控制原理,但是 STM32 到外设 / 引脚有这么多,是要一个一个的去记住它的地址?或者每一次使用一个外设都要看一下 ...

  5. 如何通过ip地址查找PC接在交换机的某个端口

    如何通过ip地址查找PC接在交换机的某个端口. 1,登陆交换机show arp | include *.*.*.*(ip地址)查处pc的mac地址. 2,show mac-address table ...

  6. 【Windows 逆向】使用 CE 工具挖掘关键数据内存真实地址 ( 查找子弹数据的动态地址 | 查找子弹数据的静态地址 | 静态地址分析 | 完整流程 ) ★

    文章目录 前言 一.查找子弹数据临时内存地址 二.查找子弹数据的静态地址 1.调试内存地址 05A59544 获取基址 05A59478 2.通过搜索基址 05A59478 获取内存地址 0E1DC1 ...

  7. 【Android 逆向】代码调试器开发 ( 代码调试器功能简介 | 设置断点 | 读写内存 | 读写寄存器 | 恢复运行 | Attach 进程 )

    文章目录 一.代码调试器功能简介 二.Attach 进程 一.代码调试器功能简介 代码调试器功能 : 设置断点 : 无论什么类型的调试器 , 都必须可以设置断点 , 运行到断点处 , 挂起被调试进程 ...

  8. java根据ip查计算机名_Java如何从IP地址查找主机名?

    在Java编程中,如何从IP地址查询出主机名? 以下示例显示了如何通过net.InetAddress类的InetAddress.getByName()方法将指定的IP地址查到主机名称. package ...

  9. 异常处理第一讲(SEH),筛选器异常,以及__asm的扩展,寄存器注入简介

    异常处理第一讲(SEH),筛选器异常,以及__asm的扩展,寄存器注入简介 参考文章: (1)异常处理第一讲(SEH),筛选器异常,以及__asm的扩展,寄存器注入简介 (2)https://www. ...

最新文章

  1. 微信上传素材 java_微信素材上传(JAVA)
  2. 第60课 比特超市 《小学生C++趣味编程》
  3. 简单描述HTML相对路径与绝对路径(转)
  4. python入门经典100例-【python】编程语言入门经典100例--22
  5. 链表常见算法题总结(Java)
  6. 图标跟字对不齐_css:图标与文字对齐的两种方法
  7. Android WebView基本使用
  8. 机械类有哪些好投一些的核心期刊?
  9. 只要 Github 域名指向任意 IP,该 IP 的 443 端口就会超时 3 分钟(TCPing, 80 端口正常)
  10. 均价 和 最新价格 是啥意思 什么是MACD DIFF DEA 指标?
  11. RS485两台设备用了半年,今天突然没数了,并上串口一直时不时有多余FF等乱码输出。单独串口接电脑试都正常,共地就正常了
  12. 史上超全免费photoshop实训零基础视频教程,新手学习PS软件教程资源下载
  13. 初始值设置项里有未知的字段ndo_change_mtu
  14. Spring Boot cache backed guava/caffeine
  15. 数据结构与算法(六)- 单向链表的反转
  16. 佳能打印机手机显示未连接服务器失败,佳能打印机连不上手机
  17. 【Java】继承、多态、接口
  18. 【轉】一個在台積電工作3年的工程師寫給學弟學妹們的信
  19. Java语言编写计算器
  20. Win10笔记本电脑某些应用能使用麦克风,但某些无法使用麦克风解决方法(本文以QQ为例,其他应用也适用)

热门文章

  1. knn之KD树深度构建原理
  2. CodePen最佳实例分享
  3. 【运筹学】由原问题直接写出对偶问题
  4. 解决IDEA输出中文显示为问号
  5. html的div的间隙,解决DIV浮动间隙
  6. 聚类算法之层次聚类方法
  7. 「GATK 4」如何提高HaplotyperCaller的效率
  8. MOOC战德臣数据库课程自用笔记_9_范式
  9. CCNP Switching (300-115) Cert Prep: 1 Layer 2 Technologies CCNP交换(300-115)证书准备:1层2技术 Lynda课程中文字幕
  10. camstar portal 7全屏显示