【问题标题】:Getting into Embedded [closed]进入嵌入式[关闭]
【发布时间】:2011-03-14 21:01:40
【问题描述】:

我正在努力熟悉嵌入式领域,但在购买时间和设备方面资源有限。

  • 有什么好的语言可以让我了解嵌入式,而不需要花费太多时间来学习嵌入式特定语言?我最熟悉 PHP、Java、Actionscript,但不幸的是,我对 C 知之甚少。我记得在某处读到有人使用 PERL 对嵌入式系统进行编程,但不确定这是否真的可能。

  • 可以通过模拟器等不购买芯片等进行学习吗?

  • 有人可以推荐一个简化的路线图来显示如何获得安全吗?我有点不确定从哪里开始。

【问题讨论】:

标签: c embedded


【解决方案1】:

您需要了解 C(但每个程序员都需要了解 C!)

这些平台中的大多数都有模拟器/仿真器,但由于重点是学习实际应用程序和实际问题(这些都与现实世界的时间问题有关),因此您需要一个真正的电路板。

您可能还想要一台示波器(非常便宜的 n'th 手慢速模拟示波器就可以了)并且知道如何使用它。

最简单的方法可能是Arduino,也许更专业但更难的是launchpad MSP430

【讨论】:

  • +1 到 Arduino。可能是开始使用嵌入式平台的最快/最便宜的方式。
  • 启动板开发套件低于 5 美元,工具链可选 gcc - 但 Arduino 最简单
  • Arduino 基于 Atmel AVR,因此当您超出 Arduino 环境时可以直接用 C 语言对其进行编程。 GCC 对 Atmel AVR 的支持非常好。
  • 大部分同意 - 唯一需要注意的是,如果您能以优惠的价格购买二手示波器,则示波器很棒,但大多数情况下,在 GPIO 引脚上巧妙地应用一些 LED 即可解决问题。即使你有一个示波器,有效地使用它来解决许多问题也需要类似的聪明才智,为此学习你可以用 LED 做什么是很好的训练。当然,在某些情况下,例如串行协议和模拟问题,范围是非常宝贵的,但不需要为学习而提前购买。
【解决方案2】:

有一些嵌入式编程课程可以从一个平台和风格转移到另一个平台和风格,但它确实是一个广泛的领域。不同的处理器可能需要非常不同的策略,不同的应用程序可能决定不同的固件设计策略和不同的微控制器。这里有一些东西可以帮助您入门....

msp430

Texas Instruments 有几个非常便宜的 USB 开发套件,他们称之为 EZ430,并且基于他们的 MSP430 系列微控制器。最简单的有一个 msp430 f2013,它有 2K 的闪存程序空间,3x128 字节的可用用户闪存(还有一个 128 字节的页面,但它很特殊),128 字节的 RAM(是的,128 字节,但对于很多事情来说已经足够了) 和 16 个 CPU 寄存器(其中一些是特殊用途,如堆栈指针、指令指针、状态寄存器,可能还有一两个)。 MSP430 还具有多个存储器映射的特殊功能寄存器,用于配置和控制内置外设。 MSP430 是 von Newman 处理器,因此一切都存在于一个地址空间中。编程器和包含 msp430 f2013 的可移动标签(PC 板)的成本约为 20 美元。大约 10 美元,您可以获得 3 个带有 msp430 2012 的替换标签,它与 2013(大部分)引脚兼容,并具有一些不同的外围设备。这些标签有一个 LED、一个按钮和几个连接到处理器引脚的大过孔(PC 板上的孔)。即使您以前从未焊接过这些通孔,也很容易将电线焊接到其中——由于毛细作用,通孔只会吸走熔化的焊料,而当它很热时,您可以将电线的末端戳进去。

他们还有几个类似的 802.15.4 无线电套件。即使您对收音机不感兴趣,您可能仍然对这些感兴趣,因为他们的程序员也有一个从可移动标签中拉出的 UART,并且与上面提到的其他套件上使用的标签兼容。这些套件还包含至少一个额外的可编程板和一个电池组。 (其中一个工具包可能包含更多,但我现在没有我的,也不打算查找)。

他们还有一个以可编程手表作为目标平台的套件。我从来没有这样的一个,但它们有一个显示器、加速度计和其他一些很酷的东西,但这可能会让你在你的第一个项目中不知所措。我建议您使用以前的套件之一来帮助您开始使用 MSP430。

您可以通过 IAR 的 Embedded Workbench kickstart(4 kb 程序空间限制)IDE、Code Composer Studio(程序大小也有限,但我认为上限更高)和 gcc 的形式获得用于 MSP430 的免费 C 编译器和开发环境/gdb 用于 MSP430。 IAR 的 kickstart 很容易快速上手,尽管它并不完美。您可能会发现必须将其关闭,拔下 USB EZ430,重新启动 IAR,然后重新插入以使其重新运行。或者也许一些不同的顺序会更适合你。

TI 还在名称错误的文件中提供了许多示例(他们所有的可下载文件都以错误的方式命名)。请注意——类似的 MSP430 可能具有用于类似外设的不同设备控制寄存器接口,这可能会造成混淆。确保您正在阅读的任何文档或示例确实适用于您正在使用的微控制器。

其他小型系统

还有许多其他处理器系列和套件可供您使用,您至少应该对它们有所了解。

AVR -- Atmel 的 8/16 位哈佛架构。哈佛指的是代码和工作内存的独立地址空间。它有 32 个 8 位寄存器,其中一些可以作为 16 位寄存器成对使用。这是一个非常流行且非常酷的处理器。一些最小的只有寄存器,没有额外的 RAM,这很可怕。 Atmel 也有一个 AVR32,它与 AVR 完全不同。除非您使用能够加载新代码的现有引导加载程序,否则您需要为这些获取 JTAG 单元。

8051 -- 这就像山丘一样古老,使用起来很痛苦,直到你最终理解它。它是一个 8/16 位处理器,对如何进行 16 位数学运算有更多限制,并且只有一对可以充当指针的寄存器。它有 3 个独立的地址空间(堆栈、全局内存和代码)和许多奇怪的(与其他架构相比)特性。如果您使用 C 进行编程,那么底层的东西可能对您没有多大意义,除了非常简单的 C 操作可能会变成比您想象的要多得多的代码。您很可能不想从其中之一开始。

propeller -- Parallax 非常有趣的多核处理器,与其他处理器非常不同。它有几个核心,这些核心大多独立运作,可用于模拟外围设备或执行更传统的计算任务。尽管我愿意,但我从未使用过其中之一。只是从来没有一个似乎适合它的任务。它们有自己的高级语言来编程它们以及处理器的汇编语言。

更大的系统

退出 8/16/24 位处理器后,您开始模糊嵌入式和桌面级编程之间的界限,即使它在技术上是嵌入式的。

AVR32 -- 这些有 2 个主要版本。一个是哈佛建筑,另一个是冯纽曼。 von Newman 版本本质上是比 ARM 更好的 ARM,但不如 ARM 受欢迎。据我所知,它的设计考虑了“运行 Linux”,尽管并没有以任何疯狂的方式与之绑定。您曾经能够为这些获得便宜的开发板,并且代码通常几乎与将文件从一台 PC 复制到另一台 PC 一样容易加载,尽管您可能会使用 uboot 和 tftp 来完成一些工作。仅当您弄乱引导加载程序时才需要 JTAG。我认为所有这些都支持原生 JAVA 加速。 www.AVR32.org

ARM——最流行的嵌入式处理器。这些有很多版本。有些没有 MMU(内存管理单元),有些则有。关于他们有太多话要说。有的版本有原生的JAVA加速,不过我觉得ARM大佬也不会随便说具体怎么用,所以你得找个JVM知道怎么用。许多供应商都生产它们,包括 Atmel、飞思卡尔、英特尔等。

MIPS -- 一个非常 RISC 的处理器。最危险的。

还有很多其他的。

编程风格

我可以为此写 3 本书,但一般规则是让应用程序尽可能简单。一个例外是,如果您可以轻松使用操作系统,那么您可能希望使用它来简化您的任务。

【讨论】:

  • Ti 在 MSp430 上有很多优惠,一个 USB 可编程板、一些芯片和一根电缆大约 5 美元 - 他们称之为启动板。
  • Launchpad 看起来很有趣。对于喜欢使用烙铁进行机器人项目的人来说,这将是一件好事。
  • 430 内置了不错的硬件,它旨在支持 DMA 和计时器,而不是大多数 I/O 的中断处理程序。非常光滑的处理器系列。在大多数其他 micros 上做同样的事情需要软件更多的“手握”。
  • 对芯片和优缺点的精彩回顾。您如何看待 Microchip PIC?树莓派?阿杜诺?
  • Rasperry Pi 板具有 Broadcom 制造的 ARM 处理器。 Arduino 板有一个 AVR 处理器(通常,虽然那里有一些 ARM 板),但我相信他们有一些在上面运行的软件,许多用户留在板上,所以编码更像是脚本。我不确定,因为我从未使用过其中之一。我也从未使用过任何图片。不过,我知道 PIC32 实际上只是 MIPS 处理器。其他 PICS 与我讨论中列出的微控制器非常不同。
【解决方案3】:

回答这个问题时,您首先需要知道的是“什么是”嵌入式系统?一般定义是专用于单一特定目的的计算机系统。这并不限制您可以使用的硬件类型,事实上“嵌入式 PC”已使用多年。 QNX 实时操作系统自 80 年代初就已存在,多年来一直用于工业 PC 的嵌入式应用。我个人在钢厂 XRAY 测厚仪的控制系统中使用过。另一方面,我目前使用没有任何操作系统支持且仅使用 256K 内存的 TI DSP。另一个例子是您汽车的钥匙扣。旧的曾经使用 Microchip 的 PIC 微控制器。 (这实际上是公司的名称。)

有些人称 iPhone 为嵌入式系统,但由于您可以加载应用程序来做任何事情,我倾向于说它是一款具有电话功能的掌上电脑。一个只是电话而不是 PDA 的 OLD DUMB 手机是一个嵌入式系统。这只是一点哲学。

一般来说,嵌入式系统编程需要掌握一些概念,其中大部分都可以在 PC 上进行探索。

编辑: 推荐 C 或 C++ 的原因是 C 本身就是为进行系统编程而设计的。 C++ 保留了它的所有优点,但增加了 OOP 编程的功能。在某些系统中可能需要一些 ASM。然而,许多芯片供应商,例如 TI,提供的工具基本上可以让你用 C++ 来做你的整个系统。 :END 编辑

很多简单的嵌入式系统或多或少是这样的:

While(true) // LOOP FOREVER... There is no command prompt
{
  // Typically you want I/O to occur on fixed "timebase."
  wait(timerTick);
  readDigitalIO(&dioStruct);
  readAnalogIO(&aioStruct);

  // Combine current system state with input values
  // and do some useful calculations.  (i.e. Analog input to temperature calc)
  Process(dioStruct,aioStruct,&CurrentState);

  // This can be a serial output/audio buzzer/leds/motor controller
  // or Whatever the system REQUIREMENT call for.
  driveOutputs(CurrentState);

  // The watchdog timer resets your system if it gets stuck.
  petWatchDogTimer();
}

这里没有什么是您无法使用 PC 完成的。 (好吧,一台仍然有并行端口的 PC。这或多或少只是一个 DIO 端口。)在没有操作系统的简单系统上,这可能就是全部了。在基于 RTOS 的系统上,您可能有几个任务看起来都与此有些相似,但在任务之间来回传递数据。

当您必须自己连接硬件时,有趣的部分就出现了,我大学毕业后的第一份工作是为 QNX 下的数据采集板编写设备驱动程序。

处理硬件或设备驱动程序的基本概念(您可以通过破解可免费获得的 Linux 设备驱动程序代码来体验它们。),大多数硬件在程序员看来只是另一个内存地址。这称为“内存映射 I/O”。这是什么意思?我们以串口为例:

// Serial port registers definition:
typedef struct  
{
   unsigned int control;  // Control bits for the port.
   unsigned int baudDiv;  // Baud rate divider.
   unsigned int status;   // READ Status bits/ Write resets fifos;
   char TXdata;           // The head of the hardware TX fifo.
   char RXdata;           // The tail of the hardware RX filo.
} serRegs;
// Using the volatile keyword to indicate the hardware can change the value
// independantly from the software.
volatile serRegs *Ser1 = (serRegs *)0x8000;  // Hardware exists at a specific location in memory.
volatile serRegs *Ser2 = (serRegs *)0x8010;  // Hardware exists at a specific location in memory.

// Bits bits 15-12 enable interupts and select interupt vector,
//      bits 11-8 enable,bits 7-4 parity,bits 3-0 stop bits.
Ser1->status = 1; // Reset fifos.  
Ser1->baudDiv = CLOCKVALUE / 9600;  // Set the baudrate 9600;
Ser1->control = 0x1801; // Enable, 8 data, no parity, 1 stop bit.
// Write out a "OK\r\n" message; (Normally this would be a loop.)
Ser1->Txdata = 'O';  // First byte in fifo Transmission starts.
Ser1->Txdata = 'K';  // Second byte in fifo still transmitting first byte
Ser1->Txdata = '\r'; // Third byte in fifo still transmitting first byte
Ser1->Txdata = '\n'; // Fouth byte in fifo still transmitting first byte

通常你会有一个函数或一个中断处理程序来处理发送数据,但是例如我想指出硬件在软件继续运行时正在工作。基本上硬件的工作原理是,我将一个值写入一个地址,并且“STUFF”独立于软件发生。这也许是嵌入式编程的关键概念之一,如何让计算机在现实世界中产生变化。

编辑:

如果你真的想买一块便宜的板子,Micro 开发人员目前的趋势是将开发套件放在 USB 拇指棒上。这个页面有几个信息,从 8 位到 ARM 架构:http://dev.emcelettronica.com/microcontrollers-usb-stick-tool

赛普拉斯 PSOC 是最早使用“FirstTouch 入门套件”实现这一目标的公司之一。 PSOC 是一个非常独特的部分,它有一个微控制器和“可配置的模拟和数字模块”,允许您使用 gui 下载 ADC、串行端口或数字 I/O,并自动配置您的 C 应用程序使用它。 PSOC 还提供 DIP 封装,使其易于在原型机的面包板上使用。

【讨论】:

  • 还有一些芯片没有内存映射 io - 它们会有一个指令 'OUT' 和 'IN' 指定要读/写的 IO 端口,以及要读/写的指针来自。
  • 是的,端口映射 I/O 在这个时间点几乎是一个历史性的脚注。它通过添加另一个限制使用总线使处理器体系结构复杂化,并且不如内存映射 I/O 通用。我使用过几十种不同的微控制器,而 0x86 是我使用过的唯一具有端口映射 I/O 的处理器。如果您使用 PC 作为嵌入式平台,您可能需要使用它。
【解决方案4】:

想象一下您的嵌入式控制器处于关闭的电路中...

  1. 施加 Vcc 电源,复位电路置位 reset 信号。

  2. 时钟已达到运行速度且电压稳定,因此reset 被取消断言。

  3. 现在您的控制器将其指令指针设置为“复位向量”,即此特定芯片上的物理地址0xE0000000。控制器在该位置获取指令。

  4. 中断被禁用,首要任务是初始化栈指针等寄存器。在某些芯片上,有一些标志位(例如,x86 方向标志)需要清除或设置。

  5. 一旦正确设置了寄存器和标志位,就可以运行中断服务程序。到现在为止,我们必须将代码运行到大约位置0xE0000072,当我们到达通过首先将一些GPIO引脚切换到外部中断控制器来启用中断的代码时,然后启用CPU中断掩码。

  6. 此时,相当于“设备驱动程序”以中断服务程序的形式运行。假设 C 环境有一个库与这些例程的数据结构的接口相匹配,现在我们的引导加载程序代码可以跳转到某些 C 目标代码的main() 函数。

换句话说,将我们从上电带到main() 并处理低级I/O 的代码是用您选择的芯片特有的汇编程序编写的。这意味着,如果你想在嵌入式编程方面多才多艺,你必须知道如何从复位向量开始实现汇编代码。

现实情况是,嵌入式编程爱好者没有时间来实现所有 ISR 和引导加载程序代码。出于这个原因,许多人使用可用于特定芯片的标准软件框架。其他人使用自定义语言芯片,例如 BASICstamp。 BASICstamp 是一个嵌入式芯片,它承载了一个板载的 BASIC 语言解释器。口译员和所有 ISR 都是为您预先编写的。 BASIC 环境使您能够控制 I/O 引脚、读取电压以及您可以通过嵌入式控制器进行组装的所有操作,但速度会慢一些。

【讨论】:

    【解决方案5】:

    至于语言,C 可能是最重要的语言。从 Java 你应该能够适应,但请记住,很多高级 Java 对你来说是不可用的。那里有很多教科书,但我推荐 Kernighan 和 Ritchie http://en.wikipedia.org/wiki/The_C_Programming_Language_(book)

    的原始 C 编程书籍

    如需深入了解嵌入式 C,您可以阅读 Michael J Pont 的书:

    http://www.amazon.com/Embedded-C-Michael-J-Pont/dp/020179523X

    至于你可以从 Microchip 开始的嵌入式方面,IDE 可以使用合理的模拟器进行开发,并且 c 编译器对于稍微有限的学生版 c18 和 c30 编译器是免费的,IDE 安装程序也将询问您是否要安装可以使用的第 3 方 HI-TECH C 编译器。至于处理器,我建议选择标准的 18 系列 PIC,例如 PIC18F4520。

    http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=1406&dDocName=en019469&part=SW007002

    无论是哪个芯片制造商,您都必须了解数据表。您不必一次全部学习,但需要掌握!

    嵌入式,像大多数编程一样,倾向于围绕:

    1) 初始化资源,在这种情况下,数据不是来自数据存储,而是来自计算机寄存器。只需包含处理器头文件 (.h),它将允许您以端口(通常是字节)或引脚(位)的形式访问它们。微处理器在芯片上也带有有用的资源,例如定时器、模数转换器 (ADC) 和串行通信系统 (UART)。请记住,芯片本身是一种资源,需要先初始化。

    2) 使用资源。 C将允许您使数据尽可能全局化,并且每次都可以访问所有内容!避免这种诱惑,并像 Java 鼓励您那样保持模块化(尽管为了速度,您可能需要在这些规则上放宽一点)。

    但他们确实有一种额外的武器,称为中断,可用于提供实时行为。这些可以被认为有点像 OnClick() 事件。中断可以由外部事件(例如按钮或从另一个设备接收字节)和内部事件(定时器、传输完成、ADC 转换完成)​​产生。保持中断服务例程 (ISR) 简短而实用,使用它们来处理实时事件(例如,接收接收到的字节并将其存储在缓冲区中然后引发标志)但允许后台代码处理它(例如检查接收到的字节标志,如果设置则读取接收到的字节)。并记住 ISR 例程和后台例程使用的变量的所有重要 volatile

    无论如何,请仔细阅读,我推荐 www.ganssle.com 以获取一般建议。

    祝你好运!

    【讨论】:

      【解决方案6】:
      1. 嵌入式计算的范围已经变得非常广泛,因此答案在某种程度上取决于您所针对的设备类型。一方面,有只有几 KB 内存的 8 位控制器,通常完全用汇编或 C 语言编程。另一方面,诸如路由器中的处理器相当强大(200 MHz 和几 MB 的 RAM并不少见)并且经常运行像 Linux 这样的操作系统,这意味着您可以使用几乎任何语言,尽管 C 和 Java 是最常见的。

      2. 最好买个真芯片做实验。所涉及的大部分工作通常是了解设备以及如何与其交互,因此使用模拟器会达不到目的。

      【讨论】:

        【解决方案7】:

        有什么好的语言可以让我了解嵌入式,而不需要花费太多时间来学习嵌入式特定语言?

        正如每个人都会建议的那样:C. 现在,根据您对所选平台的深入研究,您可能还需要一些组装,但不要害怕:通常您只会使用一点点.

        如果你正在学习 C,我个人的建议是:像在汇编中那样工作;编程语言不会给您太多抽象,因此请考虑内存管理。当你学会了如何去做时,你就会走向抽象并快乐地生活。

        C++ 在嵌入式平台上也很流行,但恕我直言,除非您非常了解如何使用 C 进行编程,否则您也可以理解其抽象的底层内容。

        当您对 C/C++ 充满信心时,您可能会开始对嵌入式操作系统感到困惑。您会注意到它们可能与您选择的操作系统完全不同(例如,并非所有操作系统都有C standard library、进程以及用户空间和内核空间之间的拆分)。

        您将学习如何构建交叉编译器、如何弄乱链接器脚本、二进制格式的技巧以及许多很酷的东西。

        从理论的角度来看,也有很多东西:如果你学习计算机科学,你可以获得嵌入式系统的硕士学位。

        可以通过模拟器等不用购买芯片等学习吗?

        是的:很多操作系统都可以在模拟器上运行,比如qemu

        有人可以推荐一个简化的路线图来说明如何获得安全吗?我有点不确定从哪里开始。

        尝试获得一个可以在模拟器上运行的简单操作系统,破解它并追随你的好奇心。不要害怕弄乱复杂的代码。

        【讨论】:

          【解决方案8】:

          1) 大多数情况下,通常是低端嵌入式系统,您需要了解 C。

          我仍然建议您购买一个 vanilla 开发板,以熟悉使用嵌入式系统的工作流程和棘手的部分,例如调试和交叉编译。如果你只依赖模拟器,你会遇到麻烦。

          你可以试试 The Linux Stamp,它不贵,适合初学者,但你需要一些 Linux 的先验知识。

          2) 对于高端嵌入式系统,一个很好的例子是 HTC 的智能手机(CPU 速度可以达到 1Ghz)或其他一些运行速度很快的 Android 手机,您甚至可以在其上编写 Java。

          【讨论】:

            【解决方案9】:
            • C 和特定于您的芯片的程序集。

            • 不,你真的需要一个真正的芯片。模拟器不是真的。您需要能够处理按键抖动、电压异常等问题。

            • Arduino 是嵌入式爱好者的当前时尚。就个人而言,我不是哈佛建筑的忠实粉丝。但是您会发现 oodles 的帮助。我在我的论文工作中使用 XCore,我发现编写多核东西非常容易。我建议从 AVR32 开始并从那里开始。

            【讨论】:

            • 出于性能原因,大多数现代处理器都是冯诺依曼和哈佛架构的混合体。数据缓存、指令缓存概念本质上是一种哈佛架构。外部模型是冯诺依曼,数据和指令都驻留在统一的内存映射中。然而,在没有 MMU 的小型嵌入式系统上,为了安全起见,将它们分开可能是有利的。在哈佛架构中,您不会像在冯诺依曼上那样意外踩到程序内存。
            • @NoMoreZealots:我很熟悉哈佛的论点。但是,出于各种原因,我一直想编辑程序存储器。如果不同的银行有不同的步幅大小,Plus 指针会变得非常棘手。
            • 冯诺依曼和哈佛都有一席之地。然而,通常情况下,在真正的嵌入式系统中,您可能不应该接触程序 RAM。触摸我所拥有的程序 ram 的主要原因是验证它在连续自检过程中没有被损坏。 (其实是基于对辐射的恐惧。)你有什么理由编辑程序RAM?
            • @NoMoreZealots:编写加载器、调试器......
            • XCore 没有 JTAG 调试器?我知道我从某个地方重新认识了这个名字,它们基于 90 年代的旧 Transputer 设计。用于大规模并行。我认为架构处于最佳状态时,您可以不断为其提供新的东西来做,因此动态加载器是必不可少的。 (不过,我会说硬件和 DMA 比软件做得更好。为什么要浪费处理器周期?)随着新行业对多核设计的关注,也许他们会在阳光下实现这一目标。
            【解决方案10】:

            正如其他人所说,您需要了解 C。

            看一看 AVR 蝶阀,寻找便宜的开发板。

            Smileymicros 有一个带有开发板和书籍的简单套件: http://www.smileymicros.com/index.php?module=pagemaster&PAGE_user_op=view_page&PAGE_id=41

            【讨论】:

              【解决方案11】:

              即将发货的Raspberry Pi 板看起来是进入该领域的一种非常便宜的方式。

              【讨论】:

                【解决方案12】:

                是的,Arduino 将是要走的路。同意.. 便宜(大约 20 美元开始)并且有很棒的 AP​​I 可以开始使用高级功能。 C是必须的,但不能避免。但如果你能用其他语言编程,那你就很好了。

                我的建议是从http://www.sparkfun.com 开始购物,这里有很多可供参考的示例以及购买哪些设备的有用提示。

                【讨论】:

                • 如果想学习嵌入式开发,最好不要使用 Ardunio API。但是,它们可以通过大量有趣的演示提供一种快速解决应用程序问题的方法,并且您可以将 arduino 草图和准系统程序交替下载到同一块板上。
                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2022-12-16
                • 2012-11-27
                • 2013-08-10
                • 2012-05-22
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多