Search code examples
python-3.xmicropythonbbc-microbit

Converting Decimal to Binary on the Microbit


I thought it would be a fun idea to turn my BBC Microbit into a digital clock - specifically, a binary digital clock. I knocked up a bit of code in Python to do just that:

from microbit import *

def makeBinary(intValue,padding):
    number = intValue
    returnValue = ""
    brightness = 4 #value 0 to 8
    while number > 0:
        bit = number % 2
        if bit > 0:
            bit = brightness
        quotient = number / 2
        returnValue = str(bit)+returnValue
        number = quotient
    for i in range(len(returnValue),padding):
        returnValue = "0"+returnValue
    return returnValue

timeAdvance = 0
minuteAdvance = 0
hourAdvance = 0
secondCounter = 0
while True:
    if button_a.was_pressed():
        #advance hours
        hourAdvance = hourAdvance + 1
        if hourAdvance > 23:
            hourAdvance = 0
        timeAdvance = (hourAdvance*60*60*1000)+(minuteAdvance*60*1000)
    elif button_b.was_pressed():
        #advance minutes
        minuteAdvance = minuteAdvance + 1
        if minuteAdvance > 59:
            minuteAdvance = 0
        timeAdvance = (hourAdvance*60*60*1000)+(minuteAdvance*60*1000)
    else:
        #calculate and display time
        if (running_time()-secondCounter) > 1000:
            secondCounter = running_time()
            seconds = (running_time()/1000)%60
            minutes = ((running_time()+timeAdvance)/1000/60)%60
            hours = ((running_time()+timeAdvance)/1000/60/60)%24
            pmString = "0"
            addthirtyMString = "00000"
            addthirtySString = "00000"
            if hours>12:
                pmString = "9"
                hours = hours - 12
            if minutes>29:
                addthirtyMString = "00900"
                minutes = minutes - 30
            if seconds>29:
                addthirtySString = "00900"
                seconds = seconds - 30
            hourString = makeBinary(hours,4)
            minuteString = makeBinary(minutes,5)
            secondString = makeBinary(seconds,5)
            time = Image(pmString+hourString+":"+minuteString+":"+addthirtyMString+":"+secondString+":"+addthirtySString)
            display.show(time)

The problem is that is doesn't work! Running it on the Microbit results in the binary fields returning all 1 unless the number is 0. So 10:48:01AM is (incorrectly) displayed as

 ****
*****

*****

It should be displayed as

 * * 
*  * 
  *  
    *

Given that the am/pm led, and the add 30 seconds / add 30 minutes markers work fine this is clearly just an issue with formatting up a binary representation of the decimal number (the makeBinary function). I initially tried using 'format' to do this - but microPython, at least on the microBit, clearly doesn't like it.

When I run makeBinary on my 'real' computer, it works fine. Does anyone have any idea what might be amiss here? Or any suggestions for other simple ways of converting decimal to a binary string without using any functions which might confuse the MicroBit?


Solution

  • The microbit uses python 3 for micropython. This means that the division of two integers will often return a float value, not an integer. If you explicitly want integer division you should use // (Which will also work with Python 2.) To summarise:

              Py 2          Py 3 and microbit
    35 / 10     3                3.5
    35 // 10    3                3
    35.0 / 10   3.5              3.5
    

    Since hours is coming out as float, it is confusing the make_binary() function, which expects an int.

            quotient = number // 2
    

    [...]

            seconds = (running_time()//1000)%60
            minutes = ((running_time()+timeAdvance)//60000)%60
            hours = ((running_time()+timeAdvance)//3600000)%24
    

    Should fix the first problems with division.

    If you install and use python 3 on the computer you might find it easier to debug.

    Now, python already has a bin() function that takes an integer and returns a binary expression as a string

    >>> bin(58)
    '0b111010'
    

    And your code should be using this instead of writing your own.