|
想要从Android手机中发送文字到Arduino开发板吗?请看下文的介绍!
所需的材料 ● 支持USB主机模式的Android手机(即支持OTG)。检查您的手机是否使用Play商店中的USB Host Diagnostics应用程序。 ● Arduino Uno R3开发板。 ● Arduino USB电缆 ● USB OTG电缆 - 需要将其连接到Arduino的USB和智能手机的micro-USB端口。 ● Android Studio - 您需要安装和设置。这很容易做到。 Android Studio通过预测和代码生成使应用程序开发更容易。您还可以按照本文在计算机上设置Android Studio。
Android应用程序的主要组件 Android应用中有3个主要文件:
● MainActivity.java 这是Java代码所在的位置。它控制着应用程序的运行方式。 ● activity_main.xml中 这包含应用程序的布局,即组件或类似小部件的按钮、TextViews等。 ● AndroidManifest.xml中 您可以在此处定义应用程序必须启动的时间、所需的权限以及需要访问的硬件。
还有许多其他文件,但它们都是在这三个文件的帮助下链接在一起的。
互动可以被描述为用户与电话交互的屏幕。互动包含按钮、文本字段、图像等小部件,这些小部件有助于传输信息。本教程将使用一个互动,即Main Activity,它将用户的输入发送到Arduino并显示收到的文本。
布局 我们将为USB应用程序和蓝牙应用程序使用相同的布局。这是一个简单的小工具,需要最少的小部件来测试设备之间的连接。
如您所见,它有一个EditText小部件,用于从用户获取输入,按钮以启动连接、传输数据、结束连接和清除TextView。收到的数据显示在TextView(按钮下方的空白部分)中。
这是XML的一部分。由于按钮的代码类似,我只截取了一小部分。 - <RelativeLayout 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:paddingLeft="@dimen/activity_horizontal_margin"
- android:paddingRight="@dimen/activity_horizontal_margin"
- android:paddingTop="@dimen/activity_vertical_margin"
- android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">
- <EditText
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:id="@+id/editText"
- android:layout_alignParentTop="true"
- android:layout_alignParentRight="true"
- android:layout_alignParentEnd="true"
- android:layout_alignParentLeft="true"
- android:layout_alignParentStart="true" />
- <Button
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="Begin"
- android:id="@+id/buttonStart"
- android:layout_below="@+id/editText"
- android:layout_alignParentLeft="true"
- android:layout_alignParentStart="true"
- android:onClick="onClickStart"/>
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:id="@+id/textView"
- android:layout_below="@+id/buttonSend"
- android:layout_alignParentLeft="true"
- android:layout_alignParentStart="true"
- android:layout_alignRight="@+id/editText"
- android:layout_alignEnd="@+id/editText"
- android:layout_alignParentBottom="true" />
- </RelativeLayout>
复制代码
我在这里使用了RelativeLayout,这意味着每个小部件都是根据它周围的小部件进行排列的。可以使用Design Tab轻松地重新创建布局,您可以在其中将窗口小部件拖放到任何位置。单击按钮时,我们必须描述需要执行的操作。为此,使用OnClick方法。在按钮的XML中指定方法的名称。为此,请添加以下行: - android:onClick="onClickMethod"
复制代码
现在将鼠标悬停在此行上,左侧会弹出一条警告,如下所示:
单击“创建'OnClick ...”。这将自动为MainActivity.java中的onClick方法注入代码。您必须为每个按钮执行此操作。
USB串行库 在Android中设置串行连接是一件非常麻烦的事情,因为它需要你手动配置很多东西,所以我一直在寻找一些自动完成这一切的库。我测试了其中的一些,最后由Github用户felHR85定位于UsbSerial库。在我找到的所有相关库中,这是唯一一个仍在更新的库。它很容易设置和使用。要将此库添加到项目中,请从Github下载最新的JAR文件。将其移动到项目目录中的“libs”文件夹。然后,在Android Studio的文件浏览器中,右键单击JAR并选择“添加为库”。
程序流程
这是我们将如何进行的简要概述。每个活动都有一个onCreate()方法,该方法是在创建活动时运行的。无论您想要在开始时运行什么代码都必须放在其中。请注意,从设备读取是异步的,这意味着它将继续在后台运行。这样做是为了尽快收到数据。
打开连接 首先,让我们为Begin按钮定义onClick方法。单击时,它应搜索所有连接的设备,然后检查Arduino的供应商ID是否与连接的设备的供应商ID相匹配。如果找到,则必须向用户请求许可。每个USB从设备都有一个供应商和产品ID,可用于识别应该使用哪些驱动程序。任何Arduino的供应商ID都是0x2341或9025。 - public void onClickStart(View view) {
- HashMap usbDevices = usbManager.getDeviceList();
- if (!usbDevices.isEmpty()) {
- boolean keep = true;
- for (Map.Entry entry : usbDevices.entrySet()) {
- device = entry.getValue();
- int deviceVID = device.getVendorId();
- if (deviceVID == 0x2341)//Arduino Vendor ID
- {
- PendingIntent pi = PendingIntent.getBroadcast(this, 0,
- new Intent(ACTION_USB_PERMISSION), 0);
- usbManager.requestPermission(device, pi);
- keep = false;
- } else {
- connection = null;
- device = null;
- }
- if (!keep)
- break;
- }
- }
- }
复制代码
现在让我们定义BroadcastReceiver来接收广播以询问用户权限,并在连接设备时自动启动连接,并在断开连接时关闭连接。 - private final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() { //Broadcast Receiver to automatically start and stop the Serial connection.
- @Override
- public void onReceive(Context context, Intent intent) {
- if (intent.getAction().equals(ACTION_USB_PERMISSION)) {
- boolean granted =
- intent.getExtras().getBoolean(UsbManager.EXTRA_PERMISSION_GRANTED);
- if (granted) {
- connection = usbManager.openDevice(device);
- serialPort = UsbSerialDevice.createUsbSerialDevice(device, connection);
- if (serialPort != null) {
- if (serialPort.open()) { //Set Serial Connection Parameters.
- setUiEnabled(true); //Enable Buttons in UI
- serialPort.setBaudRate(9600);
- serialPort.setDataBits(UsbSerialInterface.DATA_BITS_8);
- serialPort.setStopBits(UsbSerialInterface.STOP_BITS_1);
- serialPort.setParity(UsbSerialInterface.PARITY_NONE);
- serialPort.setFlowControl(UsbSerialInterface.FLOW_CONTROL_OFF);
- serialPort.read(mCallback); //
- tvAppend(textView,"Serial Connection Opened!\n");
- } else {
- Log.d("SERIAL", "PORT NOT OPEN");
- }
- } else {
- Log.d("SERIAL", "PORT IS NULL");
- }
- } else {
- Log.d("SERIAL", "PERM NOT GRANTED");
- }
- } else if (intent.getAction().equals(UsbManager.ACTION_USB_DEVICE_ATTACHED)) {
- onClickStart(startButton);
- } else if (intent.getAction().equals(UsbManager.ACTION_USB_DEVICE_DETACHED)) {
- onClickStop(stopButton);
- }
- };
- };
复制代码
如果满足第一个IF条件,并且用户已授予权限,则为其供应商ID与我们所需的供应商ID匹配的设备启动连接。 此外,如果收到设备附加或分离的广播,请手动调用onClick方法以启动和停止按钮。 使用设备作为连接作为参数定义SerialPort。 如果成功,请打开SerialPort并相应地设置参数。 对于Uno,默认参数为8个数据位,1个停止位,无奇偶校验位且流量控制为关闭。 波特率可以是300,600,1200,2400,4800,9600,14400,19200,28800,38400,57600或115200,但我们使用标准9600。
从设备接收数据 在上面的代码片段中,注意说明serialPort.read(mCallback)的行。 这里将Callback的引用传递给read函数,以便在检测到任何传入数据时自动触发。 - UsbSerialInterface.UsbReadCallback mCallback = new UsbSerialInterface.UsbReadCallback() {
- //Defining a Callback which triggers whenever data is read.
- @Override
- public void onReceivedData(byte[] arg0) {
- String data = null;
- try {
- data = new String(arg0, "UTF-8");
- data.concat("/n");
- tvAppend(textView, data);
- } catch (UnsupportedEncodingException e) {
- e.printStackTrace();
- }
- }
- };
复制代码
收到的数据将采用原始字节的形式。我们必须将其重新编码为可读格式,如UTF-8。然后使用名为tvAppend()的自定义方法将其附加到TextView。这样做是因为对UI的任何更改只能在UI线程上进行。由于此Callback将作为后台线程运行,因此它不会直接影响UI。 - private void tvAppend(TextView tv, CharSequence text) { final TextView ftv = tv; final CharSequence ftext = text; runOnUiThread(new Runnable() { @Override public void run() { ftv.append(ftext); } }); }
复制代码
将数据发送到设备 与从设备读取数据相比,发送数据相对容易。这是一个简单的函数调用,需要将数据字节作为参数发送。这将在发送按钮的OnClick方法中定义。 - serialPort.write(string.getBytes());
复制代码
关闭连接 要关闭连接,只需关闭SerialPort即可。
应用程序清单 在清单中,说明应用可能需要的额外权限。唯一需要的是允许将手机变为USB主机。将以下内容添加到清单: - <uses-feature android:name="android.hardware.usb.host" />
复制代码
通过向MainActivity添加IntentFilter,可以使应用程序自动启动。连接任何新设备时将触发此IntentFilter。可以通过在XML文件中提供供应商ID和/或产品ID来明确指定设备的类型。 - <?xml version="1.0" encoding="utf-8"?>
- <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" />
- </activity>
复制代码
注意行“android:resource =”@ xml / device_filter“。这告诉编译器它可以在src / main / res / xml中名为device_filter的文件中找到设备属性,所以在src中创建一个名为”xml“的文件夹/ main / res并在其中加入以下内容: - <resources>
- <usb-device vendor-id="9025" />
- <!-- Vendor ID of Arduino -->
- </resources>
复制代码
测试应用程序
在智能手机上构建并运行应用程序。现在启动Arduino IDE并设置Arduino以简单地回显它在串行端口上收到的任何内容。这是一个非常简单的代码。 - void setup()
- {
- Serial.begin(9600);
- }
- void loop()
- {
- char c;
- if(Serial.available())
- {
- c = Serial.read();
- Serial.print(c);
- }
- }
复制代码
现在使用OTG电缆将Arduino连接到microUSB端口。该应用必须自动启动。尝试发送一些文本,然后将‘返回相同的数据!
总结 本文主要展示了Arduino开发板如何与您的智能手机通讯。这用途是无穷无尽的!如果需要来自一些传感器的数据,并且如果智能手机上没有这些数据,则可以使用微控制器从该传感器读取数据,并将数据传输到手机。 |