Android ADK USB 通信简单示例 点亮关闭LED

前面Android ADK 编程简介 介绍了ADK编程的一般步骤,这里给出一个简单的实例说明Android手机如果通过USB端口来控制LED。

所使用的Arduino 板子为Freetronics 的 EtherTen ,就一红一绿LED连接到7,8口上。如下图所示:

参考DemoKit的 Arudino 代码,为LED 驱动编写如下代码:

#include <avrpins.h>
#include <max3421e.h>
#include <usbhost.h>
#include <usb_ch9.h>
#include <Usb.h>
#include <usbhub.h>
#include <avr/pgmspace.h>
#include <address.h>

#include <adk.h>

#include <printhex.h>
#include <message.h>
#include <hexdump.h>
#include <parsetools.h>

USB Usb;
USBHub hub0(&Usb);
USBHub hub1(&Usb);
ADK adk(&Usb,"Guidebee Pty Ltd.",
"LedDemoKit",
"DemoKit Arduino Board",
"1.0",
"http://www.imobilebbs.com",
"0000000012345678");
uint8_t  b, b1;

#define  START_MOTOR               8
#define  STOP_MOTOR                7

#define  ERROR_INDICATOR        13

void setup();
void loop();

void init_leds()
{
pinMode(START_MOTOR, OUTPUT);
pinMode(STOP_MOTOR, OUTPUT);
digitalWrite(START_MOTOR, LOW);
digitalWrite(STOP_MOTOR, LOW);
}

void setup()
{
Serial.begin(115200);
Serial.println("\r\nADK demo start");

if (Usb.Init() == -1) {
Serial.println("OSCOKIRQ failed to assert");
while(1); //halt
}//if (Usb.Init() == -1...

init_leds();

}

void loop()
{
uint8_t rcode;
uint8_t msg[3] = { 0x00 };
Usb.Task();

if( adk.isReady() == false ) {
digitalWrite(ERROR_INDICATOR, HIGH);
return;
}else{
digitalWrite(ERROR_INDICATOR, LOW);
}
uint16_t len = sizeof(msg);
rcode = adk.RcvData(&len, msg);

if(len > 0) {
USBTRACE("\r\nData Packet.");
// assumes only one command per packet
if (msg[0] == 0x2) {
switch( msg[1] ) {
case 0:
USBTRACE("LED 1\r\n.");
if(msg[2]>128){
digitalWrite(START_MOTOR, HIGH);
} else{
digitalWrite(START_MOTOR, LOW);
}
break;
case 1:
USBTRACE("LED 2\r\n.");
if(msg[2]>128){
digitalWrite(STOP_MOTOR, HIGH);
} else{
digitalWrite(STOP_MOTOR, LOW);
}
break;
}//switch( msg[1]...
}
}//if( len > 0...

msg[0] = 0x1;
delay( 10 );
}

编写一个简单的Android应用,包含四个按钮,如下:

这里设计一个帮助类ArduinoHelper,用于和Arduino板子USB通信,这个类可以和任意的Activity绑定,因此很容易应用到你自己的代码中。参见代码下载。

有了ArduinoHelper, Android应用和Arduino板子通信就非常简单,在OnCreate 中创建ArudinoHelp 的实例, 在onResume和onDestroy 方法中调用ArduinoHelper 的对于的方法:

public class ArduinoLedDemoActivity extends Activity {
/** Called when the activity is first created. */

protected ArduinoHelper mArduinoHelper;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mArduinoHelper = new ArduinoHelper(this);
Button button1 = (Button) findViewById(R.id.button1);
button1.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
mArduinoHelper.sendCommand(ArduinoHelper.LED_SERVO_COMMAND,
(byte) 0x1, 250);

}
});

Button button2 = (Button) findViewById(R.id.button2);
button2.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
mArduinoHelper.sendCommand(ArduinoHelper.LED_SERVO_COMMAND,
(byte) 0x1, 1);

}
});

Button button3 = (Button) findViewById(R.id.button3);
button3.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
mArduinoHelper.sendCommand(ArduinoHelper.LED_SERVO_COMMAND,
(byte) 0x0, 250);

}
});

Button button4 = (Button) findViewById(R.id.button4);
button4.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
mArduinoHelper.sendCommand(ArduinoHelper.LED_SERVO_COMMAND,
(byte) 0x0, 1);

}
});
}

