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