Raspberry Pi 上的 Java® SE Embedded 入门

作者:Bill Courington 和 Gary Collins

2012 年 8 月发布

如何在一小时内让 Linux 和 Java SE Embedded 在 Raspberry Pi 上运行

它只有信用卡大小,价格约等于一本 Java 编程书。

它就是 Raspberry Pi 计算机,可以支持适用于无头嵌入式应用程序的完整 Java SE 运行时。本文带您了解 Raspberry Pi 上的 Java 编程,包括以下主题:

注:此处所给出的说明可以有多种变化,特别是在主机(台式或便携式)计算机上执行的操作,以及在 Raspberry Pi 上执行的操作。请根据您的知识和喜好(可能还包括可选的 Linux 调优和调整一节中的某些主题)创建适合自己的工作流。

Raspberry Pi

Raspberry Pi 是一款小型、低功耗的主板,采用 700mHz ARMv6 CPU,在单一芯片上集成了硬件浮点和图形处理器。图形处理器和 CPU 共享 256MB RAM。提供了 USB、以太网、高清图形、音频、SD 卡以及通用 I/O 接口。图 1 显示的 Raspberry Pi B 型插入了 SD 卡进行扩展。SD 卡有着特殊的作用:Raspberry Pi 将从 SD 卡启动。本文主要介绍如何创建和修改可启动的 SD 卡上的文件。

 

图 1. Raspberry Pi B 型

图 1. Raspberry Pi B 型

可以通过 USB 键盘和鼠标以及 HDMI 监视器或电视(最高 1080p)与 Raspberry Pi 交互。该板上的以太网连接提供了另一种选择:通过 ssh 从联网主机交互。本文的可选的 Linux 调优和调整一节介绍如何启用 ssh 登录。

前提条件

要设置 Raspberry Pi B 型使其运行 Java SE Embedded,您需要:

  • 有线网络,让您可以通过以太网电缆连接 Raspberry Pi。网络必须提供 DHCP IP 地址。
  • Linux 主机,与 Raspberry Pi 位于相同的有线以太网网络。您可以在 Windows 或 Mac 主机上执行相应的操作,但细节不尽相同,本文不再赘述。您需要主机的 root 密码。在主机上,您还需要:
    • 从网站下载文件的办法,如 Web 浏览器或 wget 实用程序。
    • 磁盘分区工具。在本文中,我们使用简单、有效的 GParted。如果没有 GParted,可以自行获取并在主机上安装,如下所示:
      $ sudo apt-get install gparted
    • Web 浏览器和电子邮件客户端,用于从 Oracle 下载 Java SE Embedded
    • SD 卡读写器。如果主机在虚拟机中运行 Linux,请确保它可以读写 SD 卡。
  • 监视器,可以直接连接或通过适配器连接到 Raspberry Pi 的 HDMI 端口。
  • USB 键盘和鼠标,通过有源 USB 集线器连接到 Raspberry Pi。
  • SD 卡,用于存放 Raspberry Pi 的操作系统和 Java 运行时。一张 4GB 卡,足以容纳 Linux、Java SE Embedded 和大多数嵌入式应用程序。

    注:并非所有 SD 卡都与 Raspberry Pi 兼容。高速卡可能超出 Raspberry Pi 总线容许的速度极限。我们成功使用了 Transcend 4GB Micro 和 Patriot 4GB 4 类卡。http://elinux.org/RPi_VerifiedPeripherals#SD_cards 列出了适用和不适用 Raspberry Pi 用户的卡。
  • 5V DC Micro USB 电源,700mA 以上都可以。根据 Raspberry Pi 网站上的信息,请勿使用 USB 集线器或计算机作为电源。

必需的 Linux 安装

通电时,Raspberry Pi 固件从 SD 卡槽启动。Java SE Embedded 在 Linux 上运行,因此首先要在 SD 卡上安装 Linux。

下载适合 Raspberry Pi 的 Debian Squeeze Linux 映像

注:这些说明适用于 Debian Squeeze。其他适用于 Raspberry Pi 的 Linux 实现也可以使用,但必须 针对 ARM 芯片的软件浮点计算进行了构建。Raspberry Pi 网站上链接的映像可能已针对硬件浮点计算进行了构建;不适用于 Java SE for Embedded。