@Override
public void onDestroy() {
super.onDestroy();
mArduinoHelper.onDestroy();
}

@Override
public void onResume() {
super.onResume();
mArduinoHelper.onResume();
}

}

代码下载

 

 

发表在 Android | 标签为 , | 留下评论

Android ApiDemos示例解析(205):Graphics->OpenGL ES->Translucent GLSurfaceView

本例介绍使用透明背景绘制OpenGL 图形。步骤如下:

1. 对于Activity使用透明主题

<activity android:name=”.graphics.TranslucentGLSurfaceViewActivity”
android:label=”Graphics/OpenGL ES/Translucent GLSurfaceView”
  android:theme=”@style/Theme.Translucent”
android:configChanges=”keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize”>
<intent-filter>
<action android:name=”android.intent.action.MAIN” />
<category android:name=”android.intent.category.SAMPLE_CODE” />
</intent-filter>
</activity>

2. 使用8888 (RGBA) 格式,Alpha通道是显示透明图形必需的。

// We want an 8888 pixel format because that's required for
// a translucent window.
// And we want a depth buffer.
mGLSurfaceView.setEGLConfigChooser(8, 8, 8, 8, 16, 0);

3. 为GLSurfaceView指定Alpha通道

mGLSurfaceView.getHolder().setFormat(PixelFormat.TRANSLUCENT);

4. 为绘制的图行背景为颜色(0,0,0,0)

gl.glClearColor(0,0,0,0);

 

发表在 Android, OpenGL ES, 教程 | 标签为 , | 评论关闭

Android ApiDemos示例解析(204):Graphics->OpenGL ES->Frame Buffer Object

Frame Buffer 对象的概念可以参见前面文章Android OpenGL ES 开发教程(23):FrameBuffer

简单的和2D图像类比,Frame Buffer 如果 对应到二维图形环境中,就是一个2D的内存数组空间,缺省情况为屏幕的显存,也可以创建Offscreen 内存空间,此时Frame Buffer 可以是一个二维数组,数组每个元素代表一个像素颜色。

对于三维图形来说,除了需要代表颜色的二维数组(Color Buffer),还需要深度二维数组(Depth Buffer) 或遮罩数组(Stencil Buffer),因此在OpenGL 中的Frame Buffer为上述Color Buffer,Depth Buffer,Stencil Buffer 的集合。如果手机具有GPU,其缺省的Frame Buffer也是3D屏幕显示区域。

通过Opengl ES扩展支持,应用程序也可以创建内存中的Frame Buffer对象(不用于屏幕显示)。通过这种应用程序创建的FrameBuffer对象,OpenGL应用可以将图像显示输出重新定向到这个非屏幕显示用FrameBuffer对象中,类似于二维图形绘制中常用的Offscreen 技术。

和缺省的屏幕显示FrameBuffer一样,由应用程序创建的FrameBuffer对象也是由Color Buffer, Depth Buffer和Stencil Buffer(可选)的集合组成。这些Buffer在FrameBuffer对象中可以称为FrameBuffer-attachable 图像,FrameBuffer定义了一些接入点(Attachment Point)可以用于连接(Attach)这些Buffer数组。

OpenGL ES定义了两种FrameBuffer-attachable 图像,Texture 和 renderbuffer ,简单的可以将Texture  理解为Color buffer 或是2D图像,render buffer 对应于depth buffer。

下图表示了Texture , Renderbuffer 对象和 Frame Buffer 对象之间的关系:

但把Texture 和 Render Buffer 链接到FrameBuffer这些接入点(ATTACHMENT)之后,之后所有OpenGL绘图指令的输出结果就写入到这些内存Buffer中,而非缺省屏幕显示。

不同的Android设备支持的OpenGL ES扩展可能有所不同,因此如果需要使用应用创建FrameBuffer对象前需要检查手机是否支持Framebuffer扩展,本例使用

private boolean checkIfContextSupportsExtension(GL10 gl, String extension) {
 String extensions = " " + gl.glGetString(GL10.GL_EXTENSIONS) + " ";
 // The extensions string is padded with spaces between extensions, but not
 // necessarily at the beginning or end. For simplicity, add spaces at the
 // beginning and end of the extensions string and the extension string.
 // This means we can avoid special-case checks for the first or last
 // extension, as well as avoid special-case checks when an extension name
 // is the same as the first part of another extension name.
 return extensions.indexOf(" " + extension + " ") >= 0;
}

