Android + Bluetooth + Arduino

Android + Bluetooth + Arduino

Android-приложение для обмена данными с ардуино при помощи bluetooth-модуля HC-05.



Приложение будет отправлять ардуине команды включения-отключения D10...D13, а та, в свою очередь, сообщать о выполненных действиях.





Прежде чем приступать к написанию приложения, необходимо проверить настройки bluetooth-модуля и подключить его к ардуине.

Настройка модуля подробно описана здесь, проделайте всё, что написано в разделе Bluetooth до фразы "Модуль настроен".


После настройки заливаем в ардуину код…


char incomingbyte; // переменная для приема данных

void setup() 
 {
   Serial.begin(9600); 
   pinMode(10, OUTPUT);
   pinMode(11, OUTPUT);
   pinMode(12, OUTPUT);
   pinMode(13, OUTPUT);
 }


void loop() 
 {
  if(Serial.available() > 0) // есть ли что-то в буфере
   {
     incomingbyte = Serial.read(); // чтение символа

     switch (incomingbyte)
       {  
         case 'A': 
         digitalWrite(10,HIGH);
         Serial.println("D10 ON");
         break;

         case 'a': 
         digitalWrite(10,LOW);
         Serial.println("D10 OFF");
         break;


         case 'B': 
         digitalWrite(11,HIGH);
         Serial.println("D11 ON");
         break;

         case 'b': 
         digitalWrite(11,LOW);
         Serial.println("D11 OFF");
         break;


         case 'C': 
         digitalWrite(12,HIGH);
         Serial.println("D12 ON");
         break;

         case 'c': 
         digitalWrite(12,LOW);
         Serial.println("D12 OFF");
         break;


         case 'D': 
         digitalWrite(13,HIGH);
         Serial.println("D13 ON");
         break;

         case 'd': 
         digitalWrite(13,LOW);
         Serial.println("D13 OFF");
         break;

         default:
         break;

       }
   }
}

Ардуина получает символы от андройд-приложения, выполняет действие и возвращает ответ. Обратите внимание на скорость Serial.begin(9600), она должна совпадать с настройками модуля.



… и соединяем её с модулем по этой схеме:





Выполните сопряжение телефона с модулем.




Android



Кто не хочет обременять себя написанием приложения, может скачать готовый apk-файл, а если есть желание попрограммировать тогда...


Скачиваем, устанавливаем и запускаем Android Studio.



В процессе работы нужно будет установить sdk.


Создаём новый проект под названием BlueArdu


Next...


Оставляем как есть…


Next...


Выбираем Empty Activity


Next...


Оставляем как есть…


Finish


Открываем файл AndroidManifest.xml




После строчки package=«com.example.dima.blueardu» > добавляем разрешение на использование bluetooth:


<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>


Строку <activity android:name=".MainActivity" > делаем так:

<activity android:name=".MainActivity" android:screenOrientation="portrait">

Портретная ориентация.


В результате будет так:





Кликаем по вкладке activity_main.xml и внизу выбираем вкладку Text




Удаляем всё, что там написано и вставляем вот это:


<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"

    tools:context=".MainActivity"
    android:id="@+id/osnova"
    android:background="#e7e8ea"
    android:contextClickable="true">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/textInfo"
        android:textSize="22dp"
        android:layout_marginLeft="20dp"
        android:layout_marginTop="20dp"
        android:visibility="visible" />

    <ListView
        android:layout_width="250dp"
        android:layout_height="wrap_content"
        android:id="@+id/pairedlist"
        android:layout_below="@+id/textInfo"
        android:layout_alignParentStart="true"
        android:layout_marginTop="30dp"

        android:layout_marginLeft="20dp"
        android:visibility="visible" />

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#e7e7e5"
        android:id="@+id/ButPanel"
        android:visibility="gone">


        <!--D10-->
        <ImageButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/imageButton"
            android:layout_gravity="left|top"
            android:src="@drawable/offlamp"
            android:layout_marginTop="20dp"
            android:layout_marginLeft="30dp"
            android:onClick="onClickBut1" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="D10"
            android:id="@+id/d10"
            android:layout_gravity="center_horizontal|top"
            android:textSize="30dp"
            android:layout_marginTop="30dp" />

        <ImageButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/imageButton2"
            android:layout_gravity="right|top"
            android:layout_marginTop="20dp"
            android:layout_marginRight="30dp"
            android:src="@drawable/onlamp"
            android:onClick="onClickBut2" />


        <!--D11-->
        <ImageButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/imageButton3"
            android:layout_gravity="left|top"
            android:src="@drawable/offlamp"
            android:layout_marginTop="100dp"
            android:layout_marginLeft="30dp"
            android:onClick="onClickBut3" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="D11"
            android:id="@+id/d11"
            android:layout_gravity="center_horizontal|top"
            android:textSize="30dp"
            android:layout_marginTop="110dp" />

        <ImageButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/imageButton4"
            android:layout_gravity="right|top"
            android:layout_marginTop="100dp"
            android:layout_marginRight="30dp"
            android:src="@drawable/onlamp"
            android:onClick="onClickBut4" />


        <!--D12-->
        <ImageButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/imageButton5"
            android:layout_gravity="left|top"
            android:src="@drawable/offlamp"
            android:layout_marginTop="180dp"
            android:layout_marginLeft="30dp"
            android:onClick="onClickBut5" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="D12"
            android:id="@+id/d12"
            android:layout_gravity="center_horizontal|top"
            android:textSize="30dp"
            android:layout_marginTop="190dp" />

        <ImageButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/imageButton6"
            android:layout_gravity="right|top"
            android:layout_marginTop="180dp"
            android:layout_marginRight="30dp"
            android:src="@drawable/onlamp"
            android:onClick="onClickBut6" />


        <!--D13-->
        <ImageButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/imageButton7"
            android:layout_gravity="left|top"
            android:src="@drawable/offlamp"
            android:layout_marginTop="260dp"
            android:layout_marginLeft="30dp"
            android:onClick="onClickBut7" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="D13"
            android:id="@+id/d13"
            android:layout_gravity="center_horizontal|top"
            android:textSize="30dp"
            android:layout_marginTop="270dp" />

        <ImageButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/imageButton8"
            android:layout_gravity="right|top"
            android:layout_marginTop="260dp"
            android:layout_marginRight="30dp"
            android:src="@drawable/onlamp"
            android:onClick="onClickBut8" />

    </FrameLayout>

</RelativeLayout>




Красным цветом подсвечиваются ошибки. В данном случае среда сообщает об отсутствии картинок offlamp и onlamp




Сохраните картинки себе на компьютер. После этого скопируйте offlamp.png в буфер (правой кнопкой «копировать»), выберите (правой кнопкой) в левой колонке папку drawable и нажмите вставить.


OK...

То же самое проделайте со второй картинкой. После этого надписи станут зелёными.



Далее откройте вкладку MainActivity.java, удалите всё кроме первой строчки и вставьте этот код:



import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.FrameLayout;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Set;
import java.util.UUID;
import static android.R.layout.*;


public class MainActivity extends AppCompatActivity {

    private static final int REQUEST_ENABLE_BT = 1;

    BluetoothAdapter bluetoothAdapter;

    ArrayList<String> pairedDeviceArrayList;

    ListView listViewPairedDevice;
    FrameLayout ButPanel;

    ArrayAdapter<String> pairedDeviceAdapter;
    private UUID myUUID;

    ThreadConnectBTdevice myThreadConnectBTdevice;
    ThreadConnected myThreadConnected;

    private StringBuilder sb = new StringBuilder();

    public TextView textInfo, d10, d11, d12, d13;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final String UUID_STRING_WELL_KNOWN_SPP = "00001101-0000-1000-8000-00805F9B34FB";

        textInfo = (TextView)findViewById(R.id.textInfo);
        d10 = (TextView)findViewById(R.id.d10);
        d11 = (TextView)findViewById(R.id.d11);
        d12 = (TextView)findViewById(R.id.d12);
        d13 = (TextView)findViewById(R.id.d13);

        listViewPairedDevice = (ListView)findViewById(R.id.pairedlist);

        ButPanel = (FrameLayout) findViewById(R.id.ButPanel);

