16进制中0x00004000,为什么在vl53l0x寄存器设置中是第10位?

16进制中0x,为什么在寄存器中是第10位?_百度知道
16进制中0x,为什么在寄存器中是第10位?
我有更好的答案
0x00004的二进制是,因此1确实在第10位。
不是很懂,是怎么变换过来的呀?
你说的第10位不知道是什么意思,如果是1所在的位置好像不是第10位。从表达来说寄存器是32位。而0x的二进制表达是00 00 。
采纳率:68%
来自团队:
0x4000(16进制) = 00 0000(2进制 = 单片机中的存放方式)
并没有体现第10位的特点呀?
为您推荐:
其他类似问题
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。第5章 &&&&什么是寄存器
全套200集视频教程和1000页PDF教程请到秉火论坛下载:
野火视频教程优酷观看网址:http://i.youku.com/firege
本章参考资料:《中文参考手册》、《数据手册》、
学习本章时,配合《中文参考手册》"存储器和总线架构"、"嵌入式接口"及"通用"章节一起阅读,效果会更佳,特别是涉及到寄存器说明的部分。
5.1 什么是寄存器
我们经常说寄存器,那么什么是寄存器?这是我们本章需要讲解的内容,在学习的过程中,大家带着这个疑问好好思考下,到最后看看大家能否用一句话给寄存器下一个定义。
5.2 STM32长啥样
我们开发板中使用的芯片是的,具体见图。这个就是我们接下来要学习的,它讲带领我们进入嵌入式的殿堂。
芯片正面是丝印,应该是表示该芯片使用的是的内核,是芯片型号,后面的字应该是跟生产批次相关,最下面的是的。
芯片四周是引脚,左下角的小圆点表示脚,然后从脚起按照逆时针的顺序排列(所有芯片的引脚顺序都是逆时针排列的)。开发板中把芯片的引脚引出来,连接到各种传感器上,然后在上编程(实际就是通过程序控制这些引脚输出高电平或者低电平)来控制各种传感器工作,通过做实验的方式来学习芯片的各个资源。开发板是一种评估板,板载资源非常丰富,引脚复用比较多,力求在一个板子上验证芯片的全部功能。
图 51 STM32F429IGT6 实物图
图 52 STM32F429IGT6正面引脚图
5.3 芯片里面有什么
我们看到的芯片已经是已经封装好的成品,主要由内核和片上外设组成。若与电脑类比,内核与外设就如同电脑上的与主板、内存、显卡、硬盘的关系。
采用的是内核,内核即,由公司设计。公司并不生产芯片,而是出售其芯片技术授权。芯片生产厂商如、、,负责在内核之外设计部件并生产整个芯片,这些内核之外的部件被称为核外外设或片上外设。如、(串口)、、等都叫做片上外设。具体见图。
图 53 STM32芯片架构简图
芯片和外设之间通过各种总线连接,其中主控总线有条,被控总线有条,具体见图。主控总线通过一个总线矩阵来连接被控总线,总线矩阵用于主控总线之间的访问仲裁管理,仲裁采用循环调度算法。总线之间交叉的时候如果有个圆圈则表示可以通信,没有圆圈则表示不可以通信。比如:总线只有跟、和这三根被控总线交叉的时候才有圆圈,就表示只能跟这三根被控总线通信。从功能上来理解,总线是指令总线,用来取指,指令指的是编译好的程序指令。我们知道有三种启动方式,从启动(包含系统存储器),从内部启动,从外部启动,这三种存储器刚好对应的就是、和这三条总线。
图 54 STM32F42xxx 和 STM32F43xxx 器件的总线接口
5.4 存储器映射
在图中,连接被控总线的是,和片上外设,这些功能部件共同排列在一个的地址空间内。我们在编程的时候,操作的也正是这些功能部件。
5.4.1 存储器映射
存储器本身不具有地址信息,它的地址是由芯片厂商或用户分配,给存储器分配地址的过程就称为存储器映射,具体见图。如果给存储器再分配一个地址就叫存储器重映射。
图 55 存储器映射
1.&&&&存储器区域功能划分
在这的地址空间中,已经粗线条的平均分成了个块,每块,每个块也都规定了用途,具体分类见表格。每个块的大小都有,显然这是非常大的,芯片厂商在每个块的范围内设计各具特色的外设时并不一定都用得完,都是只用了其中的一部分而已。
表格 51 存储器功能分类
在这个里面,有个块非常重要,也是我们最关心的三个块。用来设计成内部,用来设计成内部,用来设计成片上的外设,下面我们简单的介绍下这三个里面的具体区域的功能划分。
存储器Block0内部区域功能划分
主要用于设计片内的,系列片内部最大是,我们使用的的是。要在芯片内部集成更大的或者都意味着芯片成本的增加,往往片内集成的都不会太大,能在追求性价比的同时做到以上,实乃良心之举。内部区域的功能划分具体见表格。
表格 52 存储器Block0 内部区域功能划分
区域:其中个字节只能写一次,用于存储用户数据,额外的个字节用于锁定对应的数据块。
系统存储器:里面寸的是出厂时烧写好的自举程序,用户无法改动。串口下载的时候需要用到这部分程序。
选项字节:用于配置读写保护、BOR 级别、软件/硬件看门狗以及器件处于待机或停止模式下的复位。当芯片不小心被锁住之后,我们可以从里面启动来修改这部分相应的寄存器位。
数据:,直接通过总线读取,不用经过总线矩阵,属于高速的。
:我们的程序就放在这里。
取决于引脚,为、系统存储器、的别名。
储存器Block1内部区域功能划分
用于设计片内的。内部的大小为,其中的位于,剩下的位于,分,,,内部区域的功能划分具体见表格。
表格 53 存储器Block1 内部区域功能划分
储存器Block2内部区域功能划分
用于设计片内的外设,根据外设的总线速度不同,被分成了和两部分,其中又被分为和,分为和,具体见表格。还有一个包含了,这四个用于扩展外部存储器,如,和等。
表格 54 存储器Block2 内部区域功能划分
5.5 寄存器映射
我们知道,存储器本身没有地址,给存储器分配地址的过程叫存储器映射,那什么叫寄存器映射?寄存器到底是什么?
在存储器这块区域,设计的是片上外设,它们以四个字节为一个单元,共,每一个单元对应不同的功能,当我们控制这些单元时就可以驱动外设工作。我们可以找到每个单元的起始地址,然后通过语言指针的操作方式来访问这些单元,如果每次都是通过这种地址的方式来访问,不仅不好记忆还容易出错,这时我们可以根据每个单元功能的不同,以功能为名给这个内存单元取一个别名,这个别名就是我们经常说的寄存器,这个给已经分配好地址的有特定功能的内存单元取别名的过程就叫寄存器映射。
比如,我们找到端口的输出数据寄存器的地址是(至于这个地址如何找到可以先跳过,后面我们会有详细的讲解),寄存器是,低有效,对应着个外部,写对应的的则输出低高电平。现在我们通过语言指针的操作方式,让的个都输出高电平,具体见代码。
代码 51 通过绝对地址访问内存单元
1 // GPIOH 端口全部输出高电平
2 *(unsigned int*)(0x) = 0xFFFF;
在我们看来是端口的地址,但是在编译器看来,这只是一个普通的变量,是一个立即数,要想让编译器也认为是指针,我们得进行强制类型转换,把它转换成指针,即,然后再对这个指针进行操作。
刚刚我们说了,通过绝对地址访问内存单元不好记忆且容易出错,我们可以通过寄存器的方式来操作,具体见代码。
代码 52 通过寄存器别名方式访问内存单元
1 // GPIOH 端口全部输出高电平
2 #define GPIOH_ODR (unsigned int*)(GPIOH_BASE+0x14)
3 * GPIOH_ODR = 0xFF;
为了方便操作,我们干脆把指针操作""也定义到寄存器别名里面,具体见代码。
代码 53 通过寄存器别名访问内存单元
1 // GPIOH 端口全部输出高电平
2 #define GPIOH_ODR *(unsigned int*)(GPIOH_BASE+0x14)
3 GPIOH_ODR = 0xFF;
5.5.1 STM32的外设地址映射
片上外设区分为四条总线,根据外设速度的不同,不同总线挂载着不同的外设,挂载低速外设,挂载高速外设。相应总线的最低地址我们称为该总线的基地址,总线基地址也是挂载在该总线上的首个外设的地址。其中总线的地址最低,片上外设从这里开始,也叫外设基地址。
1.&&&&总线基地址
表格 55 总线基地址
总线基地址
相对外设基地址的偏移
已不属于片上外设
表格的"相对外设基地址偏移"即该总线地址与"片上外设"基地址的差值。关于地址的偏移我们后面还会讲到。
2.&&&&外设基地址
总线上挂载着各种外设,这些外设也有自己的地址范围,特定外设的首个地址称为"外设基地址",也叫外设的边界地址。具体有关外设的边界地址请参考《参考手册》的小节的存储器映射的表:寄存器边界地址。或者参考《参考手册》的存储器映射章节,这两个手册都有详细的讲解。
这里面我们以这个外设来讲解外设的基地址,具体见表格。
表格 56 外设GPIO基地址
外设基地址
相对AHB1总线的地址偏移
从表格看到,的基址相对于总线的地址偏移为,我们应该就可以猜到,总线的第一个外设就是。
3.&&&&外设寄存器
在外设的地址范围内,分布着的就是该外设的寄存器。以外设为例,是通用输入输出端口的简称,简单来说就是可控制的引脚,基本功能是控制引脚输出高电平或者低电平。最简单的应用就是把的引脚连接到灯的阴极,灯的阳极接电源,然后通过控制该引脚的电平,从而实现控制灯的亮灭。
有很多个寄存器,每一个都有特定的功能。每个寄存器为,占四个字节,在该外设的基地址上按照顺序排列,寄存器的位置都以相对该外设基地址的偏移地址来描述。这里我们以端口为例,来说明都有哪些寄存器,具体见表格。
表格 57 GPIOH端口的寄存器地址列表
寄存器名称
寄存器地址
相对GPIOH基址的偏移
有关外设的寄存器说明可参考《参考手册》中具体章节的寄存器描述部分,在编程的时候我们需要反复的查阅外设的寄存器说明。
这里我们以"端口置位复位寄存器"为例,教大家如何理解寄存器的说明,具体见图。
图 56 GPIO端口置位/复位寄存器说明
?&&&&①名称
寄存器说明中首先列出了该寄存器中的名称,""这段的意思是该寄存器名为""其中的""可以为,也就是说这个寄存器说明适用于、至,这些端口都有这样的一个寄存器。
?&&&&②偏移地址
偏移地址是指本寄存器相对于这个外设的基地址的偏移。本寄存器的偏移地址是,从参考手册中我们可以查到外设的基地址为,我们就可以算出的这个寄存器的地址为:;同理,由于的外设基地址为,可算出寄存器的地址为:。其他端口以此类推即可。
?&&&&③寄存器位表
紧接着的是本寄存器的位表,表中列出它的位的名称及权限。表上方的数字为位编号,中间为位名称,最下方为读写权限,其中表示只写,表示只读,表示可读写。本寄存器中的位权限都是,所以只能写,如果读本寄存器,是无法保证读取到它真正内容的。而有的寄存器位只读,一般是用于表示外设的某种工作状态的,由硬件自动更改,程序通过读取那些寄存器位来判断外设的工作状态。
?&&&&④位功能说明
位功能是寄存器说明中最重要的部分,它详细介绍了寄存器每一个位的功能。例如本寄存器中有两种寄存器位,分别为及,其中的数值可以是,这里的表示端口的引脚号,如、用于控制的第个引脚,若表示,那就是控制的第引脚,而、就是控制第个引脚。
其中引脚的说明是":不会对相应的位执行任何操作;:对相应位进行复位"。这里的"复位"是将该位设置为的意思,而"置位"表示将该位设置为;说明中的是另一个寄存器的寄存器位,我们只需要知道位为的时候,对应的引脚输出高电平,为的时候对应的引脚输出低电平即可感兴趣的读者可以查询该寄存器的说明了解。所以,如果对写入""的话,那么的第个引脚就会输出"低电平",但是对写入""的话,却不会影响位,所以引脚电平不会改变。要想该引脚输出"高电平",就需要对""位写入"",寄存器位与是相反的操作。
5.5.2 C语言对寄存器的封装
以上所有的关于存储器映射的内容,最终都是为大家更好地理解如何用语言控制读写外设寄存器做准备,此处是本章的重点内容。
1.&&&&封装总线和外设基地址
在编程上为了方便理解和记忆,我们把总线基地址和外设基地址都以相应的宏定义起来,总线或者外设都以他们的名字作为宏名,具体见代码。
代码 54 总线和外设基址宏定义
1 /* 外设基地址 */
2 #define PERIPH_BASE ((unsigned int)0x)
4 /* 总线基地址 */
5 #define APB1PERIPH_BASE PERIPH_BASE
6 #define APB2PERIPH_BASE (PERIPH_BASE + 0x)
7 #define AHB1PERIPH_BASE (PERIPH_BASE + 0x)
8 #define AHB2PERIPH_BASE (PERIPH_BASE + 0x)
10 /* GPIO外设基地址 */
11 #define GPIOA_BASE (AHB1PERIPH_BASE + 0x0000)
12 #define GPIOB_BASE (AHB1PERIPH_BASE + 0x0400)
13 #define GPIOC_BASE (AHB1PERIPH_BASE + 0x0800)
14 #define GPIOD_BASE (AHB1PERIPH_BASE + 0x0C00)
15 #define GPIOE_BASE (AHB1PERIPH_BASE + 0x1000)
16 #define GPIOF_BASE (AHB1PERIPH_BASE + 0x1400)
17 #define GPIOG_BASE (AHB1PERIPH_BASE + 0x1800)
18 #define GPIOH_BASE (AHB1PERIPH_BASE + 0x1C00)
20 /* 寄存器基地址,以GPIOH为例 */
21 #define GPIOH_MODER (GPIOH_BASE+0x00)
22 #define GPIOH_OTYPER (GPIOH_BASE+0x04)
23 #define GPIOH_OSPEEDR (GPIOH_BASE+0x08)
24 #define GPIOH_PUPDR (GPIOH_BASE+0x0C)
25 #define GPIOH_IDR (GPIOH_BASE+0x10)
26 #define GPIOH_ODR (GPIOH_BASE+0x14)
27 #define GPIOH_BSRR (GPIOH_BASE+0x18)
28 #define GPIOH_LCKR (GPIOH_BASE+0x1C)
29 #define GPIOH_AFRL (GPIOH_BASE+0x20)
30 #define GPIOH_AFRH (GPIOH_BASE+0x24)
代码首先定义了"片上外设"基地址,接着在上加入各个总线的地址偏移,得到、等总线的地址、,在其之上加入外设地址的偏移,得到、的外设地址,最后在外设地址上加入各寄存器的地址偏移,得到特定寄存器的地址。一旦有了具体地址,就可以用指针操作读写了,具体见代码。
代码 55 使用指针控制BSRR寄存器
1 /* 控制GPIOH 引脚10输出低电平(BSRR寄存器的BR10置1) */
2 *(unsigned int *)GPIOH_BSRR = (0x01&&(16+10));
4 /* 控制GPIOH 引脚10输出高电平(BSRR寄存器的BS10置1) */
5 *(unsigned int *)GPIOH_BSRR = 0x01&&10;
7 unsigned int
8 /* 控制GPIOH 端口所有引脚的电平(读IDR寄存器) */
9 temp = *(unsigned int *)GPIOH_IDR;
该代码使用把宏的数值强制转换成了地址,然后再用""号做取指针操作,对该地址的赋值,从而实现了写寄存器的功能。同样,读寄存器也是用取指针操作,把寄存器中的数据取到变量里,从而获取外设的状态。
2.&&&&封装寄存器列表
用上面的方法去定义地址,还是稍显繁琐,例如都各有一组功能相同的寄存器,如等等,它们只是地址不一样,但却要为每个寄存器都定义它的地址。为了更方便地访问寄存器,我们引入语言中的结构体语法对寄存器进行封装,具体见代码。
代码 56 使用结构体对GPIO寄存器组的封装
1 typedef unsigned int uint32_t; /*无符号32位变量*/
2 typedef unsigned short int uint16_t; /*无符号16位变量*/
4 /* GPIO寄存器列表 */
5 typedef struct {
uint32_t MODER; /*GPIO模式寄存器地址偏移: 0x00 */
uint32_t OTYPER; /*GPIO输出类型寄存器地址偏移: 0x04 */
uint32_t OSPEEDR; /*GPIO输出速度寄存器地址偏移: 0x08 */
uint32_t PUPDR; /*GPIO上拉/下拉寄存器地址偏移: 0x0C */
uint32_t IDR; /*GPIO输入数据寄存器地址偏移: 0x10 */
uint32_t ODR; /*GPIO输出数据寄存器地址偏移: 0x14 */
uint16_t BSRRL; /*GPIO置位/复位寄存器低16位部分地址偏移: 0x18 */
uint16_t BSRRH; /*GPIO置位/复位寄存器高16位部分地址偏移: 0x1A */
uint32_t LCKR; /*GPIO配置锁定寄存器地址偏移: 0x1C */
uint32_t AFR[2]; /*GPIO复用功能配置寄存器地址偏移: 0x20-0x24 */
16 } GPIO_TypeD
这段代码用关键字声明了名为的结构体类型,结构体内有个成员变量,变量名正好对应寄存器的名字。语言的语法规定,结构体内变量的存储空间是连续的,其中位的变量占用个字节,位的变量占用个字节,具体见图。
图 57 GPIO_TypeDef结构体成员的地址偏移
也就是说,我们定义的这个,假如这个结构体的首地址为(这也是第一个成员变量的地址),那么结构体中第二个成员变量的地址即为,加上的这个,正是代表所占用的个字节地址的偏移量,其它成员变量相对于结构体首地址的偏移,在上述代码右侧注释已给出,其中的寄存器分成了低位和高位,置引脚输出高电平,置引脚输出低电平,这里分开只是为了方便操作。
这样的地址偏移与外设定义的寄存器地址偏移一一对应,只要给结构体设置好首地址,就能把结构体内成员的地址确定下来,然后就能以结构体的形式访问寄存器了,具体见代码。
代码 57 通过结构体指针访问寄存器
1 GPIO_TypeDef * GPIOx; //定义一个GPIO_TypeDef型结构体指针GPIOx
2 GPIOx = GPIOH_BASE; //把指针地址设置为宏GPIOH_BASE地址
3 GPIOx-&BSRRL = 0xFFFF; //通过指针访问并修改GPIOH_BSRRL寄存器
4 GPIOx-&MODER = 0xFFFFFFFF; //修改GPIOH_MODER寄存器
5 GPIOx-&OTYPER =0xFFFFFFFF; //修改GPIOH_OTYPER寄存器
7 uint32_t
8 temp = GPIOx-&IDR; //读取GPIOH_IDR寄存器的值到变量temp中
这段代码先用类型定义一个结构体指针,并让指针指向地址,使用地址确定下来,然后根据语言访问结构体的语法,用、及等方式读写寄存器。
最后,我们更进一步,直接使用宏定义好类型的指针,而且指针指向各个端口的首地址,使用时我们直接用该宏访问寄存器即可,具体代码。
代码 58 定义好GPIO端口首地址址针
1 /*使用GPIO_TypeDef把地址强制转换成指针*/
2 #define GPIOA ((GPIO_TypeDef *) GPIOA_BASE)
3 #define GPIOB ((GPIO_TypeDef *) GPIOB_BASE)
4 #define GPIOC ((GPIO_TypeDef *) GPIOC_BASE)
5 #define GPIOD ((GPIO_TypeDef *) GPIOD_BASE)
6 #define GPIOE ((GPIO_TypeDef *) GPIOE_BASE)
7 #define GPIOF ((GPIO_TypeDef *) GPIOF_BASE)
8 #define GPIOG ((GPIO_TypeDef *) GPIOG_BASE)
9 #define GPIOH ((GPIO_TypeDef *) GPIOH_BASE)
13 /*使用定义好的宏直接访问*/
14 /*访问GPIOH端口的寄存器*/
15 GPIOH-&BSRRL = 0xFFFF; //通过指针访问并修改GPIOH_BSRRL寄存器
16 GPIOH-&MODER = 0xFFFFFFF; //修改GPIOH_MODER寄存器
17 GPIOH-&OTYPER =0xFFFFFFF; //修改GPIOH_OTYPER寄存器
19 uint32_t
20 temp = GPIOH-&IDR; //读取GPIOH_IDR寄存器的值到变量temp中
22 /*访问GPIOA端口的寄存器*/
23 GPIOA-&BSRRL = 0xFFFF; //通过指针访问并修改GPIOA_BSRRL寄存器
24 GPIOA-&MODER = 0xFFFFFFF; //修改GPIOA_MODER寄存器
25 GPIOA-&OTYPER =0xFFFFFFF; //修改GPIOA_OTYPER寄存器
27 uint32_t
28 temp = GPIOA-&IDR; //读取GPIOA_IDR寄存器的值到变量temp中
这里我们仅是以这个外设为例,给大家讲解了语言对寄存器的封装。以此类推,其他外设也同样可以用这种方法来封装。好消息是,这部分工作都由固件库帮我们完成了,这里我们只是分析了下这个封装的过程,让大家知其然,也只其所以然。
5.6 每课一问
1、&&&&什么是存储器映射?什么是存储器重映射?
2、&&&&什么是寄存器?
阅读(...) 评论()他的最新文章
他的热门文章
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)STM32L0x-02系统及内存概述_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
STM32L0x-02系统及内存概述
嵌入式工程师|
总评分0.0|
用知识赚钱
阅读已结束,下载本文需要
想免费下载本文?
定制HR最喜欢的简历
下载文档到电脑,方便使用
还剩8页未读,继续阅读
定制HR最喜欢的简历
你可能喜欢他的最新文章
他的热门文章
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)}

我要回帖

更多关于 四位二进制数寄存器 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信