使用FrameBuffer的基本步骤如下:

1. 使用glGenFramebuffersOES创建FrameBuffer对象

int[] framebuffers = new int[1];
gl11ep.glGenFramebuffersOES(1, framebuffers, 0);
framebuffer = framebuffers[0];

2. 创建好FrameBuffer后,必须绑定FrameBuffer到OpenGL中,

gl11ep.glBindFramebufferOES(GL11ExtensionPack.GL_FRAMEBUFFER_OES, framebuffer);

第一个参数类型必须为GL_FRAMEBUFFER_OES,第二个参数为FrameBuffer的ID。如果Id为0,表示绑定到缺省的屏幕FrameBuffer。

绑定之后,后续的OpenGL绘制结果就从定向到FrameBuffer中,而不是显示到屏幕上。

3, 使用glGenRenderbuffersOES创建RenderBuffer

int depthbuffer;
int[] renderbuffers = new int[1];
gl11ep.glGenRenderbuffersOES(1, renderbuffers, 0);
depthbuffer = renderbuffers[0];

4. 和FrameBuffer类似,创建RenderBuffer对象,也需要绑定到OpengL库中

gl11ep.glBindRenderbufferOES(GL11ExtensionPack.GL_RENDERBUFFER_OES, depthbuffer);

5. 给renderBuffer 分配内存。

创建的renderBuffer 本身不含有内存空间,因此必须给它分配内存空间,这是通过glRenderbufferStorageOES来实现的。

gl11ep.glRenderbufferStorageOES(GL11ExtensionPack.GL_RENDERBUFFER_OES,
 GL11ExtensionPack.GL_DEPTH_COMPONENT16, width, height);

第二个参数为创建的RenderBuffer的内部格式类型。

6. 创建Texture对象,可以参见Android ApiDemos示例解析(200):Graphics->OpenGL ES->Textured Triangle

7. 在创建好FrameBuffer,Texture和renderBuffer对象之后,需要把Texture,RenderBuffer对象和FrameBuffer中对应的Attachment Point链接起来。

链接Texture对象

gl11ep.glFramebufferTexture2DOES(GL11ExtensionPack.GL_FRAMEBUFFER_OES,
 GL11ExtensionPack.GL_COLOR_ATTACHMENT0_OES, GL10.GL_TEXTURE_2D,
 targetTextureId, 0);

链接renderBuffer 对象

l11ep.glFramebufferRenderbufferOES(GL11ExtensionPack.GL_FRAMEBUFFER_OES,
 GL11ExtensionPack.GL_DEPTH_ATTACHMENT_OES,
 GL11ExtensionPack.GL_RENDERBUFFER_OES, depthbuffer);

来看一下本例的onDrawFrame方法

private static final boolean DEBUG_RENDER_OFFSCREEN_ONSCREEN = false;

public void onDrawFrame(GL10 gl) {
 checkGLError(gl);
 if (mContextSupportsFrameBufferObject) {
 GL11ExtensionPack gl11ep = (GL11ExtensionPack) gl;
 if (DEBUG_RENDER_OFFSCREEN_ONSCREEN) {
 drawOffscreenImage(gl, mSurfaceWidth, mSurfaceHeight);
 } else {
 gl11ep.glBindFramebufferOES(GL11ExtensionPack.GL_FRAMEBUFFER_OES, mFramebuffer);
 drawOffscreenImage(gl, mFramebufferWidth, mFramebufferHeight);
 gl11ep.glBindFramebufferOES(GL11ExtensionPack.GL_FRAMEBUFFER_OES, 0);
 drawOnscreen(gl, mSurfaceWidth, mSurfaceHeight);
 }
 } else {
 // Current context doesn't support frame buffer objects.
 // Indicate this by drawing a red background.
 gl.glClearColor(1,0,0,0);
 gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
 }
}

本例在创建的FrameBuffer中绘制立方体,其绘图指令和例子Android ApiDemos示例解析(203):Graphics->OpenGL ES->GLSurfaceView一样。但其显示结果存放在mFramebuffer中(可以通过将DEBUG_RENDER_OFFSCREEN_ONSCREEN设为True看到FrameBuffer的内容)。然后将mFramebuffer显示的内存作为Triangle的材质绘制三角形

 

 

