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!

 

 

 

 

 

Advertisements

One thought on “Bluetooth enabled LCD driver

  1. Pingback: Bluetooth between Android and HC-05 | Astrospanner's Project Blog

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s