AndroidThings
搭梯子訪問:https://developer.android.com/things/index.html
為了搶攻智能家電市場,Google 14 日推出全新物聯(lián)網(wǎng)平臺“Android Things”的開發(fā)者預(yù)
覽版本。未來不只是手機(jī),Android 可能將透過喇叭、監(jiān)視器和路由器等家電,占據(jù)家中每個(gè)
角落。
可用于打印機(jī)、門鎖、烤箱、燈泡、插座等
Android Things 的前身為在 2015 年 5 月發(fā)布的物聯(lián)網(wǎng)平臺 Brillo,不過至今并未受
到開發(fā)者大量采用。Google 強(qiáng)調(diào),新推出的 Android Things 除了承襲 Brillo 的功
能,還加入 Android 開發(fā)者熟悉的工具,包含 Android Studio、Android SDK、
Google Play 服務(wù)和 Google 云端平臺,提供整套打造 Android 智能聯(lián)網(wǎng)設(shè)備所需工具,
讓任何 Android 開發(fā)者都能輕松打造物聯(lián)網(wǎng)服務(wù)。
只要你有能力打造出 App,你就能打造出一個(gè)設(shè)備。──Google
硬件
現(xiàn)在支持以下3款硬件:
1)Intel Edison
2)NXP Pico
3)Raspberry Pi 3
我使用的是樹莓派3,拿到板子首先需要在安卓開發(fā)者網(wǎng)站下載預(yù)覽版鏡像。地址為:https://developer.android.com/things/preview/download.html
接下來將8G內(nèi)存以上的高速TF卡放入讀卡器,插入電腦,我使用的是OS X系統(tǒng),給樹莓派刷入
系統(tǒng)的步驟與Linux類似使用終端運(yùn)行以下命令:
dd bs=4m if=iot_rpi3.img of=/dev/disk2
其中iot_rpi3.img 表示系統(tǒng)鏡像所在的目錄,我的就在當(dāng)前目錄所以就直接寫文件名就OK
接著/dev/disk2是TF在文件系統(tǒng)上的位置。
稍等5分鐘左右,系統(tǒng)寫入完成,拔下讀卡器,將TF卡放入樹莓派上電開機(jī)。
Paste_Image.png
Paste_Image.png
第一印象
接入顯示器開機(jī),開機(jī)畫面后并沒有看到我們熟悉的安卓系統(tǒng)界面。而是在一個(gè)AndroidThings
的背景圖后顯示了已經(jīng)獲取的IP地址。對于AndroidThings來說顯示屏不是必須的,無顯示器
一樣可以工作,使用鼠標(biāo)試用了一下,界面不是很流暢。
值得一提的是系統(tǒng)開機(jī)后雖然并沒有可供操作的選項(xiàng),但是當(dāng)你編寫的帶UI的程序運(yùn)行到系統(tǒng)后
是有界面的,與普通app運(yùn)行基本沒有差別。
Paste_Image.png
使用IIC驅(qū)動(dòng)12864OLED屏幕
拿到板子不久又購買了一塊12864的OLED屏幕和一個(gè)DHT11溫濕度傳感器,然后對OLED屏幕開
始折騰。
要操作點(diǎn)陣顯示屏,也就是寫數(shù)據(jù)和寫命令!讓屏幕休眠、讓屏幕滾動(dòng)之類的操作,就要向屏幕
寫命令;要讓屏幕顯示內(nèi)容,就要寫數(shù)據(jù)。 怎樣讓屏幕知道你發(fā)送的東西是數(shù)據(jù)還是命令?有
的屏幕有類似D/C(Data/Command)這樣的引腳,說明是通過高低電平來區(qū)分,有的屏幕是向屏
幕寫入特定的值來區(qū)分。 點(diǎn)陣屏內(nèi)部都有一個(gè)驅(qū)動(dòng)芯片,這個(gè)驅(qū)動(dòng)芯片就負(fù)責(zé)按照程序的要
求,在某一個(gè)點(diǎn)來進(jìn)行操作。所謂的初始化就是這個(gè)驅(qū)動(dòng)芯片的初始化,初始化中注意兩個(gè)地
方:
一個(gè)是復(fù)位!這個(gè)非常重要,如果沒有完全復(fù)位,可能導(dǎo)致屏幕不穩(wěn)定、顯示亂碼等畸形問題!
另一個(gè)就是初始化代碼!這個(gè)初始化代碼一般都是一些16進(jìn)制數(shù),可以在顯示屏的規(guī)格書之類的文檔里面找到,可以通過“寫命令”的方式能夠把初始化代碼發(fā)送給顯示屏。
完成了這些步驟,就可以讓它顯示你想要的東西了!
上代碼
//以下代碼中不包括字碼,因?yàn)槲业钠聊槐旧聿粠ё謳欤孕枰密浖岽a得到,具體購買屏幕時(shí)一般會(huì)附帶提碼軟件
package com.donute.iot_android.utils;
import com.google.android.things.pio.I2cDevice;
import java.io.IOException;
/**
* Created by zhouyufei on 2017/1/16.
*/
public class OledUtil {
private I2cDevice device;
private static final int Brightness=0xCF;
public OledUtil(I2cDevice device) {
this.device = device;
initOled();
clearScreen();
}
public void initOled(){
oledCmd((byte)0xae);//--turn off oled panel
oledCmd((byte)0x00);//---set low column address
oledCmd((byte)0x10);//---set high column address
oledCmd((byte)0x40);//--set start line address Set Mapping RAM Display Start Line ((byte)0x00~(byte)0x3F)
oledCmd((byte)0x81);//--set contrast control register
oledCmd((byte) Brightness); // Set SEG Output Current Brightness
oledCmd((byte)0xa1);//--Set SEG/Column Mapping (byte)0xa0×óóò·′?? (byte)0xa1?y3£
oledCmd((byte)0xc8);//Set COM/Row Scan Direction (byte)0xc0é???·′?? (byte)0xc8?y3£
oledCmd((byte)0xa6);//--set normal display
oledCmd((byte)0xa8);//--set multiplex ratio(1 to 64)
oledCmd((byte)0x3f);//--1/64 duty
oledCmd((byte)0xd3);//-set display offset Shift Mapping RAM Counter ((byte)0x00~(byte)0x3F)
oledCmd((byte)0x00);//-not offset
oledCmd((byte)0xd5);//--set display clock divide ratio/oscillator frequency
oledCmd((byte)0x80);//--set divide ratio, Set Clock as 100 Frames/Sec
oledCmd((byte)0xd9);//--set pre-charge period
oledCmd((byte)0xf1);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
oledCmd((byte)0xda);//--set com pins hardware configuration
oledCmd((byte)0x12);
oledCmd((byte)0xdb);//--set vcomh
oledCmd((byte)0x40);//Set VCOM Deselect Level
oledCmd((byte)0x20);//-Set Page Addressing Mode ((byte)0x00/(byte)0x01/(byte)0x02)
oledCmd((byte)0x02);//
oledCmd((byte)0x8d);//--set Charge Pump enable/disable
oledCmd((byte)0x14);//--set((byte)0x10) disable
oledCmd((byte)0xa4);// Disable Entire Display On ((byte)0xa4/(byte)0xa5)
oledCmd((byte)0xa6);// Disable Inverse Display On ((byte)0xa6/a7)
oledCmd((byte)0xaf);//--turn on oled panel
}
private void oledCmd(int i) {
try {
device.writeRegByte(0x00,(byte)i);
} catch (IOException e) {
e.printStackTrace();
}
}
public void oledData(int data) {
try {
device.writeRegByte(0x40,(byte)(data));
} catch (IOException e) {
e.printStackTrace();
}
}
public void oledData(int[] data) {
try {
for (int i=0;i<data.length;i++){
device.writeRegByte(0x40,(byte)(data[i]));
}
} catch (IOException e) {
e.printStackTrace();
}
}
/***************功能描述:顯示6*8一組標(biāo)準(zhǔn)ASCII字符串 顯示的坐標(biāo)(x,y),y為頁范圍0~7****************/
public void oled6x8(int x,int y,char ch[])
{
int c=0,i=0,j=0;
for (int k=0;k<ch.length;k++){
c =ch[j]-32;
if(x>126){
x=0;
y++;
}
OLED_Set_Pos(x,y);
for(i=0;i<6;i++)
oledData(CodeTab.F6x8[c][i]);
x+=6;
j++;
}
}
/*******************功能描述:顯示8*16一組標(biāo)準(zhǔn)ASCII字符串 顯示的坐標(biāo)(x,y),y為頁范圍0~7****************/
public void oled8x16(int x,int y,char ch[])
{
int c=0,i=0,j=0;
for (int k=0;k<ch.length;k++){
c =ch[j]-32;
if(x>120){
x=0;
y++;
}
OLED_Set_Pos(x,y);
for(i=0;i<8;i++)
oledData(CodeTab.F8X16[c*16+i]);
OLED_Set_Pos(x,y+1);
for(i=0;i<8;i++)
oledData(CodeTab.F8X16[c*16+i+8]);
x+=8;
j++;
}
}
/*****************功能描述:顯示16*16點(diǎn)陣 顯示的坐標(biāo)(x,y),y為頁范圍0~7****************************/
public void oled16x16(int x,int y,int N,int[] codeTab)
{
char wm=0;
int adder=32*N;
OLED_Set_Pos(x , y);
for(wm = 0;wm < 16;wm++)
{
oledData(codeTab[adder]);
adder += 1;
}
OLED_Set_Pos(x,y + 1);
for(wm = 0;wm < 16;wm++)
{
oledData(codeTab[adder]);
adder += 1;
}
}
/***********功能描述:顯示顯示BMP圖片128×64起始點(diǎn)坐標(biāo)(x,y),x的范圍0~127,y為頁的范圍0~7*****************/
public void drawBmp(int x0,int y0,int x1,int y1,char BMP[])
{
int j=0;
int x,y;
if(y1%8==0)
y=y1/8;
else
y=y1/8+1;
for(y=y0;y<y1;y++)
{
OLED_Set_Pos(x0,y);
for(x=x0;x<x1;x++)
{
oledData(BMP[j++]);
}
}
}
/*********************OLED 設(shè)置坐標(biāo)************************************/
public void OLED_Set_Pos(int x, int y)
{
oledCmd(0xb0+y);
oledCmd(((x&0xf0)>>4)|0x10);
oledCmd((x&0x0f)|0x01);
}
/*****************************清除屏幕顯示內(nèi)容************************************/
public void clearScreen(){
int y,x;
for(y=0;y<8;y++)
{
oledCmd((byte) (0xb0+y));
oledCmd((byte) 0x01);
oledCmd((byte) 0x10);
for(x=0;x<128;x++){
int[] b={0};
oledData(b);
}
}
}
}
Paste_Image.png
Paste_Image.png
使用GPIO驅(qū)動(dòng)DHT11
因?yàn)橹坝惺褂肎PIO驅(qū)動(dòng)繼電器工作的經(jīng)歷,繼電器接在3.3V正常工作,接在5V下無法驅(qū)動(dòng)。
在嘗試了驅(qū)動(dòng)DHT11的時(shí)候很久一直沒有成功,起初以為跟最開始驅(qū)動(dòng)繼電器的時(shí)候一樣,電壓問題,然后后來仔細(xì)核對代碼,查看時(shí)序圖,發(fā)現(xiàn)在AndroidThings系統(tǒng)下讀取一次GPIO值耗時(shí)就在270us左右,而dht11的時(shí)序圖中電平轉(zhuǎn)換時(shí)間都是在100us以下,所以在java下使用GPIO不能捕捉到如此短時(shí)間內(nèi)的電平變化,無法獲取到溫濕度值。
以下是代碼:
package com.donute.iot_android.utils;
import android.util.Log;
import com.google.android.things.pio.Gpio;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* Created by zhouyufei on 2017/1/5.
*/
public class TemperatureUtil {
private Gpio gpio;
private LoopThread thread;
private float temp=0.0f;
private float humi=0.0f;
private static TemperatureUtil temperatureUtil;
private TemperatureUtil(Gpio gpio) {
this.gpio = gpio;
thread=new LoopThread();
thread.start();
}
public static TemperatureUtil init(Gpio gpio){
if (temperatureUtil==null){
temperatureUtil=new TemperatureUtil(gpio);
}
return temperatureUtil;
}
public void destory(){
if (thread!=null){
thread.interrupt();
thread=null;
}
}
private void calculate(List<Integer> integers){
Log.d("tem","長度:"+integers.size()+" "+integers+"");
}
public float getTemp(){
return temp;
}
public float getHumi(){
return humi;
}
class LoopThread extends Thread{
@Override
public void run() {
super.run();
while (!isInterrupted()){
List<Integer> list=new ArrayList<>();
try {
gpio.setDirection(Gpio.DIRECTION_OUT_INITIALLY_HIGH);
gpio.setActiveType(Gpio.ACTIVE_HIGH);
Thread.sleep(10);
gpio.setValue(false);
Thread.sleep(2);
gpio.setValue(true);
gpio.setDirection(Gpio.DIRECTION_IN);
gpio.setActiveType(Gpio.ACTIVE_HIGH);
while (!gpio.getValue()){
Log.d("gpio","low");
continue;
}
while (gpio.getValue()){
Log.d("gpio","high");
continue;
}
long l3=System.nanoTime();
while (list.size()<40){
int j=0;
while (!gpio.getValue()){
Log.d("gpio","low");
continue;
}
while (gpio.getValue()){
Log.d("gpio","high");
j=j+1;
if (j>100)
break;
}
Log.e("value of j",j+"");
if (j<8)
list.add(0);
else
list.add(1);
}
calculate(list);
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}