可以在此处找到适用于 Raspberry Pi 的压缩 Debian Squeeze 映像:http://elinux.org/RPi_Distributions#Debian_ARM。文件大小约 450MB。以下说明假定已下载到新目录 ~/RaspberryPi/。要验证下载的文件,请遵循下载开始时显示的页面上的 SHA-1 校验和说明。

按如下所示解压缩映像:

$ cd ~/RaspberryPi
$ unzip *.zip 

解压缩过程创建一个名称类似 debian6-19-04-2012 的子目录。

将 Debian Squeeze 映像复制到 SD 卡

在主机上找出 SD 卡设备句柄,如下所示(如果您愿意,也可以采用其他方式):

  • 在 Linux 终端窗口中,运行 dmesg | tail,这将显示与设备挂载有关的消息。我们只对消息的末尾部分感兴趣。
  • 将 SD 卡插入读写器。
  • 在另一个终端窗口中,再次运行 dmesg | tail。与第一个窗口相比,此窗口多出一些与新挂载的 SD 卡有关的行。具体细节可能不尽相同,但应如下所示:

    [ 110.084625] sdb:detected capacity change from 0 to 3963617280
    [ 118.055249] sd 2:0:0:0:[sdb] 7741440 512-byte logical blocks:(3.96 GB/3.69 GiB)
    [ 118.059409] sd 2:0:0:0:[sdb] Assuming drive cache:write through
    [ 118.064547] sd 2:0:0:0:[sdb] Assuming drive cache:write through
    [ 118.066015] sdb:sdb1

    线索是 sdb,它表示设备句柄为 /dev/sdbsdb1 指示例卡的单个分区。您的卡可能有多个分区。

在以下说明中,假定 SD 卡设备句柄为 /dev/sdb,它只有一个分区:sdb1。如果需要,可根据您的环境调整说明。

  • 卸载 SD 卡分区:

    $ sudo umount /dev/sdb1
  • 使用 dd 将 Debian 映像复制到 SD 卡。
    注:在以下命令中,确保 正确输入 of(输出文件)参数值。您将调用低级磁盘复制,这将覆盖所有数据。指定错误的设备会破坏数据。

    $ cd ~/RaspberryPi/debian6-19-04-2012
    $ sudo dd if=yourDebian.img of=/dev/sdb bs=1M
    1859+1 records in
    1859+1 records out
    1950000000 bytes (2.0 GB) copied, 212.344 s, 9.2MB/s


    dd 到 SD 卡是一个缓慢的操作。4GB 4 类卡可能需要 5-10 分钟。dd 不提供进度指示,因此请耐心等待它慢慢完成工作。

如果现在想确定 SD 卡 Linux 已起作用,请跳到首次启动一节,然后返回调整 SD 卡分区大小

调整 SD 卡分区大小

SD 卡现在包含三个分区和未分配空间。现在我们将未分配空间添加到 Linux 文件系统,为 Java SE Embedded 和应用程序提供更多空间。为了向文件系统分配未分配空间,我们修改 SD 卡上的分区,删除并重新创建一个分区,然后调整另一个分区的大小。

  • 启动 GParted:

    $ sudo gparted
    Gparted 首先显示主机磁盘的分区。您 希望更改这些分区。
  • 选择 GParted -> Devices 显示 /dev/sdb 上的分区和未分配空间:

    图 2. 初始 SD 卡分区

    图 2. 初始 SD 卡分区

三个分区分别是:

  • /dev/sdb1:引导分区
  • /dev/sdb2:Linux 根文件系统。它分配的 1.5GB 空间大部分已使用。
  • /dev/sdb3:Linux 交换区。

