Bluetooth between Android and HC-05

In a previous post, https://astrospanner.wordpress.com/2016/04/13/bluetooth-enabled-lcd-driver/ I talked about the hardware side and the code on the PIC.  This post is about the android software. I wasn’t able to find a good reference on how to do this, so there was some experimentation, hence the need for a clear post like this.

Introduction

Android uses, not surprisingly, a “client” and “server” model for Bluetooth communications. This is outlined in their developer guides (http://developer.android.com/guide/topics/connectivity/bluetooth.html), but it assumes you are connecting two android devices, and so can decide which is the client and which is the server. This isn’t the case here, adn the HC-05 documentation doesn’t specify whether its a client or server. It talks about “slave” and “master”, but that doesn’t really help…

An Aside

I am not a particularly skilled Android developer. When I see examples like this

CaseInsensitiveString cis = new CaseInsensitiveString("Polish");

my brain struggles; why am I having to type “CaseInsensitiveString” twice? Isn’t the compiler meant to be sorting out type dependences like this for me?

After a while I realise that this is

  1. defining a new object called “cis” of type “CaseInsensitiveString”
  2. Assigning it to a value of “polish”

The Android developer guide has the following example

BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

It’s good that we can all type “Adapter” correctly after these examples…

What I found

The HC-05, when configured as a slave (as by default),  works as a “server” (in the Bluetooth Socket sense).

The process that Android code has to do is then straightforward

  1. Make sure Bluetooth is on
  2. Setup to talk to remote device by MAC address
  3. Create an RF Comm socket
  4. Connect the socket
  5. Get the output stream for the scoket
  6. Write bytes into the outputstream

At Point 2, you need the MAC address of the HC-05. This is discoverable by code, (I used what is reported by BT Term for this, which is a cheat), but I’ve not yet implement it.

At Point 3, you need to set a UUID. I initially thought this was just a random number, but you need to be specific; its this UUID that tells the HC-05 that you are connecting via SSP (Simple Serial Protocol). The magic ID is

00001101-0000-1000-8000-00805F9B34FB

Searching for this ID specificially shows that its in the Adnroid Bluetooth guide, which shows I didn’t read it properly…

 

Code fragment

The resultant code (with try/catch blocks removed for readability) is then. This is single threaded, blocking, and probably gives real Android developers a hernia. Hopefully its useful for someone.

String address = "98:D3:31:FD:18:B8"; // todo remove hardcoding

UUID SPP_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");

BluetoothDevice device = BA.getRemoteDevice(address);

btSocket = device.createRfcommSocketToServiceRecord(SPP_UUID);

// connect.
while (btSocket.isConnected() == false) {
    try {
        btSocket.connect();
    } catch (IOException e) {
    }
}

// write a message
outStream = btSocket.getOutputStream();
String message = "M07Conn...";
byte[] msgBuffer = message.getBytes();

outStream.write(msgBuffer);

outStream.flush();

Conclusion

The code works, and I have a specific app on my home which will connect to the HC-05, and push things onto the screen. I then started noticing timing issues, which will have to be dealt with. But it’s now time to finalize the hardware and package it properly.

Advertisements

Bluetooth enabled LCD driver

New project!

This is a really a re-fresh of an old project. In a previous job, I had an office and lab, and it wasn’t always obvious how long I’d been gone from my office. I built a little PIC controlled system with a switch that would either display the message “astrospanner is in” or “astrospanner left xxx seconds ago”. Now, I want something where I change the message easily to say things like “astrospanner has gone home”, “astrospanner is calibrating an instrument, back in a month”. Most PIC projects have a clunky set of switches to allow for things like message adding, which requires lookup tables and is slow. Yuck. Instead, I want a wireless connection to something with a keyboard. The ideal thing would be a connection to my phone, so that limits me to internet connectivity or bluetooth. Wireless internet would be suitable (if not overkill) if I used a Raspberry PI, and had tight security, so that was rejected as I wanted to something with a PIC.

This post is going to be a description of the debugging steps of getting to a working breadboard system. Full docs (circuit diagrams) will be in a later post.

 

System diagram

The basic system diagram, before any research, is as shown:

System diagram for BT

System diagram for BlueTooth enabled LCD display

A quick google search for “bluetooth module” brings up a bunch of hobbyist suitable things, including the HC-05. Because it was hobbyist based, it seems to come in slightly different mounting versions, but all the data-sheets talk about  serial mode transmit and receive, as well as a bunch of “AT” commands for configuration.

My project box had a couple of 16×2 LCD character displays (I tend to by what I need for a project + spares, meaning the next project has a bunch of additional parts to play with already available), and I’ve got a Microchip PicKit1 programmer, so I went searching for a PIC that

  • PICkit1 compatible
  • serial port
  • Enough output pins to drive the LCD module

The LCD module is a Hitachi HD44780 compatable LCD, with the component number JHD 162A. A variety of datasheets exist explaining it exist, but I used Julyan Ilett’s guides from here:

Guide 1.pdf

and here

Guide 2.pdf

(googling “Julyan Ilett Intelligent LCDs should find them)

The LCDs have 8 (!) data lines (give them a break; they are from the era of parallel ports for printers), and 2 (important) control lines (2 are required, an additional line is required for reading data back from the LCD). A second mode of the LCD allows only half the data lines to be used, so 6 lines to be controlled from a PIC. Because I had one in the project box, I added a serial to parallel chip (74×595), which requires 3 control lines to produce 8 data lines, so the PIC required 3 + 2 lines to control the LCD (a 2nd 74×595 chip would reduce this to 3 if required; the previous version of this project used an 8pin PIC to drive two 74×595 chips to control the LCD) and 2 for the serial port. This all pushed to a 14 pin device, and the microchip website listed the 16F688 as being suitable.

After some ordering from hobbycomponents.com, I had all the bits I needed…

bt1

HC-05 module, with 1p for scle

bt2

Backside of HC-05 module. Documentation on the silkscreen for users! Awesome!

 

The HC-05 module. I really like the silkscreened interface information on the back (including voltage levels for power!). It turns out the TX output is 5V TTL/CMOS compatable, but all info recommended 3.3V only for the RX lines. Important to know if the rest of the system is running at 5V levels…

lcd1

LCD module, doing an impression of cthulhu

I had to solder the (solid core for prototyping) wires in myself, which is why there are some red and some purple lines. The purple wires are from previous experiments with the 4 bit control mode.

 

Development

Throwing everything together would not have worked; end-to-end testing is vital, but for development, splitting things into smaller, individually testable chunks makes life much easier. I split this into 4 stages

 

  1. PIC driving 74×595 driving LCD
  2. Serial port talking to PIC
  3. Serial port talking to PIC driving 74×595 driving LCD
  4. BT module talking to PIC driving 74×595 driving LCD

 

I’ll go through some pitfalls for each, and things I learnt, in the following sections

PIC driving 74×595 driving LCD

This was OK. I’d done it before, and I understood the addressing modes of the LCD. The idea is to

  1. set the data lines, corresponding to a character you want to display
  2. set the RS line high (for characters) or low (for commands)
  3. set enable high, and then low.

It’s the transition from enable high to low that the LCD picks up on, so everything else can be done slowly, quickly, by careful re-wiring…

The trick is to get everything turned on first; by default the display is OFF and the second line is OFF when the LCD is powered on. Sending the commands 0xf (blinking underline cursor) and 0x38 (8 bit data, two lines, 5×7 format) do this.

I wrote some code in C, compiled by the microchip tools, and this worked. But the sequence of unplug, reprogram, plug back in, just to change the message was tedious. Time to get the serial port working…

Serial port talking to PIC

I’ve implemented the serial port on the PIC before, so this wasn’t too bad. But previously I used a PICkit3, which allowed for in-circuit debugging, which is a definite advantage! Showing my age, my previous work had been done on a windows NT system (!), which had Hyperterminal present. Hyperterminal doesn’t exist on Windows 7. There’s a “private edition” with the same look and feel, but with a nag screen. Instead, I used RealTerm. Terrible webpage, fantastic program. Allows closing and opening of the port without reloading (which in hyperterminal, especially with a nag screen, is a pain), and allows hex output. Definitely recommended.

The voltage levels between a PCs serial port (RS232, so -12V!) are NOT the same as the serial port on a PIC (TLL). I used a TTL USB port like this one; it pretends to be a serial port (so RealTerm talks to it) and it outputs TTL voltages, keeping the PIC happy.

The “serial port” on the PIC allows for asynchronous operation, which demands your PIC code deal with interrupts. There’s also a correction required to the PIC 16F688 docs; I found that the PIC was unable to receive until I set the port to receive by setting the TRISA register correctly (the docs say this is automatic!).

The interrupt service routine, which only cares about the serial port, looks like this:

 

void interrupt general_ISR(void) {
    // interrupt service routine. 
    // only care about GPIF at the moment...

    // if interrupt raised, we should have received a character.

    // load character into data area, charrecived,
    // and increment unprocessedcharacter

    // receive

    if ((PIR1 & 0b00100000) == 0b00100000) {
        // ie RCIF has been set, because something has been received
        // not dealing with overruns here.
    
        unprocessedcharacter++;  // increment this
        charreceived = RCREG;  // store the received data    
    }

    // transmit

    if ((PIR1 & 0b00000010) == 0b00000010) {
        // ie TXIF is set, meaning something can be transmitted
        
        if (characters_to_send > 0) {
            // load the register for transmission
            TXREG = transmit_buffer[buffer_start];
            buffer_start++;
            if (buffer_start == buffersize) {
                buffer_start = 0;
            }
            characters_to_send--;
            if (characters_to_send == 0) {
                // turn off the TXEN
                TXSTA = TXSTA & 0b11011111;
                // turn on the TXEN
            }
        }
    }
}

 

The idea is that if a character is received, an interrupt is raised. Your ISR (interrupt service routine) is called, and so you just copy the received character into a global and get out of the way. (The main() loop in this code checks for the “unprocessedcharacter” variable, and decrements it when processed).

The transmit interrupt in the PIC is a little strange. An interrupt is raised by a PIC when it is ready to transmit. So the ISR has to feed the transmit buffer. (I think this is probably better than the alternative, which is for the PIC’s main code to go into a fast loop waiting for the transmit buffer to be empty if there are a lot of characters to transmit). I found that if the ISR doesn’t turn off the transmit function (and so stop the interrupt from being called) when there is nothing to transmit, then it becomes unresponsive.

With the combination of the PIC and RealTerm, and the ISR as above, I was able to write code so that the PIC responded to keypresses and sent info back to the PC on particular keypresses. Great success! Merging this with the LCD display was then meant to be easy…

Serial port talking to PIC driving 74×595 driving LCD

The PIC code flow was meant to be

  1. set up LCD
  2. Wait for serial data
  3. Decode serial data into command or data
  4. Manipulate LCD

In trying to be clever, I set up a set of commands. Typing “D” would get the next character decoded onto the LCD datalines. “E” would send the LCD line enable high, “e” would send it low, “R” would send the LCD RS line (which selected between character and data) high, “r” send it low.

For commands, this worked. I was able to send the commands to turn on a blinking cursor, and line 2. But I was unable to display a character. Putting an LED on the dataline showed that “R” would send it high, and “r” low. I was confused. After a while, I realised that the character “A” was sending the cursor to line 2, position 2, which was the correct data line. It was as though the high character line (RS) was being ignored.

I soldered up a 2nd LCD terminal (previous project couldn’t decided between orange or green background, so bought 2 of each), perhaps thinking that some latent ESD damage had affected that input. Same problem. A new PIC had the same problem. Staring at the LED whilst hammering keys, I found that the RS line was going low with all subsequent serial inputs. But there’s nothing in the code on this…

I still don’t know why. I stared at the code for days. After a while, I hacked the code so nothing sent the line low. But it still went low.  The workaround was to move the RS controlling line to a different PIC port. I am still unsatisfied by this, but it allowed progress to be made.

After this simple change: great success! I was able to send commands to the PIC from a PC (using RealTerm), and got the display working properly. I moved the control level of the code up, so commands from the PC were a conceptual level up; they were “turn display on” rather than “send 01 to display”, “drive line high”. Time to bite the bullet and plug in the bluetooth module…

 

BT module talking to PIC driving 74×595 driving LCD

ACtually, this wasn’t the next step. It sounds good, but I wanted to understand talking to the BT module from an Android device (ie my phone) first. So it went Phone -> BT module -> PC. And after the headbanging of trying to understand why the RS line was not staying up (see above), this went really really smoothly.

I plugged the BT module into a breadboard, and connected it to the Serial to USB cable (remembering that TX on one is RX on the other). I only tried uni-directional, from BT to USB cable, to avoid putting a 5V Serial line onto a 3.3V only BT line. On my phone I installed a BT terminal (I used this one). Text I sent from my phone then appeared in RealTerm. Great Success! I had to pair my phone with the BT module, which “just worked”. I had to read the docs for the passcode, but its a default. (When I deploy this at work, I’ll change the BlueTooth ID and passcode!)

Because this went so well, I swapped the connections over and connected the BT module to the PIC. I also tweaked the PIC code to allow for even less typing, and tried it…

And it almost worked. Things initalized, commands could be sent, but sending a message (which, for a 12 byte string, requries sending M12 first (“M” for message, 12 for the number of bytes to received; everything after that is ignored) only displayed the last character sent. Gah! Messages were possible, but only with extra typing.

This was another annoying debugging moment. I spent a long time not trusting my message receive buffering code, but it was perfect. I tested timing. No. I slept on it. I worried about whether variables were volatile or not. After a lot of headbanging, it was a simple refactoring error. (Working code had been cut’n’pasted into a routine to aid readability, but not all variable names were correctly changed into the function prototypes. It still worked because of globals, almost. Just not with the buffering).

However, it is now fixed. And a screenshot like this from my phone

Screenshot_2016-04-13-21-46-11

gives this sort of response on the hardware

projectblog caption

 

(Still using the USB-Serial cable as it provides a useful regulated 5V supply!)

Phew!

Next steps are :

  1. Move hardware into a box
  2. Custom android code
  3. Full documentation

 

This project also gives a nice extensible base for some other ideas I have. I now have the knowledge to build a many (slow) digital output system with a human or programmatic interface from a PC or BlueTooth-enabled device, which means some of the heavy lifting can be done by phones, or desktop PCs. I’ve also got a useful display system, which can be added to things I want to debug only requiring three lines; LEDs are great for single outputs, but sometimes a text display allows for a lot of internal state information in one go.

The HC-05 BlueTooth device is awesome. It really is a very easy-to-use drop-in  wireless serial comms solution, that adds almost no complexity to the receiving system, but wireless functionality. I’m glad I bought two!

 

 

 

 

 

Word clock; RTC

My previous version of the Word Clock didn’t keep time well. That’s because I used the PIC’s internal clock to generate an interrupt every n cycles, and counted those. Now, as a short term timer (say, for an electric toothbrush motor controller), that’s fine. But over 24 hours, small errors due to different temperatures, or, even worse, just guessing the value of n, will become significant.

To solve this, I decided use a Real Time Clock. After a little searching, I found the DS1305 from Maxim that had the following desirable properties

  • 3 wire interface (and so is easy to interface to a PIC)
  • 5V supply
  • DIP case
  • raises an “alarm” once a second
  • cheap
  • in stock

The idea is then that on startup the PIC communicates with the DS, setting it up to raise an alarm once a second. The alarm is just a single line going low (and it needs pulling high as its an open drain output). The PIC then waits, and when it notices the line going low, it increments the second counter by one. Hidden in the documentation is the line that the alarm line will remain low until the PIC (in this case) writes to the DS again.

So why is the RTC better? Well, basically it removes the requirement for getting the PIC internal oscillator right. When I first read the datasheet, I noticed that the RTC also keeps a time and date stored, as yyyy/mm/dd:hh:MM:ss. A possible code flow for the PIC would be to set the RTC to the correct date and time, and then, roughly once per minute, ask the RTC what the time is, and then use that. I decided not to do that though.

The RTC also allows a small, low voltage battery (like a little lithium coin cell) can be used as a secondary supply for the RTC which will keep the oscillator running. If the Word Clock was going to be battery operated, this would be useful. But I’d already decided that swapping batteries might be a pain and that a wallwart PSU was cheap enough. And more advanced models of RTC have temperature compensation, so if that was deemed desirable, it could be used.

So the RTC is being underused. No matter.

Word clock; demo video

The following things are not yet done for the Word Clock: 

  1. Case
  2. Real time clock
  3. Human interface

However, I have been able to write the display routines, and a basic loop around the the display. The idea is that the display routine display_time(char hh,char mm) takes two variables, the hour (in hh) and minutes (in mm), and figures out which LEDs to light, and sets an array of globals.  A second routine show_time() pushes the globals out to the shift registers in the right order. show_time() has to be called often, as we are multiplexing the LEDs, but display_time() only needs to be called when the time changes.

As the RTC isn’t yet implemented, looping through the times can then be set to run fast, so that you don’t have to wait 24 hours to test the display logic. 

The video is here: http://youtu.be/iacYOHE3SZk

No audio, because we were watching BSG whilst testing, so I stripped that out.

RTC thoughts

I’ve wired in a DS1305 RTC chip, which has multiple functions. It can operate as a stable 1 second pulse (I’ve wired to a pin on the PIC that allows interrupt on change), it can raise alarms, and it can also, over a serial link, give you a binary string representing the time (including a date if required!). I haven’t decided whether just to use it as a reliable 1 second pulse, and do all the time counting in the PIC code, or to off load all time counting to the DS1305, and just ask it every minute (or so) what the time is, and feed that to the display_time(hh,mm) routine. Current program storage use is only 60% at the moment, so should have room for either. I’ll probably try having the DS do the time keeping and see if it all fits in the code space.