AndroidThings
搭梯子访问:https://developer.android.com/things/index.html
为了抢攻智能家电市场,Google 14 日推出全新物联网平台“Android Things”的开发者预
览版本。未来不只是手机,Android 可能将透过喇叭、监视器和路由器等家电,占据家中每个
角落。
可用于打印机、门锁、烤箱、灯泡、插座等
Android Things 的前身为在 2015 年 5 月发布的物联网平台 Brillo,不过至今并未受
到开发者大量采用。Google 强调,新推出的 Android Things 除了承袭 Brillo 的功
能,还加入 Android 开发者熟悉的工具,包含 Android Studio、Android SDK、
Google Play 服务和 Google 云端平台,提供整套打造 Android 智能联网设备所需工具,
让任何 Android 开发者都能轻松打造物联网服务。
只要你有能力打造出 App,你就能打造出一个设备。──Google
硬件
现在支持以下3款硬件:
1)Intel Edison
2)NXP Pico
3)Raspberry Pi 3
我使用的是树莓派3,拿到板子首先需要在安卓开发者网站下载预览版镜像。地址为:https://developer.android.com/things/preview/download.html
接下来将8G内存以上的高速TF卡放入读卡器,插入电脑,我使用的是OS X系统,给树莓派刷入
系统的步骤与Linux类似使用终端运行以下命令:
dd bs=4m if=iot_rpi3.img of=/dev/disk2
其中iot_rpi3.img 表示系统镜像所在的目录,我的就在当前目录所以就直接写文件名就OK
接着/dev/disk2是TF在文件系统上的位置。
稍等5分钟左右,系统写入完成,拔下读卡器,将TF卡放入树莓派上电开机。
第一印象
接入显示器开机,开机画面后并没有看到我们熟悉的安卓系统界面。而是在一个AndroidThings
的背景图后显示了已经获取的IP地址。对于AndroidThings来说显示屏不是必须的,无显示器
一样可以工作,使用鼠标试用了一下,界面不是很流畅。
值得一提的是系统开机后虽然并没有可供操作的选项,但是当你编写的带UI的程序运行到系统后
是有界面的,与普通app运行基本没有差别。
使用IIC驱动12864OLED屏幕
拿到板子不久又购买了一块12864的OLED屏幕和一个DHT11温湿度传感器,然后对OLED屏幕开
始折腾。
要操作点阵显示屏,也就是写数据和写命令!让屏幕休眠、让屏幕滚动之类的操作,就要向屏幕
写命令;要让屏幕显示内容,就要写数据。 怎样让屏幕知道你发送的东西是数据还是命令?有
的屏幕有类似D/C(Data/Command)这样的引脚,说明是通过高低电平来区分,有的屏幕是向屏
幕写入特定的值来区分。 点阵屏内部都有一个驱动芯片,这个驱动芯片就负责按照程序的要
求,在某一个点来进行操作。所谓的初始化就是这个驱动芯片的初始化,初始化中注意两个地
方:
一个是复位!这个非常重要,如果没有完全复位,可能导致屏幕不稳定、显示乱码等畸形问题!
另一个就是初始化代码!这个初始化代码一般都是一些16进制数,可以在显示屏的规格书之类的文档里面找到,可以通过“写命令”的方式能够把初始化代码发送给显示屏。
完成了这些步骤,就可以让它显示你想要的东西了!
上代码
//以下代码中不包括字码,因为我的屏幕本身不带字库,所以需要用软件提码得到,具体购买屏幕时一般会附带提码软件
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Õý³£
oledCmd((byte)0xc8);//Set COM/Row Scan Direction (byte)0xc0ÉÏÏ·´Öà (byte)0xc8Õý³£
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一组标准ASCII字符串 显示的坐标(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一组标准ASCII字符串 显示的坐标(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点阵 显示的坐标(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起始点坐标(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 设置坐标************************************/
public void OLED_Set_Pos(int x, int y)
{
oledCmd(0xb0+y);
oledCmd(((x&0xf0)>>4)|0x10);
oledCmd((x&0x0f)|0x01);
}
/*****************************清除屏幕显示内容************************************/
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);
}
}
}
}
使用GPIO驱动DHT11
因为之前有使用GPIO驱动继电器工作的经历,继电器接在3.3V正常工作,接在5V下无法驱动。
在尝试了驱动DHT11的时候很久一直没有成功,起初以为跟最开始驱动继电器的时候一样,电压问题,然后后来仔细核对代码,查看时序图,发现在AndroidThings系统下读取一次GPIO值耗时就在270us左右,而dht11的时序图中电平转换时间都是在100us以下,所以在java下使用GPIO不能捕捉到如此短时间内的电平变化,无法获取到温湿度值。
以下是代码:
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();
}
}
}
}
}