大约一半的卡空间未分配。最大一块可用空间跟在 /dev/sdb3 分区后面。为了将此空间添加到 /dev/sdb2(文件系统),我们临时删除 /dev/sdb3,扩展 /dev/sdb2,然后重新创建 /dev/sdb3

  • 在 Partition 列中,选择 /dev/sdb3(linux 交换区),右键单击并选择 Delete。分区显示为已删除,但是 GParted 将此操作加入队列中,稍后运行。

    图 2. 将 Delete 操作加入队列后的 SD 卡分区

    图 3. 将 Delete 操作加入队列后的 SD 卡分区

  • 在 Partition 列中,选择 /dev/sdb2(Linux 文件系统),右键单击并选择 Resize/Move。在出现的对话框中,拖动右箭头,直至 Free space following 约为 512(或者您希望留作交换分区的空间大小)。您可能无法准确地拖到 512,但这并不重要。

    图 4. 512MB 用作交换分区

    图 4. 512MB 用作交换分区

  • 单击 Resize/Move 将更改加入队列。在出现的 Moving a partition 警告对话框中,单击 OK。
  • 现在文件系统分区已经增大,我们重新创建一个交换分区。选择 512MB 未分配分区,右键单击并选择 New。
  • 在 Create new Partition 对话框中,在 File system 下拉列表中选择 linux-swap。

    图 5. 新的交换分区

    图 5. 新的交换分区

  • 单击 Add。
  • 在 GParted 主窗口中,选择 Edit > Apply All Operations,这将执行排队的操作。在 Are you sure 对话框中,单击 Apply。重新分区是另一个耗时的操作,动辄运行数分钟。将出现一个对话框显示进度。完成后单击 Close。
    新的分区图如下所示:

    图 6. 新的分区图

    图 6. 新的分区图

  • 退出 GParted,弹出 SD 卡,以便尝试首次启动。

首次启动

注:针对这些步骤,以下组件必须连接到 Raspberry Pi:监视器、键盘以及确知有效的以太网电缆。

  • 断开 Raspberry Pi 电源,将 Linux SD 卡插入插槽,然后接通电源。数秒钟后,监视器上应显示启动进度消息。如果未出现,可能是 SD 卡类型错误或格式不正确。

    首次启动过程中出现错误消息很正常,因为有些服务尚未配置。首次启动还可能看似挂起,等待端口映射关闭。正如控制台消息所指示的,可以任其运行(通常需要数分钟),也可以断开 Raspberry Pi 电源,还可以选择重新启动。后续启动相对较快。
  • 收到登录提示后,使用 Raspberry Pi 用户名和密码登录。撰写本文时,用户名和密码分别为“pi”和“raspberry”。
    注:不兼容的键盘可能会妨碍登录,例如,因为重复字符。如果无法登录,可尝试其他键盘。
    如果使用“pi”和“raspberry”不能登录,请咨询 Linux 发行网站。
  • 获取并记录 Raspberry Pi 的 IP 地址,如下所示:
    $ sudo /etc/rc.local
    RaspberryIP
     
  • 使用以下命令允许 ssh 登录:
    $ sudo update-rc.d -f ssh defaults 20
     
  • 重新启动以实际启用 ssh 登录:
    $ sudo sync; sudo shutdown -r now
    如果关闭耗时过长,可以关闭 Raspberry Pi 电源,然后再打开。

现在,我们可以通过网络从主机读写 Raspberry Pi SD 卡。

Java SE Embedded 安装

在本节中,我们使用主机下载 Java SE Embedded,通过网络将其复制到 Raspberry Pi 的 Linux 文件系统。然后,还是通过远程方式解压缩下载文件并启动 Java。

