Monday, July 5, 2010

RN-41 Bluetooth Module

Recently I've been playing with the RN-41 bluetooth module from sparkfun, this module is really easy to use, it requires just a couple of connections to work and implements the SPP (bluetooth serial profile) with TTL levels so it's perfect for a pic project :) This is a little how-to on configuring and interfacing with the RN-41 module.
The circuit
This is a typical pic microcontroller circuit with a 3.3v voltage regulated power supply, the pic is running at 4Mhz, connected to the pic's serial port is the RN-41 module, rx->tx and tx->rx. I also wired a 16x2 LCD to print text sent to the RN-41.
Programming the pic
Alright we have the hardware ready now we need to program the pic to read from the RN-41 and print to the LCD, I used the CCS compiler, here's the code

#include <16f876.h>
#use delay(clock=4000000)     /*4Mhz*/
#use RS232(BAUD=9600, XMIT=PIN_C6, RCV=PIN_C7, STREAM=COM_A) 
#fuses XT, NOWDT, NOPROTECT, NOLVP 
#include "flcd.c"            /*flex lcd driver/

char buf[16];
int8 have_string = 0;

/*serial port interrupt service routine*/
#int_rda
void sp_isr()
{ 
    fgets(buf, COM_A);  
    have_string = 1;
}

void main(void)
{
    enable_interrupts(global);    /*enable interrupts*/
    enable_interrupts(int_rda);   /*enable serial port interrupts*/
   
    lcd_init();
    delay_ms(100); /*must delay after initiating the lcd*/
   
    while (1) {             
       if (have_string) {
          have_string = 0;         
          printf(lcd_putc, "\f%s", buf);
       }
    }
}
The code is pretty easy, but anyway, we first enable global and serial port interrupts so we get an interrupt whenever we receive data, you can poll the serial port instead but you should use interrupts because they free up the processor to do other stuff.

Inside the isr, we read a string from the serial port and set the have_string flag which is continuously checked in the main loop, when we have a string we print it to the lcd. After programming the pic, last step is configuring the RN-41.

Configuring the Module
The RN-41 module can be configured either locally, over the serial port, or remotly, over the air, I think the later approach is easier, so that's what I will be doing, I will use python to connect to the RN-41 since it's a lot more faster than doing so in C.

First we need a bdaddr and a channel to connect to the RN-41 module, so go ahead connect the power to the circuit, open a terminal and type:
$hcitool scan
Scanning ...
    00:06:66:04:11:94    FireFly-1194

$sdptool records 00:06:66:04:11:94
Service Name: SPP
Service RecHandle: 0x10000
Service Class ID List:
  "Serial Port" (0x1101)
Protocol Descriptor List:
  "L2CAP" (0x0100)
  "RFCOMM" (0x0003)
    Channel: 1
Language Base Attr List:
  code_ISO639: 0x656e
  encoding:    0x6a
  base_offset: 0x100
...
And we have the bdaddr and channel, time to configure the RN-41, the RN-41 has two modes of operation, a command mode and a data mode to configure the RN-41 we need to enter the command mode and we have to do so within then config time window, 60 seconds by default, open the python interpreter and:
import bluetooth
sock = bluetooth.BluetoothSocket(bluetooth.RFCOMM)
sock.connect(('00:06:66:04:11:94', 1))  # bdaddr, spp channel
sock.send('$$$')                        # config mode, within 60 of connecting
sock.send('ST,255\r\n')                 # enables continuous configuration
sock.send('SU,9600')                    # set baudrate to 9600bps 
sock.send('---\r\n')                    # switch back to data mode 
sock.send('Hello World !\r\n')          # send some text to test
And we're done have fun :)

Notes:
  • The 10k pot controls the LCD contrast.
  • Continous configuration allows you to enter the config mode at any time, if you don't use it don't forget to enter the config mode within the config time window.
  • The flcd driver can be found somewhere at  the CCS forums
  • If you're going to use the same pins for the LCD this is my configuration:
#define LCD_DB7   PIN_B7
#define LCD_DB6   PIN_B6
#define LCD_DB5   PIN_B5
#define LCD_DB4   PIN_B4
#define LCD_E     PIN_B1
#define LCD_RS    PIN_B0

No comments:

Post a Comment