Close

The First Bits of Code (pun unintended)

A project log for The Resistorganizer

Managing resistors is a chore. Well, with the Resistorganizer, you can just jam your loose resistors into a breadboard and be done with it.

mikeMike 08/31/2023 at 15:553 Comments

Microscopic Snakes of the Constricting Variety:

I'm initially writing the code for this in Micropython, which as we all know is great for prototyping but doesn't have the speed or the flexibility of C/C++. I'm fine with this trade-off. Really, I am. Don't let the obvious doubt in my voice tell you any different. Which means, we'll be using...

Thonny:

Thonny is rad. It's come a long way since the first time I laid eyes on it. The RPi Pico integrates seamlessly with it. But, here's the rub. I hate using it. Here's the part where I'm tempted to say that I use Vim as my daily editor. I don't. I use VSCode; shameful as that may be. But, I'm a big fan of copilot and standing on the AI generated amalgam of shoulders of giants. Again, shameful as that may be. But I know tons of you out there who'll never post a comment use VSCode with copilot. Those of you that will leave a comment will tell me how much better their choice of editor / workflow is. Please do leave these comments! As a person whose neuro-biology forces them to constantly question their set-up, then reconfigure it endlessly rather than actually finishing a project, I need your ideas to keep me from actually conquering the universe. So, I'm using Thonny, and occasionally copy /  pasting my code into VSCode to get some of that sweet AI suggestions. Bring on the flames all you Thonny fanboys (said in my best Dave Jones accent). I think this haiku sums it up nicely:

Thonny's not my jam
For Pico, yet it's not bad—
Habit ties my hands.

Enough Loops to Make Girltalk Blush:

Yea, so here's the initial code:

from machine import Pin, I2C, ADC
import utime
from lcd_api import LcdApi
from pico_12c_lcd import I2cLcd

I2C_ADDR     = 39
I2C_NUM_ROWS = 2
I2C_NUM_COLS = 16
i2c = I2C(1, sda=Pin(14), scl=Pin(15), freq=400000)
lcd = I2cLcd(i2c, I2C_ADDR, I2C_NUM_ROWS, I2C_NUM_COLS) 


# print(i2c.scan())
# print(type(i2c.scan()[0]))
# utime.sleep(3)

adc_pin = ADC(Pin(26))

ser_pin = Pin(8, Pin.OUT)
srclk_pin = Pin(12, Pin.OUT)
rclk_pin = Pin(13, Pin.OUT)

prev_button = Pin(0, Pin.IN, Pin.PULL_UP)
next_button = Pin(1, Pin.IN, Pin.PULL_UP)

sense_pins = [Pin(21, Pin.OUT), Pin(20, Pin.OUT), Pin(19, Pin.OUT)]
ref_pins = [Pin(18, Pin.OUT), Pin(17, Pin.OUT), Pin(16, Pin.OUT)]
adc_enable_pins = [Pin(2, Pin.OUT), Pin(3, Pin.OUT), Pin(4, Pin.OUT), Pin(5, Pin.OUT), Pin(6, Pin.OUT), Pin(7, Pin.OUT)]
led_enable_pin = Pin(12, Pin.OUT)
ref_enable_pin = Pin(10, Pin.OUT)
shift_clear = Pin(11, Pin.OUT, value=1)

reference_resistances = (200, 750, 1500, 24000, 200000, 510000, 1000000, 5100000)

ref_enable_pin.low()
led_enable_pin.low()

current_index = 0
# Define debounce delay in milliseconds
debounce_delay_ms = 50

custom_omega = [
    0b00000,
    0b00100,
    0b01010,
    0b10001,
    0b10001,
    0b01010,
    0b00100,
    0b00000,
]

# Load the custom character into a custom slot (check your LCD's documentation)
I2cLcd.custom_char(lcd, 0, custom_omega)


def debounce_button(pin):
    # Wait for the button state to settle
    utime.sleep_ms(debounce_delay_ms)
    return pin.value()

def previous_button_pressed(pin):
    global current_index
    if debounce_button(pin) == 0:
        if current_index > 0:
            current_index -= 1
        else:
            current_index = len(big_array) - 1
        shift_out(1 << big_array[current_index][1])
        print(big_array[current_index][1]+1,": ", big_array[current_index][-1], "Ohms")
        lcd.clear()
        lcd.putstr(big_array[current_index][-1]+ " ohm")

def next_button_pressed(pin):
    global current_index
    if debounce_button(pin) == 0:
        if current_index < len(big_array) - 1:
            current_index += 1
        else:
            current_index = 0   
        shift_out(1 << big_array[current_index][1]) 
        print(big_array[current_index][1] +1,": ", big_array[current_index][-1], "Ohms")
        lcd.clear()
        lcd.putstr(big_array[current_index][-1]+ " ohm")
        # lcd.putchar(0)

# Attach interrupt handlers to buttons
prev_button.irq(trigger=Pin.IRQ_FALLING, handler=previous_button_pressed)
next_button.irq(trigger=Pin.IRQ_FALLING, handler=next_button_pressed)


def latch():
    rclk_pin.on()
    utime.sleep_us(1)
    rclk_pin.off()

