Tuesday, 8 May 2018

MCP9808 digital temperature sensor, BBC micro:bit and LCD screen


Introduction
In my previous post, I described how to connect and code the Microchip MCP9808 digital temperature sensor. That allowed you to send accurate temperature data via the REPL to a connected PC.

In this post, I shall describe how to send the temperature readings to an LCD screen. This could be the basis of a BBC micro:bit weather station or data logging project, or maybe for environmental control. N.B. I wasn't going to risk leaving my micro:bit in the freezer long enough to see how cold it really is - apart from anything else, I doubt whether the LCD would be too happy at -18 °C!


I came across a post on the excellent MultiWingSpan website showing how the micro:bit could be used with a Sparkfun Serial Enabled 3.3V 16x2 LCD Character Display. Unfortunately, those displays are quite expensive (around £24), whereas you can pick up a parallel (5v) 16x2 LCD screen for as little as £2. If you already have one of the Sparkfun ones or don't mind buying one, you can skip the next section.

So how can we make our own (cheaper) equivalent to the Sparkfun serial LCD?
The microbit is a 3.3v logic level device, so first we need an LCD screen that will work at that voltage. You can either pay a bit more and get a 3.3v screen (but they are hard to come by in the UK), or convert a 5v one, like I described in an earlier post.

Next, we need a serial UART LCD backpack like the Sparkfun one. I happened to have bought one from Proto-Pic in a sale last year for the princely sum of £2.40. They have discontinued that now but Hobbytronics in the UK sell a similar one (and, as a bonus, it also works over I2C) for £6. All of these backpacks have their own microprocessor that converts serial UART data into the correct parallel format for any display based on the Hitachi HD44780 compatible interface.

Adding up the cost of components (using the Hobbytronics backpack), it comes to about £9.

Connecting things up
Please refer to my previous post for connecting and programming the MCP9808 digital temperature sensor. Also have a look at the MultiWingSpan post for how to use the serial backpack. Depending on which serial backpack you are using, you may need the datasheet. My Proto-Pic one was very similar to the Sparkfun one but not identical so, if you find characters not appearing on the right row or column, that could be the reason. For convenience, I connected the data connection on my backpack to micro:bit pin 12 - the same as in the MultiWingSpan post.

Micropython code
I borrowed MultiWingSpan's code for the function "move_cursor(row,col)" for sending data to the serial backpack as it is very neat! I have extended it to work with 20x4 displays as well as 16x2. As mentioned above, the Proto-Pic backpack uses a slightly different addressing scheme from the Sparkfun display so I had to adjust the numbers a little as characters weren't coming out in the right place. I also had to look up in the HD44780 datasheet how to send special characters such as the degree symbol ° (decimal 223).

from microbit import *
# set up screen
# command set 1
bl_full = [254,02,255] # backlight on full
bl_half = [254,02,80] # half
bl_off = [254,02,0] # off
clr_scr = [254,01]

# command set 2
col_wide = [124,03] # 20 cols
col_narr = [124,04] # 16 cols
rows_four = [124,05] # 4 rows
rows_two = [124,06] # 2 rows

# choose cursor position - row 0,1,2,3 col, 0-15
def move_cursor(row,col):
    cmd = [254,128]
    if row==1:
        cmd[1]+=16 # adds 16 to cmd and stores it back
    if row==2:
        cmd[1]+=40 # adds 40 to cmd and stores it back
    if row==3:
        cmd[1]+=60 # adds 60 to cmd and stores it back
    cmd[1]+=col    
    uart.write(bytes(cmd))
    sleep(100)
  
# define character code for degree symbol
deg_symb = [223] #from HD44780 datasheet

# wait half a second for the splash screen
sleep(500)

# initialise uart
uart.init(baudrate=9600, bits=8, parity=None, stop=1, tx=pin12)
uart.write(bytes(rows_two)) # set 16x2
uart.write(bytes(col_narr)) # set 16x2
uart.write(bytes(bl_full))  # set backlight to full brightness

# clear display
move_cursor(0,0)
uart.write(bytes(clr_scr))
sleep(200)


# wait half a second for the splash screen
sleep(500)

# n.b. cursor is still at 0,0
uart.write("Temp.: ")
# sleep(50)
move_cursor(0,11)
uart.write(bytes(deg_symb))
uart.write("C")
move_cursor(1,0)
uart.write("This is line two") # change this to something useful!
move_cursor(0,7) #move cursor back again for temp. data
##########################################################
# Measure temperature and send to LCD
while True:
    i2c.write(0x18,bytearray([0x05])) # select ambient temp. register
    sleep(200) #  small pause needed to allow the device to update
    t_amb=i2c.read(0x18,2) # read two bytes from the ambient temp. register
    t_hi = (t_amb[0] & 0x0f) << 4 # mask upper 4 bits (alarm settings)
    t_lo = t_amb[1] / 16          # lower 8 bits (LSB)
    if t_amb[0] & 0x10 == 0x10: # take twos complement for -ve readings
        temp = (t_hi + t_lo) - 256.0
    else:
        temp = t_hi + t_lo
    uart.write('%.1f' % temp)  # display to 1 dec place
    move_cursor(0,7) #move cursor back again ready for next reading
    sleep(500) 
uart.init(115200) # reset uart

No comments:

Post a comment