发表在 Android, OpenGL ES, 教程 | 标签为 , | 评论关闭

Android 自动控制生产线

在前面Android ADK 编程简介介绍过使用Android NDK可以通过Arduino Board 实现一个自动控制系统,今天和同事一起设计了一个“生产线”(具体用途这里就不说了),先上个图片。

中间是从IKEA买的圆等和餐桌上用的转盘:-)。经过几个小时的忙活,这个系统原型基本达到设计要求。

发表在 Android | 标签为 | 评论关闭

本博客支持android,iphone,iPad 显示

借助于WPTouch ,本博客在移动设备上有更美观的显示,有兴趣的朋友可以使用您的手机或平板电脑登录本博客:-)

发表在 手机平台 | 标签为 | 评论关闭

Android ApiDemos示例解析(203):Graphics->OpenGL ES->GLSurfaceView

这个例子是使用OpenGL ES绘图最简单的例子,说明如何使用GLSerfaceView,前面的例子Android OpenGL ES 开发教程(6):GLSurfaceView 已经详细说明了,本篇不再具体描述。几何图形顶点定义参见Android OpenGL ES 开发教程(8):基本几何图形定义,颜色定义参见Android OpenGL ES 开发教程(20):颜色Color

本例对应的类文件为Cube.java ,CubeRenderer.java ,GLSurfaceViewActivity.java 。

Cube 类定义了一个立方体,要注意的是本例使用GL_FIXED,而非GL_FLOAT, GL_FIXED 表示16.16 定点浮点数,GL_FIXED 的0×10000 相当于GL_FLOAT 的1.0

对应的代码如下:

int one = 0x10000;
int vertices[] = {
 -one, -one, -one,
 one, -one, -one,
 one, one, -one,
 -one, one, -one,
 -one, -one, one,
 one, -one, one,
 one, one, one,
 -one, one, one,
};

int colors[] = {
 0, 0, 0, one,
 one, 0, 0, one,
 one, one, 0, one,
 0, one, 0, one,
 0, 0, one, one,
 one, 0, one, one,
 one, one, one, one,
 0, one, one, one,
};

byte indices[] = {
 0, 4, 5, 0, 5, 1,
 1, 5, 6, 1, 6, 2,
 2, 6, 7, 2, 7, 3,
 3, 7, 4, 3, 4, 0,
 4, 7, 6, 4, 6, 5,
 3, 0, 1, 3, 1, 2
};

CubeRenderer 通过坐标变换的方式绘制两个立方体,

gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
gl.glTranslatef(0, 0, -3.0f);
gl.glRotatef(mAngle, 0, 1, 0);
gl.glRotatef(mAngle*0.25f, 1, 0, 0);

gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_COLOR_ARRAY);

mCube.draw(gl);

gl.glRotatef(mAngle*2.0f, 0, 1, 1);
gl.glTranslatef(0.5f, 0.5f, 0.5f);

mCube.draw(gl);

下图为当mAngle=45 度时显示结果:

发表在 Android, OpenGL ES, 教程 | 标签为 , | 评论关闭

Android ApiDemos示例解析(202):Graphics->OpenGL ES->Cube Map

Cube Map,中文可以翻译成立方环境映射,下面是摘自维基百科的说明:

立方反射映射是用立方映射使得物体看起来如同在反射周围环境的一项技术。通常,这通常使用户外渲染中使用的 skybox 完成。尽管由于反射物周围的物体无法在结果中看到,所以这并不是一个真正的反射,但是通常仍然可以达到所期望的效果。

通过确定观察物体的向量就可以进行立方映射反射,照相机光线在照相机向量与物体相交的位置按照曲面法线方向进行反射,这样传到立方图(cube map)取得纹素(texel)的反射光线在照相机看来好像位于物体表面,这样就得到了物体的反射效果。

简单的讲,就是你把一个具有金属反射特性的茶壶放在一个房间中,茶壶的金属表面会反射房间的场景,Cube Map就是解决如何将场景(环境)的内容显示在茶壶的表面,如下图所示:

本例使用环面(Torus)做为反射的表面,在OpenGL ES中任何3D物体,最终都是通过三角形来构造的,本例代码generateTorusGrid 和Grid对象用来构造环面的顶点坐标。具体算法有兴趣的可以自行研究(需要有立体几何的知识,这里不详细解释)。

