用Java開發下一代嵌入式產品
在我10年的Java佈道師生涯裏,沒有哪次Java新版本發佈能讓我如此興奮。Java 8的發佈不僅在語言本身加入了些不錯的新特性,還在嵌入式開發上加入了很棒的功能,進行了優化,還有簡潔的開發文檔。如果你是一名Java程序員,並且準備好和我一同加入機器間技術的潮流,或者說開發下一代改變世界的設備,那麼就讓我們開始學習物聯網(IoT)把。
在你開始嵌入式開發之前,你需要知道你具體想要開發出什麼,以及你打算在哪運行你的程序。這十分重要,因爲得根據目的選擇不同版本的Embedded Java。
如果你想要開發跟桌面應用相似的應用,或者你想要開發出優美的UI,那麼你需要選擇從Java SE衍生出來的Oracle Java SE Embedded版本。它支持同Java SE一樣的平臺和功能。此外,它還提供了其它特性,兼容更多平臺,小巧的Java運行環境(JREs),支持headless模式配置,以及內存優化。
如果你想要更方便地連接如開關、傳感器、馬達之類的外設,Oracle Java ME Embedded將是你最好的選擇。它具有設備訪問API,爲嵌入式平臺最常見的外設提供了接口:通用輸入/輸出(GPIO)、集成電路總線(IIC)、串行外設接口總線(SPI)、模數轉換器(ADC)、數模轉換器(DAC)、通用異步收發傳輸器(UART)、內存映射輸入輸出(MMIO)、AT命令設備、看門狗定時器、脈衝計數器、脈衝寬度調製器(PWM)和通用設備。
至於設備,Embedded Java覆蓋了大部分的平臺,從傳統的Java SE桌面平臺與服務器平臺到基於STM微處理器的STM32F4DISCOVERY板、樹莓派和windows平臺。在這篇文章中,我將使用樹莓派,不僅僅是因爲它是十分強大,且只有卡片大小的計算機,還因爲它價格便宜。最新版只要35美元。
準備樹莓派
樹莓派需要一張存有Linux鏡像的SD卡才能開機。因爲樹莓派沒有硬盤,SD卡就被用來存儲運行所需的Linux鏡像。該SD卡也被當作存儲設備用於加載其它的應用程序。
配置SD卡請按以下步驟操作:
- 格式化SD卡。
- 下載Raspbian(一個專爲樹莓派優化的基於Debian的免費操作系統)。
- 創建一個可引導的鏡像。使用像Win32 Disk Imager這樣的應用可以更方便地創建鏡像。
當你準備好SD卡之後,樹莓派就可以開機了。第一次開機時,樹莓派會加載軟件配置工具讓你進行基本的設置。以下是此時應該注意的選項:
- 勾選“擴展文件系統(Expand Filesystem)”選項,使操作系統對整個SD存儲具有權限。
- 選擇“國際化(Internationalisation)”選項中選擇與當地對應的語言與區域。
- 在主菜單選擇“高級(Advanced)”選項,通過開啓SSH將樹莓派設置爲headless嵌入式設備模式(沒有顯示器)。
- 設置靜態IP地址,確保樹莓派總以相同的IP地址接入。雖然這不是必須的,但我發現在樹莓派headless模式下總是很有用。設置靜態IP需要編輯/etc/network/interfaces文件如下圖:
(圖1)
現在你已經準備好了連接樹莓派,你可以選擇使用[PuTTY](http://www.putty.org/)連接。如下圖:
(圖2)
在樹莓派上安裝Embedded Java
現在是時候決定你打算在你的設備上運行什麼樣的應用了。我個人喜歡搞外設,所以在這篇文章中我將使用Oracle Java ME Embedded,這樣我才能使用設備訪問API。但是你也可以用Oracle Java SE Embedded來開發樹莓派應用。
在樹莓派上安裝Oracle Java ME Embedded二進制文件十分簡單,只需要通過SSH連接用FTP協議把樹莓派版本的zip壓縮文件從桌面傳輸到樹莓派,然後再解壓到一個新目錄就好了。
集成開發環境
使用Java ME SDK和NetBeans IDE是創建嵌入式應用不錯的選擇。這兩者結合就能在設備上運行之前先在虛擬機中進行測試,並且能夠自動地將代碼傳輸到樹莓派運行,甚至能在運行時調試。你所需要做的只是確保Java ME SDK是IDE的Java平臺的一部分。你需要在 工具->Java平臺 點擊“添加平臺”的選項,然後選擇SDK的路徑。
爲了能夠遠程管理樹莓派上的嵌入式應用,你需要運行應用管理系統(AMS)。通過SSH,運行以下代碼:
pi@raspberrypi sudo
javame8ea/bin/usertest.sh
第一個嵌入式應用
Oracle Java ME Embedded應用與Java ME應用看起來完全一樣,就如下例:
你的應用必須繼承MIDlet類,並且重寫兩個生命週期方法:startApp和destroyApp。這兩個方法分別在應用啓動時和快結束前被調用。以上代碼能在控制檯輸出信息。
打開LED燈
現在讓我們做些更有趣的事,比如通過開關來實現開啓和關閉LED燈。首先讓我們看下樹莓派的通用外設輸入輸出(GPIO)管腳。
(圖3)
通用外設輸入輸出連接器(GPIO connector)上有許多不同的連接類型管腳:
– 通用外設輸入輸出管腳(GPIO)
– 集成電路總線管腳(IIC)
– 串行外設接口管腳(SPI)
– RxTx串口管腳
這意味着我們有好幾個選擇可以連接LED和開關,以上任何一個GPIO管腳都可以,只要記住管腳數字和外設ID,因爲你需要這些信息才能用代碼指向這些設備。
現在按照下圖焊接電路。注意我們將LED連接到16管腳(GPIO 23),把開關連接到11管腳(GPIO 17)。同時加上 兩個電阻以保證電壓在安全範圍之內。
(圖4)
現在讓我們看下程序。設備訪問API中的PeripheralManager類能夠讓你用外設ID連接到任何類型的外設,這能夠極大地簡化代碼。比如要連接LED,只需要用靜態方法open,提供管腳ID 23如下代碼:
要改變LED的值(即開關函數)只要用setValue方法傳入相應參數:
這實在不能再簡單了。
我們能用PeripheralManager中同樣的open方法來連接開關,但我們將用稍微不同的方法來設置一些配置信息。首先,創建GPIOPinConfig對象(代碼3),其中包含了如下信息:
外設名稱
– 管腳號 – 傳輸方向:輸入、輸出還是雙向 – 模式:上拉、下拉還是開漏 – 觸發器:無觸發、下降沿觸發、上升沿觸發還是雙邊沿觸發,高電平觸發、低電平觸發還是雙電平觸發 – 初始值
接着我們用該配置對象調用open方法,如下:
我們也可以給管腳添加監聽器,這樣管腳值一旦發生改變,我們就能夠知道。在這個例子中,我們想要知道什麼時候開關的值發生了改變,這樣我們就能相應的改變LED的值:
button1.setInputListener(this);
然後實現valueChanged方法,當監聽器事件發生時就調用該方法。
在結束時關閉管腳是十分重要的,同時還要保證關掉了LED。
整個類的代碼可以在鏈接找到。
現在,我們剩下的只有MIDlet來啓用我們的代碼了。代碼7中的startApp方法會生成一個對象來控制我們的兩個通用輸入輸出設備(LED和開關),並且監聽我們的輸入。stopApp方法則保證所有東西都被正確地關閉。
感知環境
做到LED和開關已經十分不錯,但感知周圍環境纔是真正有意思的。在下面的例子中,我將演示如何着手使用IIC協議的傳感器。
IIC設備可能是最常見的設備,它們最大的有點是設計簡單。IIC只有兩條雙向的開漏線:串行數據線(SDA)和串行時鐘線(SCL)。
總線上的設備都會有一個特殊的地址。主控制器通過在串行數據線上發出開始請求和設備地址建立通訊連接。如果對應地址的設備空閒,則返回請求。然後數據就在串行數據線上傳輸,用串行時鐘線來控制每一比特的時間。
一旦通訊結束,控制器就發出停止請求。這樣的協議使得在兩條總線上得以增加多個設備。
啓動樹莓派的集成電路總線
如果你查看樹莓派的管腳圖(圖3),你會發現兩個IIC管腳:管腳3是數據總線,管腳5是時鐘總線。IIC默認未開啓,所以我們需要採取以下步驟才能讓我們的應用使用總線。
首先,用終端連接樹莓派,然後在/etc/modules文件增加一下兩行:
i2c-bcm2708
i2c-dev
i2c-tools包十分有用,它能夠檢測設備,保證一切正常運轉。可以通過以下命令安裝:
sudo apt-get install python-smbus
sudo apt-get install i2c-tools
最後,樹莓派中有個黑名單文件/etc/modprobe.d/raspi-blacklist.conf,默認情況下SPI和IIC都在該名單中。這意味着除非我們移除它們或者把他們設爲註釋,IIC和SPI在樹莓派上是不能用的。編輯該文件去除以下兩行:
blacklist spi-bcm2708
blacklist i2c-bcm2708
重啓樹莓派,確保應用所有的修改。
添加傳感器
Bosch Sensortec的BMP180傳感器是測量大氣壓和氣溫的經濟解決方案。由於氣壓隨着海拔高度改變,你也可以把它當作海拔高度測量儀。BMP180使用IIC協議,工作電壓爲3V到5V,十分適合連接到樹莓派。
按照以下的圖5把BMP180焊接到樹莓派上。通常情況下,使用IIC設備時需要需要在串行數據線和串行時鐘線加上一個上拉電阻。幸運的是,樹莓派支持上拉電阻,所以你只需要把它們連接在一起。
(圖5)
在你把傳感器連接到樹莓派之後,就可以檢查是否能看到IIC設備了。在樹莓派上運行以下命令:
sudo i2cdetect -y 1
你應該能在表格中看到設備。圖6中顯示了兩個IIC設備:一個在地址40,另一個在地址70。
使用IIC設備來獲取溫度 在你編程連接IIC設備之前有一些必須知道的事項:
- 設備地址是多少?IIC使用7位作爲設備地址,樹莓派使用IIC總線1。
- 寄存器的地址是多少?在我們的例子中,我們將讀取溫度值,而相應寄存器地址是0xF6。(針對BMP180)
- 是否需要設置控制寄存器來啓動傳感器?某些設備默認處於睡眠狀態,除非我們啓動它,否則它是不會監測任何數據的。此處設備的控制寄存器地址是0xF4。(針對BMP180)
- 設備的時鐘頻率是多少?BMP180頻率爲3.4Mhz。
代碼8將BMP180的這些參數設置爲靜態變量供之後的代碼使用:
編程連接設備依然是使用PeripheralManager類的靜態方法open。該處我們將針對IIC設備創建一個I2CDeviceConfig對象(代碼9)。該對象能讓我們設定設備的總線,地址,地址位數(比特單位)和時鐘速度。
要讀取溫度,我們需要採取以下步驟:
- 按代碼10a和代碼10b從設備讀取校準數據。該步只針對BMP180傳感器,使用其它溫度傳感器時不一定需要這一步。
2.寫入到設備上的一個控制寄存器,初始化溫度傳感器(代碼11)。
3.讀取未補償溫度爲兩個字節的變量,用校準常量得出真實的溫度。代碼如下(依然針對BMP180)
最後,攝氏度爲單位的溫度數據就被保存在了celsius變量中。你可以在鏈接找到整個程序。
作爲練習,你也可以把該程序擴展到讀取壓力、海拔或者兩者。
總結:
我們通過演示如何使用GPIO和IIC設備的真實案例學習瞭如何創建Java嵌入式應用。現在是時候輪到你自己在樹莓派上連接更多設備了,希望你喜歡樹莓派嵌入式Java開發。