获取 Java SE Embedded 评估版软件

  • 在主机的 Web 浏览器中,转到 http://www.oracle.com/technetwork/java/embedded/downloads/javase/index.html。网页细节在本文撰写后可能已改变。

    图 7. 第一个下载链接

    图 7. 第一个下载链接

  • 在 Java SE Embedded 7 列中,单击 EABI, VFP, SoftFB ABI, Little Endian。
    将出现一个调查页面。
  • 填写调查表,单击 Submit。将出现一个验证页面。
  • 检查验证页面,看是否正确(尤其是电子邮件地址),然后单击 Submit。
    不久,您的收件箱中将收到一封来自 JavaSE-Embedded-LinkNotify 的电子邮件。
  • 单击电子邮件中的链接。将出现另一个下载页面(有些细节可能在本文撰写之后发生更改):

    图 8. 第二个下载链接

    图 8. 第二个下载链接

  • 选择 Accept License Agreement,然后单击 ARMv6/7 Linux - Headless 行中的链接。

    注:本文撰写时,尚未在 Raspberry Pi 上测试 ARMv7 Linux - Headful 软件。ARMv7 Linux - Headless - Server Compiler 软件不能在 Raspberry Pi 上工作,因为它需要 ARM v7 芯片。
  • .gz 文件保存到 Downloads 目录。
     
  • 通过网络以 pi 用户身份登录 Raspberry Pi,创建一个用于下载 Java 的目录:
    $ ssh pi@RaspberryIP mkdir /home/pi/java
  • 将 Java 下载复制到 Raspberry Pi 上的新目录:
    $ scp ~/Downloads/*.gz pi@RaspberryIP:/home/pi/java
  • 解压缩 Java 下载文件:
    $ ssh pi@RaspberryIP
    $ cd /home/pi/java
    $ tar -zxvf *.gz
    ...
  • 启动 Java:
    $ ls ejre*
    ejre1.7.0_04
    $ cd ejre*
    $ ./bin/java -version
    java version "1.7.0_04-ea"
    Java(TM) SE Runtime Environment for Embedded (build 1.7.0_04-ea-b20, headless)
    Java Hotspot(TM) Embedded Client VM (build 23.0-b21, mixed mode)

    有些细节(如版本号和内部版本号)可能在本文撰写后发生更改。
  • 也可以删除下载文件:
    $ rm /home/pi/java/*.gz
     

可选的 Linux 调优和调整

本节中的命令可以让您的 Raspberry Pi 系统运行地可靠、响应更即时、更方便。根据自己的喜欢进行选择,然后在 Raspberry Pi 上运行。为了简化诊断问题,请在每次更改后重新启动。

在本节中:

设置静态 IP 地址

如果您的网络重用动态 IP 地址,您可以跳过更改静态 IP,因为 Raspberry Pi 的 IP 地址实际上将保持不变。如果每次启动时 Raspberry Pi 的动态 IP 地址可能不同,对于 ssh 来说,使用静态 IP 地址会更方便。在以下说明中,假定希望为 Raspberry Pi 分配主机名 raspberrypi

首先以超级用户身份在文本编辑器中打开 /etc/hosts(例如,sudo vi /etc/hosts)。为 Raspberry Pi 添加一行,包括网络中的有效静态 IP 地址、可选的域名以及别名。以下是一个假设示例,其中将 Raspberry Pi 指定为 raspberrypi

127.0.0.1 localhost?192.168.0.100	raspberrypi.yourDomain raspberrypi loghost 

保存文件,退出编辑器。

以超级用户身份在文本编辑器中打开 /etc/hostname。添加一行,如下所示:

raspberrypi

保存文件,退出编辑器。

以下说明可以防止过载网络中导致操作系统更改 Raspberry Pi 静态 IP 地址的问题。这一问题会使 ssh 或其他使用静态 IP 地址的操作停止工作。

发现以太网端口的硬件地址,如下所示。

首先,确定以太网控制器的名称(x 代表地址数字):

$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN
   link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
   inet 127.0.0.1/8 scope host lo
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1488 qdisc pfifo_fast state UNKNOWN qlen 1000
   link/ether b8:27:eb:b5:e8:90 brd ff:ff:ff:ff:ff:ff
   inet xx.xxx.xxx.xx/xx brd xx.xxx.xxx.xxx scope global eth0
在此例中,名称为 eth0。硬件地址是 link/ether 之后的十六进制数字,本例中为 b8:27:eb:b5:e8:90

得到以太网控制器的硬件地址之后,以超级用户身份在文本编辑器中打开 /etc/network/interfaces,并添加(替代网络详细信息)类似下面所示 # New entries 注释之后的内容。

# Used by ifup(8) and ifdown(8). See the interfaces(5) manpage or?
# /usr/share/doc/ifupdown/examples for more information.
auto lo
iface lo inet loopback
#
# New entries to support static IP follow: 

auto eth0
iface eth0 inet static
hwaddress ether b8:27:eb:b5:e8:90
address 192.168.0.100
network 192.168.0.0
netmask 255.255.255.0255.255.255.0
broadcast 192.168.0.255
gateway 192.168.0.1

启用交换和优化文件系统访问时间

默认情况下,Debian Linux 中禁用交换。如果操作超出 Raspberry Pi 的 256KB RAM 大小,系统就会崩溃。还有一种情况没这么严重,即默认情况下,文件系统要花时间维护每个文件的上次访问时间,这对嵌入式应用程序基本没有用处。维护上次访问时间还可能缩短 SD 卡的生命周期。这两种默认行为均在 /etc/fstab 文件中指定。

以超级用户身份在编辑器(如 vi)中打开 /etc/fstab。该文件如下所示:

proc            /proc           proc    defaults        0       0 
/dev/mmcblk0p1  /boot           vfat    defaults        0       0 
#/dev/mmcblk0p3  none            swap    sw              0       0 

要启用交换,请取消第三行的注释。

注:SD 卡上的交换很慢。对于嵌入式应用程序,您可能希望管理内存以避免出现此问题。

为避免维护上次访问信息产生的开销,请在 p1p3 之间插入一个 p2 挂载点。noatimenodiratime 选项可完成此任务。当文件如下面所示时,保存文件,退出编辑器:

proc            /proc           proc    defaults        0       0 
/dev/mmcblk0p1  /boot           vfat    defaults        0       0 
/dev/mmcblk0p2  /               auto    rw,noatime,nodiratime,errors=remount-ro 0 1
/dev/mmcblk0p3  none            swap    sw              0       0

现在,为交换空间分配 p3(在主机上创建的交换分区 /dev/sdb3):

$ sudo mkswap /dev/mmcblk0p3 

设置时区和语言环境

默认情况下,Raspberry Pi 配置为使用欧洲/伦敦时区和 en_GB_UTF-8 语言环境。要实现计算机本地化,请遵循以下说明。

要更改时区,请输入以下命令:

$ sudo dpkg-reconfigure tzdata 
将出现一个伪图形界面。

图 9. 时区用户界面

图 9. 时区用户界面

使用上下箭头键在地区和城市间移动选择光标。使用左右箭头键选择 <Ok> 或 <Cancel>。按 Return 输入选择。

按如下所示设置语言环境:

$ sudo dpkg-reconfigure -p low locales 

用户界面与设置时区的界面类似。

设置时间服务器

许多操作(包括软件包更新)依赖于正确的日期和时间。要自动设置日期和时间,请了解网络时间服务器的身份,然后运行以下命令:

$ sudo ntpdate yourNTPServer 
要在每次启动时设置时间,请以超级用户身份编辑 /etc/rc.local,并在脚本退出前添加以下代码行:
ntpdate yourNTPServer 

设置互联网代理

Ping 某个知名的互联网主机,如 www.lego.com。如果主机不响应,则确定网络是否位于代理后面,如有需要,还可根据网络约定设置环境变量 http_proxy,例如(假设):

$ sudo export http_proxy =’http:192.168.0.1:3128’

要在每次登录时设置代理,请在 ~/.bash_profile 中添加 export 命令,或等效命令(如果使用其他 shell)。

重新映射键盘

如果键盘键解释错误或者希望更改键盘布局,请使用以下命令:

$ sudo dpkg-reconfigure keyboard-configuration

用户界面类似于本文设置时区和语言环境一节中描述的内容。

更新 Debian 软件包

更新随 Debian 发布的软件包之前,以超级用户身份在文本编辑器中打开 /etc/apt/sources.list。此文件包含新/更新软件包的信息库位置。发行时,位置 URL 中含 ftp.uk。如果您不在英国,将这些条目更改为物理上离您更近的位置可以提高性能。例如,如果您在美国,可以将 ftp.uk 全局更改为 ftp.us。以下站点包含有关 Debian 信息库位置的信息:http://ftp.debian.org/debian/README.mirrors.html。

要更新已安装的软件包,请在验证 Raspberry Pi 可以连接到互联网连接之后,输入以下命令:

$ sudo apt-get update 
$ sudo apt-get upgrade 

如果收到消息,指示软件包列表中有重复项,则在编辑器中再次打开 /etc/apt/sources.list,注释掉其中一个重复的条目。通常最好保留包含信息较多的条目。

自动启动图形用户界面

如果希望窗口系统在您本地登录 Raspberry Pi 时自动启动,则需更改默认的运行级别,如下所示。以超级用户身份在文本编辑器中打开 /etc/inittab。找到以下条目:

# The default runlevel.	
id:2:initdefault:
将它更改为 5:
# The default runlevel.	
id:5:initdefault:
注:图形会使用大量 Raspberry Pi RAM,大约 90MB。

 

添加其他 Web 浏览器

如果使用默认 midori 浏览器遇到困难,可以尝试 iceweasel:

$ sudo apt-get update
$ sudo apt-get install iceweasel

启用声音

默认情况下,Raspberry Pi 声音输出不起作用。要想启用,以超级用户身份在文本编辑器中打开 /etc/modules。在文件末尾添加以下代码行:

snd_bcm2835 

保存并关闭文件。重新启动 Raspberry Pi 时就会启用声音。