Unfortunately they don't support I2C but given that they're currently selling on Ebay for US$1 each (inc intl shipping) they're an incredibly cheap way to add wireless/internet connectivity. That link is for one with a breakout board, I bought it without and simply glued/soldered it to a 4-way female header:
They're very simple to use, you just create an instance of SoftwareSerial and set it to use the CLK/SDA pins on the IC2 ports. Since it's a raw serial stream you need something on the other end to communicate with, I whipped up a simple console app that sits in the background listening for incoming characters and firing off media keyboard events, thus turning Gamebuino into a wireless media controller:
One interesting thing I did manage to do was get the module to pair with my Android phone, which instantly opens the door to giving Gamebuino an internet connection anywhere you go! I have too many other things on my Gamebuino plate at the moment but an Android app that provides socket support would be very cool indeed.
Range is surprisingly good, I had no problems getting a straight-line signal at 30 meters (the longest open stretch in my house), it also managed to make it through 3 brick walls. Power consumption is a little high at 40mA, for comparison Gamebuino itself is usually around 10-15mA depending on what you're doing. There's probably a way to cut power consumption in AT mode but that would require the use of another pin.
Gamebuino sketch is here:
- Code: Select all
#include <SPI.h>
#include <Gamebuino.h>
Gamebuino gb;
#define TX A4 // DA
#define RX A5 // CK
#include <SoftwareSerial.h>
SoftwareSerial bluetooth(RX, TX);
extern const byte font5x7[];
void setup(){
gb.begin();
gb.display.setFont(font5x7);
bluetooth.begin(9600);
pinMode(RX, INPUT);
pinMode(TX, OUTPUT);
}
void loop(){
if(gb.update()){
gb.display.println(F("Commands:"));
gb.display.print(F(" \25 Play/pause"));
gb.display.println(F(" \26 Stop"));
gb.display.println(F(" \27 Mute"));
gb.display.println(F(" \36\37 Volume +-"));
gb.display.println(F(" \21\20 Prev/next"));
if (gb.buttons.pressed(BTN_A))
bluetooth.print("A");
if (gb.buttons.pressed(BTN_B))
bluetooth.print("B");
if (gb.buttons.pressed(BTN_C))
bluetooth.print("C");
if (gb.buttons.pressed(BTN_LEFT))
bluetooth.print("<");
if (gb.buttons.pressed(BTN_RIGHT))
bluetooth.print(">");
if (gb.buttons.pressed(BTN_UP) || gb.buttons.held(BTN_UP, 1))
bluetooth.print("^");
if (gb.buttons.pressed(BTN_DOWN) || gb.buttons.held(BTN_DOWN, 1))
bluetooth.print("v");
}
}
And here's the code for the Visual Studio console app that decodes the serial stream (it uses 32feet.net for the bluetooth support which you can find in nuget):
- Code: Select all
using InTheHand.Net;
using InTheHand.Net.Sockets;
using System;
using System.Linq;
using System.Runtime.InteropServices;
namespace BluetoothTest
{
class Program
{
[DllImport("user32.dll")]
public static extern void keybd_event(byte bVk, byte bScan, int dwFlags, int dwExtraInfo);
const int KEYEVENTF_EXTENDEDKEY = 0x0001; //Key down flag
const int KEYEVENTF_KEYUP = 0x0002; //Key up flag
const int VK_PLAY = 0xFA;
const int VK_MEDIA_STOP = 0xB2;
const int VK_VOLUME_MUTE = 0xAD;
const int VK_MEDIA_NEXT_TRACK = 0xB0;
const int VK_MEDIA_PLAY_PAUSE = 0xB3;
const int VK_MEDIA_PREV_TRACK = 0xB1;
const int VK_VOLUME_DOWN = 0xAE;
const int VK_VOLUME_UP = 0xAF;
const int MediaNext = 11;
const int MediaPrevious = 12;
static void Main(string[] args)
{
try
{
Console.WriteLine("Searching for HC-05...");
var cli = new BluetoothClient();
var device = cli.DiscoverDevices().FirstOrDefault(p => p.DeviceName=="HC-05");
if (device==null)
throw new Exception("Device not found!");
Console.WriteLine("Device found! Trying to connect...");
try {cli.Connect(new BluetoothEndPoint(device.DeviceAddress, device.InstalledServices.First()));}
catch (Exception e) {throw new Exception("Couldn't connect: " + e.Message);}
try
{
Console.WriteLine("Connected! Press any key to stop service.");
var stream = cli.GetStream();
while (stream.DataAvailable)
stream.ReadByte(); // flush pending data
while (true)
{
if (Console.KeyAvailable && Console.ReadKey(true).Key==ConsoleKey.Escape)
break;
if (stream.DataAvailable)
{
var b = (char)stream.ReadByte();
switch (b)
{
// play/pause
case 'A':
keybd_event(VK_MEDIA_PLAY_PAUSE, 0x45, 0, 0);
keybd_event(VK_MEDIA_PLAY_PAUSE, 0x45, KEYEVENTF_KEYUP, 0);
break;
// stop
case 'B':
keybd_event(VK_MEDIA_STOP, 0x45, 0, 0);
keybd_event(VK_MEDIA_STOP, 0x45, KEYEVENTF_KEYUP, 0);
break;
// mute
case 'C':
keybd_event(VK_VOLUME_MUTE, 0x45, KEYEVENTF_EXTENDEDKEY, 0);
keybd_event(VK_VOLUME_MUTE, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
break;
// prev track
case '<':
keybd_event(VK_MEDIA_PREV_TRACK, 0x45, KEYEVENTF_EXTENDEDKEY, 0);
keybd_event(VK_MEDIA_PREV_TRACK, 0x45, KEYEVENTF_EXTENDEDKEY|KEYEVENTF_KEYUP, 0);
break;
// next track
case '>':
keybd_event(VK_MEDIA_NEXT_TRACK, 0x45, KEYEVENTF_EXTENDEDKEY, 0);
keybd_event(VK_MEDIA_NEXT_TRACK, 0x45, KEYEVENTF_EXTENDEDKEY|KEYEVENTF_KEYUP, 0);
break;
// volume up
case '^':
keybd_event(VK_VOLUME_UP, 0x45, KEYEVENTF_EXTENDEDKEY, 0);
keybd_event(VK_VOLUME_UP, 0x45, KEYEVENTF_EXTENDEDKEY|KEYEVENTF_KEYUP, 0);
break;
// volume down
case 'v':
keybd_event(VK_VOLUME_DOWN, 0x45, 0, 0);
keybd_event(VK_VOLUME_DOWN, 0x45, KEYEVENTF_KEYUP, 0);
break;
}
}
}
}
finally
{
if (cli.Connected)
cli.Close();
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
}
}