Cube map技术说到底就是用一个虚拟的立方体(cube)包围住物体,眼睛到物体某处的向量eyevec经过反射(以该处的法线为对称轴),反射向量reflectvec射到立方体上,就在该立方体上获得一个纹素了(见下图)。明显,我们需要一个类似天空盒般的6张纹理贴在这个虚拟的立方体上。按CUBE MAPPING原意,就是一种enviroment map,因此把周围场景渲染到这6张纹理里是“正统”的。也就是每次渲染时,都作一次离线渲染,分别在每个矩形中心放置相机“拍下”场景,用FBO渲染到纹理,然后把这张纹理作为一个cube map对象的六纹理之一。这样即使是动态之物也能被映射到物体表面了(虽然缺点是不能映射物体自身的任何部分)。

本例使用的六张图为res/raw 目录下的 skycubemap0 — skycubemap5 ,如下图所示

使用Cube Map,首先要检测设备是否支持Cube Map 材质,本例使用以下代码检测设备是否支持Cube Map。

private boolean checkIfContextSupportsCubeMap(GL10 gl) {
return checkIfContextSupportsExtension(gl, "GL_OES_texture_cube_map");

}

/**
* This is not the fastest way to check for an extension, but fine if
* we are only checking for a few extensions each time a context is created.
* @param gl
* @param extension
* @return true if the extension is present in the current context.
*/
private boolean checkIfContextSupportsExtension(GL10 gl, String extension) {
String extensions = " " + gl.glGetString(GL10.GL_EXTENSIONS) + " ";
// The extensions string is padded with spaces between extensions, but not
// necessarily at the beginning or end. For simplicity, add spaces at the
// beginning and end of the extensions string and the extension string.
// This means we can avoid special-case checks for the first or last
// extension, as well as avoid special-case checks when an extension name
// is the same as the first part of another extension name.
return extensions.indexOf(" " + extension + " ") >= 0;
}

Cube Map (使用6张图),处调用设置Cube Map外,其基本使用步骤类似于普通材质的使用。本例使用资源,其设置Cube Map的基本步骤如下:

1. 调入图像资源

if (mContextSupportsCubeMap) {
int[] cubeMapResourceIds = new int[]{
R.raw.skycubemap0, R.raw.skycubemap1, R.raw.skycubemap2,
R.raw.skycubemap3, R.raw.skycubemap4, R.raw.skycubemap5};
mCubeMapTextureID = generateCubeMap(gl, cubeMapResourceIds);
}

....

private int generateCubeMap(GL10 gl, int[] resourceIds) {
checkGLError(gl);
int[] ids = new int[1];
gl.glGenTextures(1, ids, 0);
int cubeMapTextureId = ids[0];
gl.glBindTexture(GL11ExtensionPack.GL_TEXTURE_CUBE_MAP, cubeMapTextureId);
gl.glTexParameterf(GL11ExtensionPack.GL_TEXTURE_CUBE_MAP,
GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
gl.glTexParameterf(GL11ExtensionPack.GL_TEXTURE_CUBE_MAP,
GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);

for (int face = 0; face < 6; face++) {
InputStream is = getResources().openRawResource(resourceIds[face]);
Bitmap bitmap;
try {
bitmap = BitmapFactory.decodeStream(is);
} finally {
try {
is.close();
} catch(IOException e) {
Log.e("CubeMap", "Could not decode texture for face " + Integer.toString(face));
}
}
GLUtils.texImage2D(GL11ExtensionPack.GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, 0,
bitmap, 0);
bitmap.recycle();
}
checkGLError(gl);
return cubeMapTextureId;
}

2. 绑定材质

函数generateCubeMap返回一个Texture的ID,在OpenGL ES中使用材质时,需要绑定材质

gl.glActiveTexture(GL10.GL_TEXTURE0);
checkGLError(gl);
gl.glEnable(GL11ExtensionPack.GL_TEXTURE_CUBE_MAP);
checkGLError(gl);
gl.glBindTexture(GL11ExtensionPack.GL_TEXTURE_CUBE_MAP, mCubeMapTextureID);
checkGLError(gl);
GL11ExtensionPack gl11ep = (GL11ExtensionPack) gl;
gl11ep.glTexGeni(GL11ExtensionPack.GL_TEXTURE_GEN_STR,
GL11ExtensionPack.GL_TEXTURE_GEN_MODE,
GL11ExtensionPack.GL_REFLECTION_MAP);
checkGLError(gl);
gl.glEnable(GL11ExtensionPack.GL_TEXTURE_GEN_STR);
checkGLError(gl);
gl.glTexEnvx(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE, GL10.GL_DECAL);
...
mGrid.draw(gl);
...
gl.glDisable(GL11ExtensionPack.GL_TEXTURE_GEN_STR);

这样就给环面物体添加了环境材质,显示结果如下:

发表在 Android, OpenGL ES, 教程 | 标签为 , | 评论关闭

引路蜂地图应用GNavigator完整源码

GNavigator是 曾经发布在Nokia Ovi Store的Java ME应用,基本使用到了引路蜂地图API的所有功能,尽管这是一个基于LWUIT的应用,使用Java语言开发,其它平台也可以参考这个应用的代码。

总代码量大约为24000行,其中纯代码为12000行。

几个用户界面如下:

包括导航演示(可以连接GPS)

代码下载 ,用户手册 ,为Netbean 项目。

如果您喜欢本博客,希望捐赠本站,请点击右方的捐赠按钮,或点击下面按钮,谢谢您的支持!


Donate!

发表在 地图开发 | 标签为 | 评论关闭

Android ADK 编程简介

前面已经说过Android SDK ,NDK, APK, 现在有来了个ADK, 这么多K:-). 那么什么是ADK,ADK是Android Open Accessory Development Kit 的缩写。使用ADK使得不支持USB Host功能的Android设备也可以和其它USB设备交互。比如使用Android手机来控制步进电机,条码扫描仪,机器人等。

