24c04硬件地址位_【博文连载】奔跑吧,SOC(一)——软件是怎么控制硬件的

很多人肯定很疑惑,在嵌入式开发中,为什么写c代码,就能够控制硬件。这一切是怎么发生的了,下面我就给大家解剖一下,软件是怎么控制硬件的。

我们从控制8个led为例来说明:

从最简单的开始,如果使用硬件,控制8个led,最简单的方式是什么:直接接上开关。就是以下的图。通过开关控制led管脚输出不同的电平,就能控制led了。但是这个方法很不灵活,我们要手动的去拨动开关,才能改变led状态。

bc6244638566c39354f9813841a34747.png

我们将上面电路改一下,把开关的地方换成寄存器,并加一些额外的电路,这样就可以通过使能信号和信号值改变led值输出不同电平,间接的控制led了。而使能信号和信号值我们是可以通过外部给的,就比开关要灵活一些了。

ceae7aa82e48ae3c6cd5f09bd42f6519.png

既然,上面有寄存器,我们可以给这个寄存器定义一个地址,当然这个地址目前是可以随意定义的。假设为0x77777777。你可能会有疑问,为什么要给寄存器定义地址了?而且定义的地址为什么是32位了,这个先不着急,听我慢慢道来。

我们继续在前面加电路

0da2c36c14caa85875ce5498f1de1aaf.png

这里,多了一个前级电路,前级电路提供两个信号,一个地址,一个数据。在地址信号通路上,有一个电路模块,判断地址是不是0x77777777,是的话,使能信号为1,这样数据不就直接传递给寄存器了。不是的话,使能信号为0。寄存器的输出不变。这样,通过地址和数据就能改变led了。

这里0x77777777是不是很熟悉,这不就是之前定义的寄存器A的地址吗?原来,地址就是用来判断是否产生使能信号的,使能才能使数据能够输入到寄存器中。

到了这里,是不是对软件控制硬件有些眉目了。别着急,我们继续往下走。

既然前级电路只需要提供地址和数据,并且地址是0x77777777,就可以控制寄存器A的值了,而控制了寄存器A,就控制led。那么我们将前级电路换成一个32位CPU。

我们知道,CPU是可以产生3种总线信号的,一种地址总线,一种数据总线,一种控制总线。控制总线我们这里用不到。将地址总线接到地址线上,将数据总线接到数据线上。就是以下的电路:

fa629a31adb0cda4f31f522ebf064d32.png

如果我们让CPU产生地址为0x77777777,然后发出想要写入寄存器A的数据B,那么数据B不就被写入到寄存器A中,这样,不就控制led了。这里知道为什么地址要32位的把,因为CPU是32位的,地址就是32位宽的。之所以定义32位的地址,目的是为了和CPU的地址总线32位宽兼容。

到这里,是不是有豁然开朗的感觉了。我们再继续。

我们知道CPU是要取机器码然后执行的。如果刚好某条机器码,能让地址总线上产生0x77777777,数据总线上产生数据B。那么结果,数据B不就被写入到寄存器A中了。假设CPU是32位risc的CPU,机器码就是32位。那么该机器码应该是如下:

1001 0000 1110 0000 1011 1010 1111 0010(假设)

既然这是一条机器码,那么就应该有一个汇编指令与之对应,假设是

str r0, r1

我们预先将地址0x77777777写入到r0中,数据B写入到r1中,那么上面一条语句执行后,不就将数据B写入到寄存器A中了,不就控制led了。这样不就实现了软件控制了硬件了。既然汇编代码可以控制硬件了,那么高级语言同样也是控制硬件的,只要编译后的汇编代码是以上代码就行了。

整体控制硬件的代码就是

ldr r0, = 0x77777777

ldr r1, =B

str [r0], r1

对应的C代码就是

(*(volatile unsigned long *)0x77777777) = B;

使用指针操作,往0x77777777地址的寄存器写入数据B,加入volatile关键字,是防止编译器对操作进行优化。

通过上面的过程,是不是也可以理解,为什么在嵌入式底层驱动开发中,基本都是用C语言,而不用其他高级语言,比如JAVA等。因为这些高级语言没有指针,你就不能控制寄存器,不能控制寄存器了,你当然就控制不了硬件了。C++也很少用,因为底层驱动开发需要高效率代码,不能太复杂,而C++在这方面,比不过C语言。

以上是写入的过程了,如果想要知道led的状态呢?通过读取寄存器A的值,不就知道led的状态了。原理是一样的。只不过数据线要变成两根,一个是负责写,一根负责读。电路图如下:

9fc90bb93b27f182cae8bb0d02815c88.png

因为只考虑了一个寄存器,当不选中寄存器A时,读取的数据为全0。

通过,上面的讲述,对软件控制硬件有没有了解一些了。软件控制硬件,本质上,就是通过写代码去修改或读取硬件对应的寄存器的值。这样,就相当于间接的控制了硬件。而硬件的寄存器对于一个处理器来说,都是固定的,都预先定义好了地址。所以在看ARM的数据手册中,可以看到很多寄存器的地址。这些地址的作用,也就是能够让你在写程序的时候,能够正确的往这些寄存器里面写入或读取正确的值,从而控制硬件。

CPU对外看到的都是寄存器,所以硬件设计的时候,就要对硬件的功能设置几个寄存器,然后对这几个寄存器分别定义几个地址,这样CPU才可以去控制这几个寄存器,也就能控制硬件了。定义的寄存器地址位宽是和CPU的地址线位宽是有关系的,如果是一个8位的CPU,也就是经典的C51,地址的宽度就是8位,所以你可以在头文件reg51.c中看到使用sfr定义的地址位宽是8位。在STM32中,CPU是32位的,所以地址的宽度就是32位的,所以你看到STM32数据手册中,寄存器的地址都是32位的,而且是4字节对齐的。

以上,CPU只是控制了一个硬件,led,但是我们知道,CPU是可以控制很多硬件的,那这又是怎么实现的了?这个就得谈谈片上互联总线了。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值