def shift_out(data):
    for _ in range(8):
        ser_pin.value(data & 0x80)
        srclk_pin.on()
        utime.sleep_us(1)
        srclk_pin.off()
        data <<= 1
    latch()        


#create big array to hold all the adc readings
big_array = []

def enable_adc(a):
    for i in range(len(adc_enable_pins)):
        # Set the current enable pin low and others high
        adc_enable_pins[i].value(0 if i == a else 1)

def set_adc(a):
    # Convert the decimal value 'a' to a binary string
    binary_string = bin(a)[2:]
    while len(binary_string) < 3:
        binary_string = '0'+ binary_string
    binary_string = list(reversed(binary_string))
    for i in range(len(binary_string)):
        sense_pins[i].value(int(binary_string[i]))

def set_ref(a):
    # Convert the decimal value 'a' to a binary string
    binary_string = bin(a)[2:]
    while len(binary_string) < 3:
        binary_string = '0'+ binary_string
    binary_string = list(reversed(binary_string))
    for i in range(len(binary_string)):
        ref_pins[i].value(int(binary_string[i]))

def number_formatter(number):
    return "{:,}".format(number)

def scan():
    # Loop through all enable pins
    for e in range(len(adc_enable_pins)):
        enable_adc(e)
        
        
        
        # print("Enabling pin:", e)
        # print([p.value() for p in adc_enable_pins])


        for i in range(8):
            # Light the LED
            shift_out(1 << i)
            
            set_adc(7-i)
                
                # create an array to hold the adc readings
            adc_read_array = []
            for k in range(8):
                set_ref(k)
                avg_array = []
                for r in range(3):
                    avg_array.append(adc_pin.read_u16())
                adc_read_array.append(sum(avg_array)/len(avg_array))

                # print("ASR: ", e)        
                # print("ADC Address:", binary_string_adc, " ---- ", i)
                # print("REF Address:", binary_string_ref, " ---- ", k)                   
                # print("ADC values:", adc_read_array)
                # utime.sleep_us(1)
            
            # min_index = min(range(len(adc_read_array)), key=lambda i: abs(adc_read_array[i] - 65535))
            # Calculate the index of the minimum absolute difference
            min_index = min(range(len(adc_read_array)), key=lambda i: abs(adc_read_array[i] - (65535/2)))
            # print("Index of Minimum: ", min_index)
            adc_value = adc_read_array[min_index]
            # print("ADC Value: ", adc_value)
            R1 = reference_resistances[min_index]
            # print("R1: ", R1, " Ohms")
            R2 = R1 * (1 / ((65535 / adc_value) - 1))
            R2 = int(R2)
            # R2 = number_formatter(R2)
            print("R2: ", R2, " Ohms")
            if int(R2 < 4000000):
                seq = int(e)*8 + int(i)
                shift_out(1 << seq)
                big_array.append((str(e)+ str(i), seq, adc_read_array, min_index, adc_value, R1, number_formatter(R2)))
            # print(big_array)
# utime.sleep(.5)
scan()
for idx,poop in enumerate(big_array):
    print(idx +1, poop)
# while True:
#     utime.sleep(.1)

So, this is me being in 'get shit done' mode. I couldn't figure out how to get the debugger to work. So... yea lot's of print statements. And less loops than I thought. 

Discussions

Kevin Santo Cappuccio wrote 09/05/2023 at 17:59 point

It's crazy how quickly Copilot became a thing I take for granted. Like when I do simple projects in Arduino IDE and type something like count1 = 0; I get all incredulous that I have to type count2=0; afterwards. And with Thonny, I just recently decided to try every other python IDE that runs on mac, and concluded that Thonny sucks the least *by far*.

  Are you sure? yes | no

Mike wrote 09/05/2023 at 19:32 point

100% agree.
At first Copilot scared me a bit. I found some frequency detection code written in javascript and I set out to implement it in python. So I copy and pasted the javascript code into my python file and commented it all out, so I could just use it for reference. I get back to the top and Copilot's suggesting was precisely what I wanted to do. So I hit enter. The next suggestion was spot on. So I hit enter. Then it basically filled out the entire rest of the script. I looked it over... and pressed enter. Done. I freaked out a little. 

Now, when I sit down to code, I'm hopelessly dependent on it. I don't know how many for loops I've written in C++, but I'm pretty sure I had to check StackOverflow for 90% of them to remember how to set it up with the proper syntax. Nevermore. 

Does it make me a better programmer? No. Not by a long shot. But actually, it's lowered the barrier in my mind enough that coding doesn't scare me anymore. Which makes me code more, which I suppose indirectly helps make me better. It definitely makes me more productive. 

I did discover that Thonny will update the script when the file is updated. Same with VSCode. So, when I save in one place, it's reflected in the other. So I can write the code in VSCode and alt-tab over to Thonny for uploading to the pico. Don't know if this works on Mac or not. 

I love my MacBook, coding on it is a 'great' or 'useless' experience. Little in between. 

  Are you sure? yes | no

Kevin Santo Cappuccio wrote 09/05/2023 at 19:43 point

Ooh I hadn't thought of using it to translate from one language to another. That's a great idea. I'm going to try that with my JumperlessWokwiBridge Python app, hopefully I can get it to run in a more native language.

  Are you sure? yes | no