Android 设备支持各种各样的USB设备,即可以以USB Host模式工作,也可以以USB Accessory 模式工作:

从Android 3.1 (API Level 12) 开始Andriod平台开始支持USB Accessory 和 Host 工作模式,Google也通过附加库的方式中Android 2.3.4 (API Level 10) 支持USB Accessory 和Host 工作模式。

注意:对USB Host或Accessory 模式的支持最终取决于设备硬件,和平台OS的版本无关,比如Sumsung Galaxy Nexus 同时支持USB Host或Accessory 模式而Sumsung Nexus S 只支持USB Accessory 模式,尽管两种手机都采用了ICS 4.0.4平台。

本例介绍如何使用ADK 通过Arduino 连接QRCode Scanner 通过ADK 和Android应用通信。

其硬件连接图如下:

其中Arduino 控制板采用的Freetronics的UsbDroid控制板(和Arduino兼容),QRCode Scanner(工作中USB HID模式)。

由于手机的USB需要和Usb Hub 连接,因此本例需要Android 不通过USB数据线调试的方法

本例没有采用http://developer.android.com/guide/topics/usb/adk.html 中介绍的软件和USB_Host_Sheild 库,是以为这个库不支持Usb Hub,需要将上图中连接Usb Hub的线直接连到手机,这样就无法再连接QR Code Scanner了。不过基本步骤是一致的。

1. 下载Ardunio软件和对应的USB库。

目前Ardunio的版本为1.0,如果你想使用Google 网站上的例子,你需要使用023版本。为方便起见,你可以从本站下载软件和USB库(支持USB Hub功能),其中USB库为Circuits @Home 提供。

2. 下载 对应的Android实例应用,本例使用Arduino terminal

3. 将firmware 安装到Arduino 控制板上。

本例使用adk 中adk-barcode 示例。其代码如下,可以参见

/**/
/* A sketch demonstrating data exchange between two USB devices
- a HID barcode scanner and ADK-compatible Android phone */
/**/
#include <avrpins.h>
#include <max3421e.h>
#include <usbhost.h>
#include <usb_ch9.h>
#include <Usb.h>
#include <usbhub.h>
#include <avr/pgmspace.h>
#include <address.h>

#include <adk.h>

#include <hidboot.h>

USB Usb;
USBHub Hub1(&Usb);
USBHub Hub2(&Usb);
HIDBoot<HID_PROTOCOL_KEYBOARD> Keyboard(&Usb);

ADK adk(&Usb,"Circuits@Home, ltd.",
"USB Host Shield",
"Arduino Terminal for Android",
"1.0",
"http://www.circuitsathome.com",
"0000000000000001");

