Связаться с нами

  • (097) ?601-88-87
    (067) ?493-44-27
    (096) ?830-00-01

Статьи

Передача даних по Bluetooth між Android і Arduino

  1. Arduino
  2. Android - передаємо дані в Arduino
  3. Android - прийом і передача даних до Arduino

у статті Arduino і Bluetooth було розглянуто один із способів передачі інформації між Android-пристроєм і ПК по Bluetooth-з'єднанню. Там же, в двох словах було згадано і Android-пристрій, але для прийняття і передачі даних використовувався Android Bluetooth термінал. Однак, для реальних пристроїв необхідна повноцінна програма (думати ж ми управляти тим же роботом з терміналу ...), написана для Android'а. У даній статті хотілося б торкнутися теми програмного забезпечення для роботи з Bluetooth, із застосуванням мови Java і середовища розробки Eclipse. Установка і настройка Eclipse добре описана в цій статті: Android і Arduino. Програмне забезпечення .

Arduino

Я буду використовувати Bluetooth модуль HC-06, проте для інших модулів HC-04, HC-05 і т.п. схема підключення така ж (за винятком світлодіода). Плата Arduino Nano V3.

Для наочності, до плати Arduino я підключив червоний світлодіод, до 12-піну, але можна використовувати і вбудований LED (зазвичай 13 пін).

Скетч для Arduino наступний:

char incomingByte; // вхідні дані int LED = 12; // LED підключений до 12 піну void setup () {Serial.begin (9600); // ініціалізація порту pinMode (LED, OUTPUT); Serial.println ( "Press 1 to LED ON or 0 to LED OFF ..."); } Void loop () {if (Serial.available ()> 0) {// якщо прийшли дані incomingByte = Serial.read (); // зчитуємо байт if (incomingByte == '0') {digitalWrite (LED, LOW); // якщо 1, то вимикаємо LED Serial.println ( "LED OFF. Press 1 to LED ON!"); // і виводимо назад повідомлення} if (incomingByte == '1') {digitalWrite (LED, HIGH); // якщо 0, то включаємо LED Serial.println ( "LED ON. Press 0 to LED OFF!"); }}}

Програма працює дуже просто. Після запуску або скидання пристрою, в послідовний порт виводиться повідомлення з пропозицією натиснути 1 або 0. Залежно від натиснутої (прийнятої) цифри світлодіод буде загорятися або гаснути. Загалом програма абсолютно така ж як і в статті: Arduino і Bluetooth.

Тепер, що стосується Android. Ми розглянемо два приклади, в першому ми будемо передавати дані від Android-пристрої до arduino, а в другому прикладі ми розглянемо двосторонній обмін даними між пристроями. Другий приклад складніше і в частині розуміння і за складністю коду, тому що використовуються потоки (thread).

Ми будемо використовувати Java код, з явним зазначенням MAC-адресу свого пристрою, до якого ми будемо підключатися. Оскільки якщо робити інтерфейс виявлення Bluetooth-пристроїв, їх вибору, підключення до них і т.д., то код буде дуже великий і для деяких читачів важкозрозумілі. Але для тих, кому цікаво можуть подивитися стандартний приклад Bluetooth Chat.

Дізнатися MAC-адресу можна наприклад в програмі для Android'а: Bluetooth Terminal:

Нас цікавить пристрій BOLUTEK (наш модуль HC-06, підключений до Arduino), його MAC адресу: 00: 15: FF: F2: 19: 4C. Його і треба буде надалі прописати в програмі.

Android - передаємо дані в Arduino

Перша програма дуже проста, головне вікно активують буде містити 2 кнопки: включити LED і вимкнути LED. При натисканні на кнопку включення LED, по Bluetooth буде передаватися "1", при натисканні на вимикання LED - "0".

У файлі маніфесту необхідно прописати 2 рядки дозволу роботи з Bluetooth:

Сам код головного активують:

package com.example.bluetooth1; import java.io.IOException; import java.io.OutputStream; import java.util.UUID; import com.example.bluetooth1.R; import android.app.Activity; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothSocket; import android.content.Intent; import android.os.Bundle; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.Toast; public class MainActivity extends Activity {private static final String TAG = "bluetooth1"; Button btnOn, btnOff; private static final int REQUEST_ENABLE_BT = 1; private BluetoothAdapter btAdapter = null; private BluetoothSocket btSocket = null; private OutputStream outStream = null; // SPP UUID сервісу private static final UUID MY_UUID = UUID.fromString ( "00001101-0000-1000-8000-00805F9B34FB"); // MAC-адресу Bluetooth модуля private static String address = "00: 15: FF: F2: 19: 4C"; / ** Called when the activity is first created. * / @Override public void onCreate (Bundle savedInstanceState) {super.onCreate (savedInstanceState); setContentView (R.layout.activity_main); btnOn = (Button) findViewById (R.id.btnOn); btnOff = (Button) findViewById (R.id.btnOff); btAdapter = BluetoothAdapter.getDefaultAdapter (); checkBTState (); btnOn.setOnClickListener (new OnClickListener () {public void onClick (View v) {sendData ( "1"); Toast.makeText (getBaseContext (), "Включаємо LED", Toast.LENGTH_SHORT) .show ();}}); btnOff.setOnClickListener (new OnClickListener () {public void onClick (View v) {sendData ( "0"); Toast.makeText (getBaseContext (), "Вимикаємо LED", Toast.LENGTH_SHORT) .show ();}}); } @Override public void onResume () {super.onResume (); Log.d (TAG, "... onResume - спроба з'єднання ..."); // Set up a pointer to the remote node using it's address. BluetoothDevice device = btAdapter.getRemoteDevice (address); // Two things are needed to make a connection: // A MAC address, which we got above. // A Service ID or UUID. In this case we are using the // UUID for SPP. try {btSocket = device.createRfcommSocketToServiceRecord (MY_UUID); } Catch (IOException e) {errorExit ( "Fatal Error", "In onResume () and socket create failed:" + e.getMessage () + "."); } // Discovery is resource intensive. Make sure it is not going on // when you attempt to connect and pass your message. btAdapter.cancelDiscovery (); // Establish the connection. This will block until it connects. Log.d (TAG, "... Єднаймося ..."); try {btSocket.connect (); Log.d (TAG, "... З'єднання встановлено і готове до передачі даних ..."); } Catch (IOException e) {try {btSocket.close (); } Catch (IOException e2) {errorExit ( "Fatal Error", "In onResume () and unable to close socket during connection failure" + e2.getMessage () + "."); }} // Create a data stream so we can talk to server. Log.d (TAG, "... Створення Socket ..."); try {outStream = btSocket.getOutputStream (); } Catch (IOException e) {errorExit ( "Fatal Error", "In onResume () and output stream creation failed:" + e.getMessage () + "."); }} @Override public void onPause () {super.onPause (); Log.d (TAG, "... In onPause () ..."); if (outStream! = null) {try {outStream.flush (); } Catch (IOException e) {errorExit ( "Fatal Error", "In onPause () and failed to flush output stream:" + e.getMessage () + "."); }} Try {btSocket.close (); } Catch (IOException e2) {errorExit ( "Fatal Error", "In onPause () and failed to close socket." + E2.getMessage () + "."); }} Private void checkBTState () {// Check for Bluetooth support and then check to make sure it is turned on // Emulator does not support Bluetooth and will return null if (btAdapter == null) {errorExit ( "Fatal Error" , "Bluetooth не підтримує"); } Else {if (btAdapter.isEnabled ()) {Log.d (TAG, "... Bluetooth включений ..."); } Else {// Prompt user to turn on Bluetooth Intent enableBtIntent = new Intent (btAdapter.ACTION_REQUEST_ENABLE); startActivityForResult (enableBtIntent, REQUEST_ENABLE_BT); }}} Private void errorExit (String title, String message) {Toast.makeText (getBaseContext (), title + "-" + message, Toast.LENGTH_LONG) .show (); finish (); } Private void sendData (String message) {byte [] msgBuffer = message.getBytes (); Log.d (TAG, "... Надсилаємо дані:" + message + "..."); try {outStream.write (msgBuffer); } Catch (IOException e) {String msg = "In onResume () and an exception occurred during write:" + e.getMessage (); if (address.equals ( "00: 00: 00: 00: 00: 00")) msg ​​= msg + ". \ n \ nВ змінної address у вас прописаний 00: 00: 00: 00: 00: 00, вам необхідно прописати реальний MAC-адресу Bluetooth модуля "; msg = msg + ". \ n \ nПроверьте підтримку SPP UUID:" + MY_UUID.toString () + "на Bluetooth модулі, до якого ви підключаєтеся. \ n \ n"; errorExit ( "Fatal Error", msg); }}}

Даний код знайдений на одному із зарубіжних блогів і злегка модернізований. Як видно вище, на кнопки ми вішаємо обробники подій. При натисканні на кнопку передається рядок 1 або 0 через sendData () в буфер Bluetooth адаптера. Повний проект з початковими кодами наведено нижче. Для роботи програми, необхідний Android не нижче версії API15, тобто 4.0.3 і вище.

Android - прийом і передача даних до Arduino

А ось тут довелося повозитися. Справа в тому, що в Android'е для прийому даних від будь-якого пристрою необхідно створювати окремий фоновий потік, щоб у нас не зависала основне активують. Для цього ми задіємо thread і всі дані будуть прийматися в окремому потоці.

На вікно головного активують ми додамо новий елемент TextView, який буде служити для відображення отриманих даних від Arduino. Сам java-код головного активують я постарався добре прокоментувати, щоб зробити його легким для читання:

package com.example.bluetooth2; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.UUID; import com.example.bluetooth2.R; import android.app.Activity; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothSocket; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView; import android.widget.Toast; public class MainActivity extends Activity {private static final String TAG = "bluetooth2"; Button btnOn, btnOff; TextView txtArduino; Handler h; private static final int REQUEST_ENABLE_BT = 1; final int RECIEVE_MESSAGE = 1; // Статус для Handler private BluetoothAdapter btAdapter = null; private BluetoothSocket btSocket = null; private StringBuilder sb = new StringBuilder (); private ConnectedThread mConnectedThread; // SPP UUID сервісу private static final UUID MY_UUID = UUID.fromString ( "00001101-0000-1000-8000-00805F9B34FB"); // MAC-адресу Bluetooth модуля private static String address = "00: 15: FF: F2: 19: 4C"; / ** Called when the activity is first created. * / @Override public void onCreate (Bundle savedInstanceState) {super.onCreate (savedInstanceState); setContentView (R.layout.activity_main); btnOn = (Button) findViewById (R.id.btnOn); // кнопка включення btnOff = (Button) findViewById (R.id.btnOff); // кнопка виключення txtArduino = (TextView) findViewById (R.id.txtArduino); // для виведення тексту, отриманого від Arduino h = new Handler () {public void handleMessage (android.os.Message msg) {switch (msg.what) {case RECIEVE_MESSAGE: // якщо прийняли повідомлення в Handler byte [] readBuf = (byte []) msg.obj; String strIncom = new String (readBuf, 0, msg.arg1); sb.append (strIncom); // формуємо рядок int endOfLineIndex = sb.indexOf ( "\ r \ n"); // визначаємо символи кінця рядка if (endOfLineIndex> 0) {// якщо зустрічаємо кінець рядка, String sbprint = sb.substring (0, endOfLineIndex); // то витягаємо рядок sb.delete (0, sb.length ()); // і очищаємо sb txtArduino.setText ( "Відповідь від Arduino:" + sbprint); // оновлюємо TextView btnOff.setEnabled (true); btnOn.setEnabled (true); } //Log.d(TAG, "... Рядок:" + sb.toString () + "Байт:" + msg.arg1 + "..."); break; }}; }; btAdapter = BluetoothAdapter.getDefaultAdapter (); // отримуємо локальний Bluetooth адаптер checkBTState (); btnOn.setOnClickListener (new OnClickListener () {// визначаємо обробник при натисканні на кнопку public void onClick (View v) {btnOn.setEnabled (false); mConnectedThread.write ( "1"); // Відправляємо через Bluetooth цифру 1 // Toast.makeText (getBaseContext (), "Включаємо LED", Toast.LENGTH_SHORT) .show ();}}); btnOff.setOnClickListener (new OnClickListener () {public void onClick (View v) {btnOff.setEnabled (false); mConnectedThread.write ( "0"); // Відправляємо через Bluetooth цифру 0 //Toast.makeText (getBaseContext (), "Вимикаємо LED", Toast.LENGTH_SHORT) .show ();}}); } @Override public void onResume () {super.onResume (); Log.d (TAG, "... onResume - спроба з'єднання ..."); // Set up a pointer to the remote node using it's address. BluetoothDevice device = btAdapter.getRemoteDevice (address); // Two things are needed to make a connection: // A MAC address, which we got above. // A Service ID or UUID. In this case we are using the // UUID for SPP. try {btSocket = device.createRfcommSocketToServiceRecord (MY_UUID); } Catch (IOException e) {errorExit ( "Fatal Error", "In onResume () and socket create failed:" + e.getMessage () + "."); } // Discovery is resource intensive. Make sure it is not going on // when you attempt to connect and pass your message. btAdapter.cancelDiscovery (); // Establish the connection. This will block until it connects. Log.d (TAG, "... Єднаймося ..."); try {btSocket.connect (); Log.d (TAG, "... З'єднання встановлено і готове до передачі даних ..."); } Catch (IOException e) {try {btSocket.close (); } Catch (IOException e2) {errorExit ( "Fatal Error", "In onResume () and unable to close socket during connection failure" + e2.getMessage () + "."); }} // Create a data stream so we can talk to server. Log.d (TAG, "... Створення Socket ..."); mConnectedThread = new ConnectedThread (btSocket); mConnectedThread.start (); } @Override public void onPause () {super.onPause (); Log.d (TAG, "... In onPause () ..."); try {btSocket.close (); } Catch (IOException e2) {errorExit ( "Fatal Error", "In onPause () and failed to close socket." + E2.getMessage () + "."); }} Private void checkBTState () {// Check for Bluetooth support and then check to make sure it is turned on // Emulator does not support Bluetooth and will return null if (btAdapter == null) {errorExit ( "Fatal Error" , "Bluetooth не підтримує"); } Else {if (btAdapter.isEnabled ()) {Log.d (TAG, "... Bluetooth включений ..."); } Else {// Prompt user to turn on Bluetooth Intent enableBtIntent = new Intent (btAdapter.ACTION_REQUEST_ENABLE); startActivityForResult (enableBtIntent, REQUEST_ENABLE_BT); }}} Private void errorExit (String title, String message) {Toast.makeText (getBaseContext (), title + "-" + message, Toast.LENGTH_LONG) .show (); finish (); } Private class ConnectedThread extends Thread {private final BluetoothSocket mmSocket; private final InputStream mmInStream; private final OutputStream mmOutStream; public ConnectedThread (BluetoothSocket socket) {mmSocket = socket; InputStream tmpIn = null; OutputStream tmpOut = null; // Get the input and output streams, using temp objects because // member streams are final try {tmpIn = socket.getInputStream (); tmpOut = socket.getOutputStream (); } Catch (IOException e) {} mmInStream = tmpIn; mmOutStream = tmpOut; } Public void run () {byte [] buffer = new byte [256]; // buffer store for the stream int bytes; // bytes returned from read () // Keep listening to the InputStream until an exception occurs while (true) {try {// Read from the InputStream bytes = mmInStream.read (buffer); // Отримуємо кількість байт і саме собщение в байтовий масив "buffer" h.obtainMessage (RECIEVE_MESSAGE, bytes, -1, buffer) .sendToTarget (); // Відправляємо в чергу повідомлень Handler} catch (IOException e) {break; }}} / * Call this from the main activity to send data to the remote device * / public void write (String message) {Log.d (TAG, "... Дані для відправки:" + message + "... "); byte [] msgBuffer = message.getBytes (); try {mmOutStream.write (msgBuffer); } Catch (IOException e) {Log.d (TAG, "... Помилка відправки даних:" + e.getMessage () + "..."); }} / * Call this from the main activity to shutdown the connection * / public void cancel () {try {mmSocket.close (); } Catch (IOException e) {}}}}

В даному прикладі для відправки даних ми використовуємо окремий потік Thread. Теж саме і для прийому даних - метод run (). Також зверніть увагу на клас Handler, який служить для організації черги повідомлень і їх виведення в головне активують. Справа в тому, що в фоновому потоці можна безпосередньо виводити щось в головне активують, тому що це призведе до "фарбую" програми.
Клас StringBuilder використовується для формування рядки з прийнятих даних. Після, відбувається пошук кінця рядка з символами \ r \ n, і якщо вони знайдені, то рядок відображається на активують і об'єкт sb очищається, щоб не сталося склейка з подальшими прийнятими даними.

До статті додаються скомпільовані файли для Android: bluetooth1.apk і bluetooth2.apk, а також вихідні проекту для Arduino IDE і Eclipse

Прикріплені файли:

Теги:

Новости

Как сделать красивую снежинку из бумаги
Красивые бумажные снежинки станут хорошим украшением дома на Новый год. Они создадут в квартире атмосферу белоснежной, зимней сказки. Да и просто занимаясь вырезанием из бумаги снежинок разнообразной

Пиротехника своими руками в домашних
Самые лучшие полезные самоделки рунета! Как сделать самому, мастер-классы, фото, чертежи, инструкции, книги, видео. Главная САМОДЕЛКИ Дизайнерские

Фольгированные шары с гелием
Для начала давайте разберемся и чего же выполнен фольгированный шар и почему он летает дольше?! Как вы помните, наши латексные шарики достаточно пористые, поэтому их приходится обрабатывать специальным

Все товары для праздника оптом купить
Как сделать правильный выбор в работе, бизнесе и жизни, о котором никогда не придется жалеть. Мы хотим рассказать вам об удивительной и очень простой технике 7 вопросов, которые позволят оценить ситуацию

2400 наименований пиротехники
В последние десятилетия наша страна может похвастаться появлением нескольких десятков отечественных производителей, специализирующихся на выпуске пиротехники. Если вы сомневаетесь, какой фейерверк заказать,

Как сделать из бумаги самолет
 1. Самолеты сделанный по первой и второй схеме являются самыми распространенными. Собирается такое оригами своими руками достаточно быстро, несмотря на это самолет летит достаточно далеко за счет свое

Надувные шарики с гелием с доставкой
На праздники часто бывают востребованы воздушные шарики, надутые гелием. Обычно, их покупают уже готовыми (надутыми) и привозят на праздник. Или, приглашают специалистов, которые приезжают и надувают

Аниматоры на детские праздники в Зеленограде
Уж сколько раз твердили миру…Что готовиться ко дню рождения нужно заранее, а не бегать в предпраздничный день угорелой кошкой. Нельзя впихнуть в 24 часа дела, рассчитанные на недели. К празднику нужно