Bluetooth Module Interfacing with AVR
Hi everyone! Today we're going to learn how to interface Bluetooth module with AVR microcontroller and how LED is controlled remotely using smartphone. In this lesson we're going to develop our own mobile application using Android Studio to communicate with the Bluetooth module. If you're not familiar with USART serial communication, please read it before going through this lesson.
Interface Bluetooth Module
Bluetooth module can be interfaced either by using Interrupts or without Interrupts. I recommand to use Interrupts because, we don't need to always search for UDR (USART Data Register) for received data. Here I'll show you how microcontroller is programmed in both ways.
First, add bluetooth library to your project and include bluetooth.h header file.
Without Interrupts
#include <avr/io.h> #include "bluetooth.h" int main(void) { DDRB = 0xFF; // set PORTB as output PORTB = 0x00; // initially turn off LED bluetooth_init(); // initialize USART communication while (1) { char read = bluetooth_receivec(); // read byte from UDR if (read == 'T') PORTB |= 1 << PINB0; // turn on LED else if (read == 'F') PORTB &= ~(1 << PINB0); // turn off LED } }
With Interrupts
#include <avr/io.h> #include <avr/interrupt.h> #include "bluetooth.h" ISR(USART_RXC_vect){ char read = UDR; // read byte from UDR if (read == 'T') PORTB |= 1 << PINB0; // turn on LED else if (read == 'F') PORTB &= ~(1 << PINB0); // turn off LED } int main(void) { DDRB = 0xFF; // set PORTB as output PORTB = 0x00; // initially turn off LED bluetooth_init(); // initialize USART communication sei(); // enable global interrupts while (1); // wait forever }
Mobile App
We're going to develop our mobile app using Android Studio. You can import the project to Android Studio using this : https://github.com/UdaraWanasinghe/LEDControl.git GitHub URL. Following is a summary of our mobile app.
- Required permissions
<uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
- Before openning connection with the Bluetooth module, first you have to pair with it using Bluetooth passkey.
- Bluetooth communication is done by openning RfcommSocket (Radio Frequency Communication Socket) and connecting to Bluetooth Module as a client.
- When a successful connection is established with the Bluetooth module, a new thread is created in order to handle input stream.
- When sending data to bluetooth module, output stream need to be handled in a new thread.
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <Button android:id="@+id/buttonConnect" android:layout_width="wrap_content" android:layout_height="47dp" android:layout_marginEnd="8dp" android:layout_marginLeft="8dp" android:layout_marginRight="8dp" android:layout_marginStart="8dp" android:layout_marginTop="32dp" android:text="Connect" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <Switch android:id="@+id/switchLED" android:layout_width="136dp" android:layout_height="wrap_content" android:layout_marginEnd="8dp" android:layout_marginLeft="8dp" android:layout_marginRight="8dp" android:layout_marginStart="8dp" android:layout_marginTop="32dp" android:text="Switch LED" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/buttonConnect" /> </android.support.constraint.ConstraintLayout>
MainActivity.java
package com.udara.developer.ledcontrol; import android.bluetooth.BluetoothDevice; import android.content.DialogInterface; import android.content.Intent; import android.support.v7.app.AlertDialog; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.CompoundButton; import android.widget.Switch; import android.widget.Toast; import java.util.ArrayList; public class MainActivity extends AppCompatActivity { private BluetoothManager bluetoothManager; private Button buttonConnect; private Switch switchLED; private boolean isConnected; private int selectedDevice = 0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); buttonConnect = findViewById(R.id.buttonConnect); switchLED = findViewById(R.id.switchLED); buttonConnect.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (!isConnected) { if (bluetoothManager.isBluetoothOn()) showConnectBluetoothDialog(); } else { AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this); builder.setTitle("Alert"); builder.setMessage("Are you sure to disconnect device?"); builder.setPositiveButton("Yes", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { isConnected = false; bluetoothManager.disconnectDevice(); } }); builder.setNegativeButton("No", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { dialogInterface.dismiss(); } }); builder.create().show(); } } }); switchLED.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { if (isConnected) { if (isChecked) { bluetoothManager.transmitString("T"); } else { bluetoothManager.transmitString("F"); } } } }); bluetoothManager = new BluetoothManager(this, new BluetoothManager.BluetoothReceiveListener() { @Override public void onReceiveData(String data) { showToast("Received :" + data); } @Override public void onBluetoothMessage(int message) { if (message == BluetoothManager.CONNECTION_SUCCESS) { isConnected = true; buttonConnect.setText("Disconnect"); showToast("Connection successful"); } else if (message == BluetoothManager.CONNECTION_TIMEOUT) { showToast("Connection timeout"); } else if (message == BluetoothManager.CONNECTION_CLOSED) { showToast("Connection closed"); isConnected = false; buttonConnect.setText("Connect"); } else if (message == BluetoothManager.BLUETOOTH_OFF) { showToast("Bluetooth is off"); isConnected = false; buttonConnect.setText("Connect"); } } }); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK) { //bluetooth enabled showConnectBluetoothDialog(); } else if (resultCode == RESULT_CANCELED) { //error enabling bluetooth } } //bluetooth connect dialog private void showConnectBluetoothDialog() { //get paired device list final ArrayList<BluetoothDevice> pairedDevices = bluetoothManager.getBondedDeviceList(); AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this); builder.setTitle("Paired devices"); builder.setSingleChoiceItems(getDevicesNameList(pairedDevices), selectedDevice, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { selectedDevice = i; dialogInterface.dismiss(); BluetoothDevice device = pairedDevices.get(i); showToast("Connecting to : " + device.getName()); bluetoothManager.connectToDevice(device); } }); builder.setPositiveButton("Add devices", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { Intent openBluetoothSettings = new Intent(android.provider.Settings.ACTION_BLUETOOTH_SETTINGS); try { startActivity(openBluetoothSettings); } catch (Exception e) { Toast.makeText(MainActivity.this, e.getMessage(), Toast.LENGTH_LONG).show(); } } }); builder.create().show(); } //paired devices name list as string array private String[] getDevicesNameList(ArrayList<BluetoothDevice> devices) { ArrayList<String> nameListArr = new ArrayList<>(); for (BluetoothDevice device : devices) { nameListArr.add(device.getName()); } String[] nameList = new String[nameListArr.size()]; return nameListArr.toArray(nameList); } //show toast private void showToast(final String message) { runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(MainActivity.this, message, Toast.LENGTH_LONG).show(); } }); } }
BluetoothManager.java
package com.udara.developer.ledcontrol; import android.app.Activity; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothSocket; import android.content.Intent; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.UUID; class BluetoothManager { //global values private final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); private final static int REQUEST_ENABLE_BLUETOOTH = 1; //bluetooth manager messages final static int CONNECTION_SUCCESS = 1; final static int CONNECTION_TIMEOUT = 2; final static int CONNECTION_CLOSED = 3; final static int BLUETOOTH_OFF = 4; //activity reference private Activity activity = null; //bluetooth adapter private BluetoothAdapter bluetoothAdapter = null; private BluetoothSocket bluetoothSocket = null; static BluetoothDevice deviceConnected; //bluetooth receiver message listener private BluetoothReceiveListener bluetoothReceiveListener; //bluetooth constructor BluetoothManager(Activity activity, BluetoothReceiveListener bluetoothReceiveListener) { this.activity = activity; this.bluetoothReceiveListener = bluetoothReceiveListener; initBluetooth(); } //get bluetooth adapter if bluetooth available private void initBluetooth() { //get bluetooth adapter if (bluetoothAdapter == null) bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); } //get list of paired devices ArrayList<BluetoothDevice> getBondedDeviceList() { if (bluetoothAdapter != null) return new ArrayList<>(bluetoothAdapter.getBondedDevices()); return new ArrayList<>(); } //check if Bluetooth is on if not, request from system to turn on Bluetooth boolean isBluetoothOn() { if (bluetoothAdapter != null) { //request to turn on bluetooth if bluetooth is turned off if (!bluetoothAdapter.isEnabled()) { Intent enableBluetooth = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); activity.startActivityForResult(enableBluetooth, REQUEST_ENABLE_BLUETOOTH); return false; } } //return true if bluetooth on or not available return true; } //connect to given bluetooth device by opening RfcommSocket //Rfcomm - radio frequency communication, a widespread bluetooth protocol //Input stream handled by separate thread void connectToDevice(final BluetoothDevice deviceToConnect) { new Thread() { @Override public void run() { //scan for availability of the device BluetoothDevice device = bluetoothAdapter.getRemoteDevice(deviceToConnect.getAddress()); try { //open bluetooth socket bluetoothSocket = device.createInsecureRfcommSocketToServiceRecord(MY_UUID); //cancel discovery to speed up connection bluetoothAdapter.cancelDiscovery(); //connect to device bluetoothSocket.connect(); deviceConnected = device; bluetoothReceiveListener.onBluetoothMessage(CONNECTION_SUCCESS); //start input stream startBluetoothReceiver(); } catch (IOException e) { bluetoothReceiveListener.onBluetoothMessage(CONNECTION_TIMEOUT); e.printStackTrace(); } } }.start(); } //close bluetooth socket and disconnect from the device void disconnectDevice() { new Thread() { @Override public void run() { if (bluetoothSocket != null && bluetoothSocket.isConnected()) { try { bluetoothSocket.close(); } catch (IOException e) { e.printStackTrace(); } } } }.start(); } //method to transmit string void transmitString(final String stringToTransmit) { if (bluetoothSocket != null && bluetoothSocket.isConnected()) { new Thread() { @Override public void run() { try { //transmit data OutputStream outputStream = bluetoothSocket.getOutputStream(); outputStream.write(stringToTransmit.getBytes()); outputStream.flush(); } catch (IOException e) { e.printStackTrace(); } } }.start(); } } //method to handle bluetooth socket input stream private void startBluetoothReceiver() { if (bluetoothSocket != null && bluetoothSocket.isConnected()) { new Thread() { @Override public void run() { byte[] dataBuffer = new byte[256]; int bufferSize; try { InputStream inputStream = bluetoothSocket.getInputStream(); while (true) { try { if (inputStream.available() > 0) { bufferSize = inputStream.read(dataBuffer); if (bufferSize > 0 && bluetoothReceiveListener != null) { bluetoothReceiveListener.onReceiveData( new String(dataBuffer, 0, bufferSize)); } } } catch (IOException e) { bluetoothReceiveListener.onBluetoothMessage(CONNECTION_CLOSED); break; } } } catch (IOException e) { e.printStackTrace(); } } }.start(); } } //get connected device BluetoothDevice getDeviceConnected() { return deviceConnected; } //interface to bluetooth receive listener public interface BluetoothReceiveListener { void onReceiveData(String data); void onBluetoothMessage(int message); } }
Comments
Post a Comment