class KbdRptParser : public KeyboardReportParser
{

protected:
virtual void OnKeyDown    (uint8_t mod, uint8_t key);
virtual void OnKeyPressed(uint8_t key);
};

void KbdRptParser::OnKeyDown(uint8_t mod, uint8_t key)
{
uint8_t c = OemToAscii(mod, key);

if (c)
OnKeyPressed(c);
}

/* what to do when symbol arrives */
void KbdRptParser::OnKeyPressed(uint8_t key)
{
const char* new_line = "\n";
uint8_t rcode;
uint8_t keylcl;

if( adk.isReady() == false ) {
return;
}

keylcl = key;

if( keylcl == 0x13 ) {
rcode = adk.SndData( strlen( new_line ), (uint8_t *)new_line );
}
else {
rcode = adk.SndData( 1, &keylcl );
}

Serial.print((char) keylcl );
Serial.print(" : ");
Serial.println( keylcl, HEX );
};

KbdRptParser Prs;

void setup()
{
Serial.begin(115200);
Serial.println("\r\nADK demo start");

if (Usb.Init() == -1) {
Serial.println("OSCOKIRQ failed to assert");
while(1); //halt
}//if (Usb.Init() == -1...

Keyboard.SetReportParser(0, (HIDReportParser*)&Prs);

delay( 200 );
}

void loop()
{
Usb.Task();
}

这里的ADK与Google提供的示例稍有不同,但大同小异。

4. 在手机上运行Arduino terminal (这不是必须的),当将USB线连接到手机时,会自动触发这个应用。这是因为:

Firmware中使用ADK定义

ADK adk(&Usb,”Circuits@Home, ltd.”,
USB Host Shield“,
“Arduino Terminal for Android”,
1.0″,
“http://www.circuitsathome.com”,
“0000000000000001″);

和Arduino terminal 的broadcast receiver 定义对应:

<activity android:name=”.StartServiceActivity” android:label=”@string/starter_app_name”
android:launchMode=”singleInstance” android:theme=”@android:style/Theme.NoDisplay”
android:excludeFromRecents=”true”>

<intent-filter>
<action android:name=”android.hardware.usb.action.USB_ACCESSORY_ATTACHED” />
</intent-filter>

<meta-data android:name=”android.hardware.usb.action.USB_ACCESSORY_ATTACHED”
android:resource=”@xml/accessory_filter” />
</activity>

xml/accessory_filter.xml 的定义如下:

<resources>

<usb-accessory manufacturer=”Circuits@Home, ltd.” model=”USB Host Shield” version=”1.0″ />
</resources>

对于你自己的例子,你可以使用你自己定义的名称,只有保证这几个值在firmware 和Android应用中定义的值一致即可。

运行结果如下:

Arduino 编程并不复杂,只要会C语言即可,可以参见arduino-1.0 中的reference文档。Usb_host C库可以参考libraries/felis_USB_Host_Shield 的头文件。

注:通过这种连接方法,可以连接USB照相机,GPS, 步进电机等各种外设,可以实现使用Android来自动控制等。

发表在 Android | 标签为 , | 评论关闭

Android ApiDemos示例解析(201):Graphics->OpenGL ES->Compressed Texture

本例和上例Android ApiDemos示例解析(200):Graphics->OpenGL ES->Textured Triangle 非常类似,所不同的是调用图像(Texture)的方法不同。

本例介绍如何使用ETC1 压缩格式的图像,一种方式是从资源文件中读取ETC1格式的图像作为三角形的材质(本例使用res.raw 中的androids.pkm文件),一种是通过代码动态创建ETC1格式的图像。 android.opengl 包中的 ETC1, ETCUtil, ETCUtil.ETC1Texture 用来支持ETC1格式的压缩格式图像,简单的讲,可以把android.pkm 当做android.png ,所不同的是两种图像压缩方法不同。

使用ETC1 图像作为Texture的基本方法如下:

InputStream input = getResources().openRawResource(R.raw.androids);
...
ETC1Util.loadTexture(GLES10.GL_TEXTURE_2D, 0, 0,
GLES10.GL_RGB, GLES10.GL_UNSIGNED_SHORT_5_6_5, input);

发表在 Android, OpenGL ES | 标签为 , | 评论关闭