【问题标题】:How to a program works with hardware device程序如何与硬件设备一起工作
【发布时间】:2018-09-27 15:23:34
【问题描述】:

我想知道程序如何与硬件设备一起工作。我想了解不深入的基础知识。

所有编程代码都有以下内容。

  • int、float、short 等变量。
  • 函数和函数调用
  • if else 之类的语句
  • 计算
  • for 循环等循环

我想当我们将程序下载到硬件时,数据会进入编程存储器 (ROM)。当我们运行程序时,上面提到的所有东西都进入 RAM 还是只进入特定区域,如函数数据?

当我们考虑 8bit 总线时,如何处理超过 8bit 的数据,比如 10bit char,因为总线很小?

什么是堆栈以及如何使用它进行编程?

为什么void main 功能很重要?如何硬件识别?

请告诉我如何使用硬件进行编程。

【问题讨论】:

  • 你所有的问题都依赖于硬件设备,需要很多大书才能详细解答。硬件设备几乎涵盖了所有内容,包括无法通过传统方式编程的设备、具有 32 位总线的设备、没有任何总线的设备,以及完全模拟的设备。您有更具体的硬件设备吗?
  • 没有特定的硬件设备我一般问这个问题并得到一个基本的想法。如果您愿意,我可以考虑使用 PIC 单片机设备,例如 PIC16F887 IC

标签: process hardware


【解决方案1】:

你有很多问题。 首先,让我们假设一个简单的情况,比如 Arduino,它是软件和硬件的组合。 软件部分从您编写一些简单的 C++ 代码开始,例如:

byte ledPin = 13;
void setup(){
pinMode (ledPin, OUTPUT);
}
void loop(){
digitalWrite (ledPin, HIGH);
digitalWrite (ledPin, LOW);
}

接下来,您将编译代码。 Arduino IDE(集成开发环境)做了一些事情(在后台,比如添加一个 main() 来调用 setup() 函数一次,循环()函数重复)将 C++ 转换为汇编代码,它可能看起来像这样(不是上面的实际输出):

; Define pull-ups and set outputs high
; Define directions for port pins
ldi r16,(1<<PB7)|(1<<PB6)|(1<<PB1)|(1<<PB0)
ldi r17,(1<<DDB3)|(1<<DDB2)|(1<<DDB1)|(1<<DDB0)
out PORTB,r16
out DDRB,r17
; Insert nop for synchronization
nop
; Read port pins
in r16,PINB

汇编程序将代码转换为十六进制格式信息,程序员可以将其放入 Atmega328P 微控制器的 ROM 中。基本上,文件中的数据行,每行包含一行的起始地址,可能是 16 个字节的数据,以及一个校验和,以确保数据在处理时没有损坏:

000100005673495a6b4f5e205673495a6b4f5e24465

这不是真实数据。 0001000 可能是 ROM 中的起始地址,接下来的 32 个字符是要编程的 16 个字节的数据,最后 4 个可能是通过以某种方式操作数据创建的校验和。程序员接收数据,执行相同的操作,如果校验和正确,则将其刻录到内存中。

可以通过多种方式将十六进制代码放入 ROM - 程序员可以控制芯片并将代码直接放入内存,复位后芯片将运行代码;或者引导加载程序可以复位后从芯片上的 ROM 区域运行,它会通过串行线(Rx,Tx)与 PC 通信以接收数据,然后将其写入 ROM 的不同区域。如果引导加载代码没有检测到 PC 试图与其通信,它将跳转到代码开始的 ROM 地址并从那里运行。

8 位微控制器可能有一些 16 位寄存器,可用于捕获 ADC 转换的结果,或者将结果存储为两个 8 位字节,包含高位和低位数据。

堆栈可能是专用的硬件寄存器,也可能是 SRAM 的一个区域,用于保存诸如数学运算结果之类的东西。代码负责将内容放入堆栈并读回,您通常不会处理它的编程。对于 '328P,有 2048 字节的 SRAM,因此您只需要确保没有在代码中声明太多变量(如 byte ledPin = 13;),这些变量都用完了并且没有留下空间对于代码。通常,例如在 328Ps 中,这是由于尝试访问超出其限制的数组而引起的,因此要么返回无意义的结果,要么在写入超过数组末尾的内容覆盖其他内容时导致程序崩溃。 C++的灵活性很好,但稍不注意也会让你陷入困境。

【讨论】:

    【解决方案2】:

    正如@nos 所说,需要大量书籍来解释它。

    在代码和硬件之间缺少的是编译器。它的作用是将您的代码(C、C++ 或任何语言)翻译成汇编。汇编大致是一组 CPU 或微控制器能够理解的非常底层的指令。

    当程序翻译成汇编时,它被上传到内存中。根据架构的不同,它进入通用存储器(冯诺依曼)或程序存储器(与哈佛架构的数据存储器相对)。

    当谈到堆栈时,你也有指针。指针指向(是的,指向的指针,真棒啊)堆栈的“级别”。例如,您有指向当前指令的“当前”指针。一旦当前指令完成,指针就会递增,因此指向下一级。 当您调用子函数并指向您停止父函数的级别时,将使用另一个指针。一个子功能完成了,你回到你停止的地方。

    这些指针存储在寄存器中,这些寄存器是芯片中的小(且快速)存储器。

    来到 main 函数,硬件在编译时并没有从字面上识别它。对于硬件,只有一个程序可以执行(即主程序)并调用子函数(即主程序中使用的函数)。

    所以.. 当你编写一些代码时,让我们说在 C 中:

    int main ()
    {
        int a = 0;
        printf("a = %d", a);
        return 0;
    }
    

    main 的内容被翻译成汇编,是你的“正常”程序。首先,它将 0 放入寄存器的单元格中。然后它暂停执行 printf(它使用我们保存 0 的单元格中的值)并保存它在指针中停止的位置。完成后,当前指针取回我们保存的指针的值并继续。

    关于内存中的内容:您有不同级别的内存。磁盘,硬盘或固态,速度慢但又大又便宜。 Ram,更快但更昂贵且更小。缓存,内置在 CPU 中,速度非常快,体积更小,价格也更贵。寄存器,也是内置的,更快但更小。当 CPU 使用一个变量时,它进入寄存器。但是现代 CPU 会“猜测”(也称为预取)在不久的将来可能需要什么变量(例如,您读取表的前两个单元格,它可能会在您询问之前加载第三个单元格),并将其放入缓存中。否则,它在 ram 中。

    希望对您有所帮助,可能会有一些捷径或不准确之处,但大致就是这样。同样,很难用几行总结数百页。

    【讨论】:

      猜你喜欢
      • 2021-10-14
      • 1970-01-01
      • 1970-01-01
      • 2021-07-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多