В 3-ей части статьи нами был рассмотрен проект для передачи данных от Android-устройства в ADK-плату. Сейчас мы рассмотрим обратную задачу.
Но для того, чтобы немного усложнить наш пример, мы немного усложним нашу задачу. Передавать в Android Нужно будет 2 переменные: первая будет содержать случайное число, а вторая — состояние нажатия кнопки. На Android устройстве первая переменная будет отображаться простым текстом, а вторая будет влиять на переключатель. Т.е. если кнопка, подключенная к плате Arduino ADK нажата, то и переключатель на Android устройстве будет включен.
Программа для Arduino
Скетч для Arduino будет следующий:
#include #include // Adb connection. Connection * connection; long lastTime; byte rndNum; // Случайное число int buttonState = 0; // Состояние кнопки uint16_t tosend; // Данные для передачи в Android const int buttonPin = 2; // PIN-подключенной кнопки void setup() { pinMode(buttonPin, INPUT); // Инициализация подсистемы ADB. ADB::init(); // Open an ADB stream to the phone's shell. Auto-reconnect. Use any unused port number eg:4568 connection = ADB::addConnection("tcp:4568", true, NULL); //Serial.begin(115200); randomSeed(analogRead(0)); // Для генератора случайных чисел (чтобы не повторялись значения) } void loop() { if ((millis() - lastTime) > 100) // Условие выполняется каждые 100 мс { rndNum = random(1, 99); // Генерируем случайное число от 1 до 99 buttonState = digitalRead(buttonPin); // Считываем состояние цифр. входа tosend = (rndNum << 8) | buttonState; // Формируем слово из 2-х байт Serial.println(tosend,BIN); connection->write(2,(uint8_t*)&tosend); // Отсылаем 2 байта lastTime = millis(); } // Poll the ADB subsystem. ADB::poll(); }
Код я постарался хорошо прокомментировать, поэтому расписывать подробно его не буду. Здесь используется основная функция connection->write(), которая отсылает данные по USB кабелю через TCP на Android устройство. В функции передается 2 параметра, первый — кол-во байт для пересылки, второй — сами данные. Обратите, внимание, что предварительно, мы упаковали 2 байта данных в 2-х байтовое слово.
Компилируем скетч и загружаем его в нашу плату.
Программа для Android
Создание проекта, настройку манифест файла вы можете посмотреть в предыдущей статье.
Немного про активити. В прошлый раз я говорил, что activity можно создавать при помощи графического интерфейса и при помощи XML файла. В этот раз я приведу XML-файл нашего активити (см. в файлах)
Ключевыми элементами здесь являются switch1 (переключатель) и textView2 (текстовое поле). Вот что должно получиться:
Теперь открываем файл /src/com/example/arduino53/MainActivity.java, все в нем удаляем и копируем следующие строки:
package com.example.arduino53; import java.io.IOException; import org.microbridge.server.Server; import org.microbridge.server.AbstractServerListener; import android.os.AsyncTask; import android.os.Bundle; import android.app.Activity; import android.util.Log; import android.widget.Switch; import android.widget.TextView; public class MainActivity extends Activity { private int Ard_data1 = 0; private int Ard_data2 = 0; public final String APP_NAME = "arduino53"; Server server = null; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Создаем TCP сервер (на основе сервера MicroBridge LightWeight) try { server = new Server(4568); //Этот же порт необходимо использовать и на ADK-плате server.start(); } catch (IOException e) { Log.e(APP_NAME, "Unable to start TCP server", e); System.exit(-1); } server.addListener(new AbstractServerListener() { @Override public void onReceive(org.microbridge.server.Client client, byte[] data) { Log.d(APP_NAME, "data0:"+data[0]+"; data1:"+data[1]); if (data.length<2) Log.e(APP_NAME, "Размер данных менее 2-х байт:"+data.length); Ard_data1 = data[0]; Ard_data2 = data[1]; //Any update to UI can not be carried out in a non UI thread like the one used //for Server. Hence runOnUIThread is used. runOnUiThread(new Runnable() { //@Override public void run() { new UpdateData().execute(Ard_data1,Ard_data2); } }); } }); } @Override protected void onDestroy (){ super.onDestroy(); server.stop(); } class UpdateData extends AsyncTask { // Called to initiate the background activity @Override protected Integer[] doInBackground(Integer... ArdState) { return (ArdState); //Возвращаем в onPostExecute() } @Override protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); // Not used in this case } @Override protected void onPostExecute(Integer... result) { //Log.d(APP_NAME, "onPostExecute0:"+result[0]); //Log.d(APP_NAME, "onPostExecute1:"+result[1]); TextView txt_btn_Arduino = (TextView) findViewById(R.id.textView2); txt_btn_Arduino.setText(String.valueOf(result[1])); // Выводим на activity RND число полученное от ADK Switch switch1 = (Switch) findViewById(R.id.switch1); if(result[0] == 1){ switch1.setChecked(true); } else switch1.setChecked(false); } } }
Здесь мы для класса server определяем метод server.addListener(new AbstractServerListener() {}), а также onReceive() который вызывается каждый раз, при получении данных от сервера MicroBridge.
Затем мы создаем новый поток. Для этого используется класс AsyncTask с тремя методами (всего их 4, но мы один из них не используем):
doInBackground() — выполняется в фоновом потоке. Здесь необходимо производить сложные вычисления, но мы здесь ничего не делаем, а просто возвращаем объект в метод onPostExecute()
onProgressUpdate() — используется для ввода промежуточных результатов (в нашей программе не задействован)
onPostExecute() — выполняется после метода doInBackground(). В нем мы принимаем данные в массив result и отображаем данные на экране устройства в элементе TextView, а также двигаем переключатель Switch в зависимости от положения нажатой внешней кнопки.
Обращаю ваше внимание, что создание UI элементов в классе AsyncTask возможно только в методе onPostExecute().
Ниже вы можете скачать проекты для Arduino и Android, а также все необходимые библиотеки