        if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)){
            Toast.makeText(this, "BLUETOOTH NOT support", Toast.LENGTH_LONG).show();
            finish();
            return;
        }

        myUUID = UUID.fromString(UUID_STRING_WELL_KNOWN_SPP);

        bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

        if (bluetoothAdapter == null) {
            Toast.makeText(this, "Bluetooth is not supported on this hardware platform", Toast.LENGTH_LONG).show();
            finish();
            return;
        }

        String stInfo = bluetoothAdapter.getName() + " " + bluetoothAdapter.getAddress();
        textInfo.setText(String.format("Это устройство: %s", stInfo));

    } // END onCreate


    @Override
    protected void onStart() { // Запрос на включение Bluetooth
        super.onStart();

        if (!bluetoothAdapter.isEnabled()) {
            Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
        }

        setup();
    }

    private void setup() { // Создание списка сопряжённых Bluetooth-устройств

        Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();

        if (pairedDevices.size() > 0) { // Если есть сопряжённые устройства

            pairedDeviceArrayList = new ArrayList<>();

            for (BluetoothDevice device : pairedDevices) { // Добавляем сопряжённые устройства - Имя + MAC-адресс
                pairedDeviceArrayList.add(device.getName() + "\n" + device.getAddress());
            }

            pairedDeviceAdapter = new ArrayAdapter<>(this, simple_list_item_1, pairedDeviceArrayList);
            listViewPairedDevice.setAdapter(pairedDeviceAdapter);

            listViewPairedDevice.setOnItemClickListener(new AdapterView.OnItemClickListener() { // Клик по нужному устройству

                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

                    listViewPairedDevice.setVisibility(View.GONE); // После клика скрываем список

                    String  itemValue = (String) listViewPairedDevice.getItemAtPosition(position);
                    String MAC = itemValue.substring(itemValue.length() - 17); // Вычленяем MAC-адрес

                    BluetoothDevice device2 = bluetoothAdapter.getRemoteDevice(MAC);

                    myThreadConnectBTdevice = new ThreadConnectBTdevice(device2);
                    myThreadConnectBTdevice.start();  // Запускаем поток для подключения Bluetooth
                }
            });
        }
    }

    @Override
    protected void onDestroy() { // Закрытие приложения
        super.onDestroy();
        if(myThreadConnectBTdevice!=null) myThreadConnectBTdevice.cancel();
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if(requestCode == REQUEST_ENABLE_BT){ // Если разрешили включить Bluetooth, тогда void setup()

            if(resultCode == Activity.RESULT_OK) {
                setup();
            }

            else { // Если не разрешили, тогда закрываем приложение

                Toast.makeText(this, "BlueTooth не включён", Toast.LENGTH_SHORT).show();
                finish();
            }
        }
    }


    private class ThreadConnectBTdevice extends Thread { // Поток для коннекта с Bluetooth

        private BluetoothSocket bluetoothSocket = null;

        private ThreadConnectBTdevice(BluetoothDevice device) {

            try {
                bluetoothSocket = device.createRfcommSocketToServiceRecord(myUUID);
            }

            catch (IOException e) {
                e.printStackTrace();
            }
        }


        @Override
        public void run() { // Коннект

            boolean success = false;

            try {
                bluetoothSocket.connect();
                success = true;
            }

            catch (IOException e) {
                e.printStackTrace();

                runOnUiThread(new Runnable() {

                    @Override
                    public void run() {
                        Toast.makeText(MainActivity.this, "Нет коннекта, проверьте Bluetooth-устройство с которым хотите соединица!", Toast.LENGTH_LONG).show();
                        listViewPairedDevice.setVisibility(View.VISIBLE);
                    }
                });

                try {
                    bluetoothSocket.close();
                }

                catch (IOException e1) {

                    e1.printStackTrace();
                }
            }

            if(success) {  // Если законнектились, тогда открываем панель с кнопками и запускаем поток приёма и отправки данных

                runOnUiThread(new Runnable() {

                    @Override
                    public void run() {
                        ButPanel.setVisibility(View.VISIBLE); // открываем панель с кнопками
                    }
                });

                myThreadConnected = new ThreadConnected(bluetoothSocket);
                myThreadConnected.start(); // запуск потока приёма и отправки данных
            }
        }


        public void cancel() {

            Toast.makeText(getApplicationContext(), "Close - BluetoothSocket", Toast.LENGTH_LONG).show();

            try {
                bluetoothSocket.close();
            }

            catch (IOException e) {
                e.printStackTrace();
            }
        }

    } // END ThreadConnectBTdevice:



    private class ThreadConnected extends Thread {    // Поток - приём и отправка данных

        private final InputStream connectedInputStream;
        private final OutputStream connectedOutputStream;

        private String sbprint;

        public ThreadConnected(BluetoothSocket socket) {

            InputStream in = null;
            OutputStream out = null;

            try {
                in = socket.getInputStream();
                out = socket.getOutputStream();
            }

            catch (IOException e) {
                e.printStackTrace();
            }

            connectedInputStream = in;
            connectedOutputStream = out;
        }


        @Override
        public void run() { // Приём данных

            while (true) {
                try {
                    byte[] buffer = new byte[1];
                    int bytes = connectedInputStream.read(buffer);
                    String strIncom = new String(buffer, 0, bytes);
                    sb.append(strIncom); // собираем символы в строку
                    int endOfLineIndex = sb.indexOf("\r\n"); // определяем конец строки

                    if (endOfLineIndex > 0) {

                        sbprint = sb.substring(0, endOfLineIndex);
                        sb.delete(0, sb.length());

                        runOnUiThread(new Runnable() { // Вывод данных

                            @Override
                            public void run() {

                                switch (sbprint) {

                                    case "D10 ON":
                                        d10.setText(sbprint);
                                        break;

                                    case "D10 OFF":
                                        d10.setText(sbprint);
                                        break;

                                    case "D11 ON":
                                        d11.setText(sbprint);
                                        break;

                                    case "D11 OFF":
                                        d11.setText(sbprint);
                                        break;

                                    case "D12 ON":
                                        d12.setText(sbprint);
                                        break;

                                    case "D12 OFF":
                                        d12.setText(sbprint);
                                        break;

                                    case "D13 ON":
                                        d13.setText(sbprint);
                                        break;

                                    case "D13 OFF":
                                        d13.setText(sbprint);
                                        break;

                                    default:
                                        break;
                                }
                            }
                        });
                    }
                } catch (IOException e) {
                    break;
                }
            }
        }


            public void write(byte[] buffer) {
                try {
                    connectedOutputStream.write(buffer);
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }

        }

/////////////////// Нажатие кнопок /////////////////////
/////////////////////////D10////////////////////////////

    public void onClickBut1(View v) {

        if(myThreadConnected!=null) {

            byte[] bytesToSend = "a".getBytes();
            myThreadConnected.write(bytesToSend );
        }
    }


    public void onClickBut2(View v) {

        if(myThreadConnected!=null) {

            byte[] bytesToSend = "A".getBytes();
            myThreadConnected.write(bytesToSend );
        }
    }

////////////////////////D11////////////////////////////

    public void onClickBut3(View v) {

        if(myThreadConnected!=null) {

            byte[] bytesToSend = "b".getBytes();
            myThreadConnected.write(bytesToSend );
        }
    }


    public void onClickBut4(View v) {

        if(myThreadConnected!=null) {

            byte[] bytesToSend = "B".getBytes();
            myThreadConnected.write(bytesToSend );
        }
    }

//////////////////////D12//////////////////////////

    public void onClickBut5(View v) {

        if(myThreadConnected!=null) {

            byte[] bytesToSend = "c".getBytes();
            myThreadConnected.write(bytesToSend );
        }
    }


    public void onClickBut6(View v) {

        if(myThreadConnected!=null) {

            byte[] bytesToSend = "C".getBytes();
            myThreadConnected.write(bytesToSend );
        }
    }

    //////////////////////D13//////////////////////////

    public void onClickBut7(View v) {

        if(myThreadConnected!=null) {

            byte[] bytesToSend = "d".getBytes();
            myThreadConnected.write(bytesToSend );
        }
    }


    public void onClickBut8(View v) {

        if(myThreadConnected!=null) {

            byte[] bytesToSend = "D".getBytes();
            myThreadConnected.write(bytesToSend );
        }
    }
} // END



Если всё сделано правильно, то никаких ошибок не должно быть.


Разрешите на телефоне отладку по USB:




Подключите телефон к компьютеру и запустите компиляцию нажав зелёную стрелку:




Через некоторое время появится окно с выбором устройства на котором будет запущено приложение:


Отсутствие в списке телефона, означает какие-то проблемы с драйверами.


Нажмите ОК, приложение установится и откроется окно со списком сопряжённых устройств:



Выберите ваш модуль и после соединения откроется главное окно программы:




На этом всё, далее можно приступать к изучению программирования под Android и добавлять свой функционал.


Скачать исходники.

Здесь можно почитать о том, как сделать метеостанцию.


  • +487
  • 57870
Поддержать автора


Telegram-чат istarik

Задать вопрос по статье
Telegram-канал istarik

Известит Вас о новых публикациях






Комментарии (4)

0
В статью внесены незначительные изменения.
  • avatar
  • stD
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.