A USB OTG cable is needed in Android side, to connect with a Arduino USB cable, to connect to Arduino Uno.
Android Side:
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.androidusbmatrix"
android:versionCode="1"
android:versionName="1.0" >
<uses-feature android:name="android.hardware.usb.host" />
<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="21" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
<meta-data
android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource="@xml/device_filter" />
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_DETACHED" />
</intent-filter>
</activity>
</application>
</manifest>
/res/xml/device_filter.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- idVendor=2341, idProduct=0043 for Arduino Uno R3 -->
<usb-device
vendor-id="9025"
product-id="0067" />
</resources>
/res/layout/activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.androidtouchview.MainActivity" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:autoLink="web"
android:text="http://android-er.blogspot.com/"
android:textStyle="bold" />
<TextView
android:id="@+id/textstatus"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textStyle="bold"
android:text="Status" />
<GridLayout
android:id="@+id/mygrid"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:columnCount="8"
android:rowCount="8"
android:layout_gravity="center"
android:background="@android:color/background_light" >
</GridLayout>
</LinearLayout>
MyView.java
package com.example.androidusbmatrix;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
public class MyView extends View {
public interface OnToggledListener {
void OnToggled(MyView v, boolean touchOn);
}
boolean touchOn;
boolean mDownTouch = false;
private OnToggledListener toggledListener;
int idX = 0; //default
int idY = 0; //default
public MyView(Context context, int x, int y) {
super(context);
idX = x;
idY = y;
init();
}
public MyView(Context context) {
super(context);
init();
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
touchOn = false;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec),
MeasureSpec.getSize(heightMeasureSpec));
}
@Override
protected void onDraw(Canvas canvas) {
if (touchOn) {
canvas.drawColor(Color.RED);
} else {
canvas.drawColor(Color.GRAY);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touchOn = !touchOn;
invalidate();
if(toggledListener != null){
toggledListener.OnToggled(this, touchOn);
}
mDownTouch = true;
return true;
case MotionEvent.ACTION_UP:
if (mDownTouch) {
mDownTouch = false;
performClick();
return true;
}
}
return false;
}
@Override
public boolean performClick() {
super.performClick();
return true;
}
public void setOnToggledListener(OnToggledListener listener){
toggledListener = listener;
}
public int getIdX(){
return idX;
}
public int getIdY(){
return idY;
}
}
MainActivity.java
package com.example.androidusbmatrix;
import java.util.HashMap;
import java.util.Iterator;
import com.example.androidusbmatrix.MyView.OnToggledListener;
import android.support.v7.app.ActionBarActivity;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbManager;
import android.os.Bundle;
import android.view.ViewGroup;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.widget.GridLayout;
import android.widget.TextView;
public class MainActivity extends ActionBarActivity
implements OnToggledListener{
TextView textStatus;
MyView[] myViews;
GridLayout myGridLayout;
private static final int targetVendorID = 9025; //Arduino Uno
private static final int targetProductID = 67; //Arduino Uno, not 0067
private static final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION";
PendingIntent mPermissionIntent;
UsbDevice deviceFound = null;
UsbInterface usbInterfaceFound = null;
UsbInterface usbInterface;
UsbDeviceConnection usbDeviceConnection;
UsbEndpoint endpointIn = null;
UsbEndpoint endpointOut = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textStatus = (TextView) findViewById(R.id.textstatus);
myGridLayout = (GridLayout) findViewById(R.id.mygrid);
int numOfCol = myGridLayout.getColumnCount();
int numOfRow = myGridLayout.getRowCount();
myViews = new MyView[numOfCol * numOfRow];
for (int yPos = 0; yPos < numOfRow; yPos++) {
for (int xPos = 0; xPos < numOfCol; xPos++) {
MyView tView = new MyView(this, xPos, yPos);
tView.setOnToggledListener(this);
myViews[yPos * numOfCol + xPos] = tView;
myGridLayout.addView(tView);
}
}
myGridLayout.getViewTreeObserver().addOnGlobalLayoutListener(
new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
int pLength;
final int MARGIN = 5;
int pWidth = myGridLayout.getWidth();
int pHeight = myGridLayout.getHeight();
int numOfCol = myGridLayout.getColumnCount();
int numOfRow = myGridLayout.getRowCount();
// Set myGridLayout equal width and height
if (pWidth >= pHeight) {
pLength = pHeight;
} else {
pLength = pWidth;
}
ViewGroup.LayoutParams pParams = myGridLayout
.getLayoutParams();
pParams.width = pLength;
pParams.height = pLength;
myGridLayout.setLayoutParams(pParams);
int w = pLength / numOfCol; // pWidth/numOfCol;
int h = pLength / numOfRow; // pHeight/numOfRow;
for (int yPos = 0; yPos < numOfRow; yPos++) {
for (int xPos = 0; xPos < numOfCol; xPos++) {
GridLayout.LayoutParams params = (GridLayout.LayoutParams) myViews[yPos
* numOfCol + xPos].getLayoutParams();
params.width = w - 2 * MARGIN;
params.height = h - 2 * MARGIN;
params.setMargins(MARGIN, MARGIN, MARGIN,
MARGIN);
myViews[yPos * numOfCol + xPos]
.setLayoutParams(params);
}
}
// deprecated in API level 16
myGridLayout.getViewTreeObserver()
.removeGlobalOnLayoutListener(this);
// for API Level >= 16
// myGridLayout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
// register the broadcast receiver
mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(
ACTION_USB_PERMISSION), 0);
IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
registerReceiver(mUsbReceiver, filter);
registerReceiver(mUsbDeviceReceiver, new IntentFilter(
UsbManager.ACTION_USB_DEVICE_ATTACHED));
registerReceiver(mUsbDeviceReceiver, new IntentFilter(
UsbManager.ACTION_USB_DEVICE_DETACHED));
connectUsb();
}
@Override
public void OnToggled(MyView v, boolean touchOn) {
if(deviceFound != null){
byte[] bytesSend = setupCmd();
usbDeviceConnection.bulkTransfer(endpointOut,
bytesSend, bytesSend.length, 0);
}
}
private byte[] setupCmd(){
byte[] bytes = new byte[18];
bytes[0] = (byte) 0xFF; //sync byte
bytes[1] = 0x01; //CMD
int i = 2;
int numOfRow = 8;
int numOfCol = 8;
int numOfHalfCol = 4;
for (int yPos = 0; yPos < numOfRow; yPos++) {
byte b = 0x00;
byte mask = 0x01;
for (int xPos = 0; xPos < numOfHalfCol; xPos++) {
if(myViews[yPos * numOfCol + xPos].touchOn){
b = (byte) (b | mask);
}
mask = (byte) (mask << 1);
}
bytes[i] = b;
i++;
b = 0x00;
mask = 0x10;
for (int xPos = numOfHalfCol; xPos < numOfCol; xPos++) {
if(myViews[yPos * numOfCol + xPos].touchOn){
b = (byte) (b | mask);
}
mask = (byte) (mask << 1);
}
bytes[i] = b;
i++;
}
return bytes;
}
//usb related
private boolean setupUsbComm() {
// for more info, search SET_LINE_CODING and
// SET_CONTROL_LINE_STATE in the document:
// "Universal Serial Bus Class Definitions for Communication Devices"
// at http://adf.ly/dppFt
final int RQSID_SET_LINE_CODING = 0x20;
final int RQSID_SET_CONTROL_LINE_STATE = 0x22;
boolean success = false;
UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
Boolean permitToRead = manager.hasPermission(deviceFound);
if (permitToRead) {
usbDeviceConnection = manager.openDevice(deviceFound);
if (usbDeviceConnection != null) {
usbDeviceConnection.claimInterface(usbInterfaceFound, true);
usbDeviceConnection.controlTransfer(0x21, // requestType
RQSID_SET_CONTROL_LINE_STATE, // SET_CONTROL_LINE_STATE
0, // value
0, // index
null, // buffer
0, // length
0); // timeout
// baud rate = 9600
// 8 data bit
// 1 stop bit
byte[] encodingSetting = new byte[] { (byte) 0x80, 0x25, 0x00,
0x00, 0x00, 0x00, 0x08 };
usbDeviceConnection.controlTransfer(0x21, // requestType
RQSID_SET_LINE_CODING, // SET_LINE_CODING
0, // value
0, // index
encodingSetting, // buffer
7, // length
0); // timeout
}
} else {
manager.requestPermission(deviceFound, mPermissionIntent);
textStatus.setText("Permission: " + permitToRead);
}
return success;
}
private void connectUsb() {
textStatus.setText("connectUsb()");
searchEndPoint();
if (usbInterfaceFound != null) {
setupUsbComm();
}
}
private void releaseUsb() {
textStatus.setText("releaseUsb()");
if (usbDeviceConnection != null) {
if (usbInterface != null) {
usbDeviceConnection.releaseInterface(usbInterface);
usbInterface = null;
}
usbDeviceConnection.close();
usbDeviceConnection = null;
}
deviceFound = null;
usbInterfaceFound = null;
endpointIn = null;
endpointOut = null;
}
private void searchEndPoint() {
usbInterfaceFound = null;
endpointOut = null;
endpointIn = null;
// Search device for targetVendorID and targetProductID
if (deviceFound == null) {
UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
HashMap<String, UsbDevice> deviceList = manager.getDeviceList();
Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();
while (deviceIterator.hasNext()) {
UsbDevice device = deviceIterator.next();
if (device.getVendorId() == targetVendorID) {
if (device.getProductId() == targetProductID) {
deviceFound = device;
}
}
}
}
if (deviceFound == null) {
textStatus.setText("device not found");
} else {
// Search for UsbInterface with Endpoint of USB_ENDPOINT_XFER_BULK,
// and direction USB_DIR_OUT and USB_DIR_IN
for (int i = 0; i < deviceFound.getInterfaceCount(); i++) {
UsbInterface usbif = deviceFound.getInterface(i);
UsbEndpoint tOut = null;
UsbEndpoint tIn = null;
int tEndpointCnt = usbif.getEndpointCount();
if (tEndpointCnt >= 2) {
for (int j = 0; j < tEndpointCnt; j++) {
if (usbif.getEndpoint(j).getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
if (usbif.getEndpoint(j).getDirection() == UsbConstants.USB_DIR_OUT) {
tOut = usbif.getEndpoint(j);
} else if (usbif.getEndpoint(j).getDirection() == UsbConstants.USB_DIR_IN) {
tIn = usbif.getEndpoint(j);
}
}
}
if (tOut != null && tIn != null) {
// This interface have both USB_DIR_OUT
// and USB_DIR_IN of USB_ENDPOINT_XFER_BULK
usbInterfaceFound = usbif;
endpointOut = tOut;
endpointIn = tIn;
}
}
}
}
}
private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (ACTION_USB_PERMISSION.equals(action)) {
textStatus.setText("ACTION_USB_PERMISSION");
synchronized (this) {
UsbDevice device = (UsbDevice) intent
.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if (intent.getBooleanExtra(
UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
if (device != null) {
connectUsb();
}
} else {
textStatus.setText("permission denied for device ");
}
}
}
}
};
private final BroadcastReceiver mUsbDeviceReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) {
deviceFound = (UsbDevice) intent
.getParcelableExtra(UsbManager.EXTRA_DEVICE);
textStatus.setText("ACTION_USB_DEVICE_ATTACHED");
connectUsb();
} else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
UsbDevice device = (UsbDevice) intent
.getParcelableExtra(UsbManager.EXTRA_DEVICE);
textStatus.setText("ACTION_USB_DEVICE_DETACHED");
if (device != null) {
if (device == deviceFound) {
releaseUsb();
}
}
}
}
};
}
Download the files in Android side.
Arduino Uno side:
Connection:
UnoUsbMatrix.ino
/*
* Modify from Row-Column Scanning an 8x8 LED matrix tutorial
* http://android-er.blogspot.com
* http://arduino-er.blogspot.com/
*/
// 2-dimensional array of row pin numbers:
const int row[8] = {
2, 7, 19, 5, 13, 18, 12, 16
};
// 2-dimensional array of column pin numbers:
const int col[8] = {
6, 11, 10, 3, 17, 4, 8, 9
};
// 2-dimensional array of pixels:
int pixels[8][8];
const int ST_0 = 0; //waiting Sync word
const int ST_1_CMD = 1; //Waiting CMD
const int ST_2_DATA= 2; //Receiving Data
const int DATA_LENGTH = 16; //length of data = 16
const byte SYNC_WORD = 0xFF;
const byte CMD_01 = 0x01; //currently only 01;
int cmdState;
int dataIndex;
byte data[DATA_LENGTH];
void setup() {
Serial.begin(9600);
// initialize the I/O pins as outputs
// iterate over the pins:
for (int thisPin = 0; thisPin < 8; thisPin++) {
// initialize the output pins:
pinMode(col[thisPin], OUTPUT);
pinMode(row[thisPin], OUTPUT);
// take the col pins (i.e. the cathodes) high to ensure that
// the LEDS are off:
digitalWrite(col[thisPin], HIGH);
}
for(int y=0; y<8; y++){
for(int x=0; x<8; x++){
pixels[x][y] = HIGH;
}
}
cmdState = ST_0;
}
void loop() {
refreshScreen();
if(Serial.available()){
cmdHandle(Serial.read());
}
}
void cmdHandle(int incomingByte){
switch(cmdState){
case ST_0:
if(incomingByte == SYNC_WORD){
cmdState = ST_1_CMD;
}
break;
case ST_1_CMD:
if(incomingByte == CMD_01){
cmdState = ST_2_DATA;
dataIndex = 0;
}else{
cmdState = ST_0;
}
break;
case ST_2_DATA:
data[dataIndex] = incomingByte;
dataIndex++;
int iData = 0;
if(dataIndex==DATA_LENGTH){
cmdState = ST_0;
for(int i=0; i<8; i++){
byte mask = 0x01;
for(int j=0; j<4; j++){
if (data[iData] & mask){
pixels[i][j] = LOW;
}else{
pixels[i][j] = HIGH;
}
mask = mask << 1;
}
iData++;
for(int j=4; j<8; j++){
if (data[iData] & mask){
pixels[i][j] = LOW;
}else{
pixels[i][j] = HIGH;
}
mask = mask << 1;
}
iData++;
}
}
break;
}
}
void refreshScreen() {
// iterate over the rows (anodes):
for (int thisRow = 0; thisRow < 8; thisRow++) {
// take the row pin (anode) high:
digitalWrite(row[thisRow], HIGH);
// iterate over the cols (cathodes):
for (int thisCol = 0; thisCol < 8; thisCol++) {
// get the state of the current pixel;
int thisPixel = pixels[thisRow][thisCol];
// when the row is HIGH and the col is LOW,
// the LED where they meet turns on:
digitalWrite(col[thisCol], thisPixel);
// turn the pixel off:
if (thisPixel == LOW) {
digitalWrite(col[thisCol], HIGH);
}
}
// take the row pin low to turn off the whole row:
digitalWrite(row[thisRow], LOW);
}
}
Download sketch in Arduino Uno side.
Next:
- Send and display single ASCII character to Arduino Uno.
Hi,how to run app?
ReplyDelete