• How to interface 0.96″ OLED display with Raspberry Pi Pico without library using I2C in Micropython

    The 0.96-inch OLED screen is monochromatic blue. Which means it has only blue light. You can either switch on the led to make the text blue or you can invert the in which background is blue and the text black.

    The OLED uses a ssd1306 IC. Which is a 128 x 64 Dot Matrix OLED/PLED Segment/Common Driver with Controller.

    The code written does not need any library to be installed.

    I made the following connections

    OLED		RPI Pico
    
    SDA	->	RP0
    SCK	->	RP1
    VDD	->	3v3
    GND	->	GND
    		
    Note: RP0 and RP1 are pin number 0 and 1 on the pico develeopment board.

    Code

    # MicroPython SSD1306 OLED driver, I2C and SPI interfaces
    import machine
    import time
    import framebuf
    import utime
    
    # register definitions
    SET_CONTRAST        = const(0x81)
    SET_ENTIRE_ON       = const(0xa4)
    SET_NORM_INV        = const(0xa6)
    SET_DISP            = const(0xae)
    SET_MEM_ADDR        = const(0x20)
    SET_COL_ADDR        = const(0x21)
    SET_PAGE_ADDR       = const(0x22)
    SET_DISP_START_LINE = const(0x40)
    SET_SEG_REMAP       = const(0xa0)
    SET_MUX_RATIO       = const(0xa8)
    SET_COM_OUT_DIR     = const(0xc0)
    SET_DISP_OFFSET     = const(0xd3)
    SET_COM_PIN_CFG     = const(0xda)
    SET_DISP_CLK_DIV    = const(0xd5)
    SET_PRECHARGE       = const(0xd9)
    SET_VCOM_DESEL      = const(0xdb)
    SET_CHARGE_PUMP     = const(0x8d)
    
    
    class SSD1306:
        def __init__(self, width, height, external_vcc):
            self.width = width
            self.height = height
            self.external_vcc = external_vcc
            self.pages = self.height // 8
            # Note the subclass must initialize self.framebuf to a framebuffer.
            # This is necessary because the underlying data buffer is different
            # between I2C and SPI implementations (I2C needs an extra byte).
            self.poweron()
            self.init_display()
    
        def init_display(self):
            for cmd in (
                SET_DISP | 0x00, # off
                # address setting
                SET_MEM_ADDR, 0x00, # horizontal
                # resolution and layout
                SET_DISP_START_LINE | 0x00,
                SET_SEG_REMAP | 0x01, # column addr 127 mapped to SEG0
                SET_MUX_RATIO, self.height - 1,
                SET_COM_OUT_DIR | 0x08, # scan from COM[N] to COM0
                SET_DISP_OFFSET, 0x00,
                SET_COM_PIN_CFG, 0x02 if self.height == 32 else 0x12,
                # timing and driving scheme
                SET_DISP_CLK_DIV, 0x80,
                SET_PRECHARGE, 0x22 if self.external_vcc else 0xf1,
                SET_VCOM_DESEL, 0x30, # 0.83*Vcc
                # display
                SET_CONTRAST, 0xff, # maximum
                SET_ENTIRE_ON, # output follows RAM contents
                SET_NORM_INV, # not inverted
                # charge pump
                SET_CHARGE_PUMP, 0x10 if self.external_vcc else 0x14,
                SET_DISP | 0x01): # on
                self.write_cmd(cmd)
            self.fill(0)
            self.show()
    
        def poweroff(self):
            self.write_cmd(SET_DISP | 0x00)
    
        def contrast(self, contrast):
            self.write_cmd(SET_CONTRAST)
            self.write_cmd(contrast)
    
        def invert(self, invert):
            self.write_cmd(SET_NORM_INV | (invert & 1))
    
        def show(self):
            x0 = 0
            x1 = self.width - 1
            if self.width == 64:
                # displays with width of 64 pixels are shifted by 32
                x0 += 32
                x1 += 32
            self.write_cmd(SET_COL_ADDR)
            self.write_cmd(x0)
            self.write_cmd(x1)
            self.write_cmd(SET_PAGE_ADDR)
            self.write_cmd(0)
            self.write_cmd(self.pages - 1)
            self.write_framebuf()
    
        def fill(self, col):
            self.framebuf.fill(col)
    
        def pixel(self, x, y, col):
            self.framebuf.pixel(x, y, col)
    
        def scroll(self, dx, dy):
            self.framebuf.scroll(dx, dy)
    
        def text(self, string, x, y, col=1):
            self.framebuf.text(string, x, y, col)
    
    
    class SSD1306_I2C(SSD1306):
        def __init__(self, width, height, i2c, addr=0x3c, external_vcc=False):
            self.i2c = i2c
            self.addr = addr
            self.temp = bytearray(2)
            # Add an extra byte to the data buffer to hold an I2C data/command byte
            # to use hardware-compatible I2C transactions.  A memoryview of the
            # buffer is used to mask this byte from the framebuffer operations
            # (without a major memory hit as memoryview doesn't copy to a separate
            # buffer).
            self.buffer = bytearray(((height // 8) * width) + 1)
            self.buffer[0] = 0x40  # Set first byte of data buffer to Co=0, D/C=1
            self.framebuf = framebuf.FrameBuffer1(memoryview(self.buffer)[1:], width, height)
            super().__init__(width, height, external_vcc)
    
        def write_cmd(self, cmd):
            self.temp[0] = 0x80 # Co=1, D/C#=0
            self.temp[1] = cmd
            self.i2c.writeto(self.addr, self.temp)
    
        def write_framebuf(self):
            # Blast out the frame buffer using a single I2C transaction to support
            # hardware I2C interfaces.
            self.i2c.writeto(self.addr, self.buffer)
    
        def poweron(self):
            pass
    
    
    
    
    
    
    
    i2c = machine.SoftI2C(scl=machine.Pin(1), sda=machine.Pin(0))
    
    pin = machine.Pin(16, machine.Pin.OUT)
    pin.value(0) #set GPIO16 low to reset OLED
    pin.value(1) #while OLED is running, must set GPIO16 in high
    
    oled_width = 128
    oled_height = 64
    oled = SSD1306_I2C(oled_width, oled_height, i2c)
    
    oled.fill(0)
    oled.text('hallo, ', 0, 0)
    oled.text('exasub.com!', 0, 10)
    def toggle(i):
        if i == 0:
            i = 1
        else:
            i = 0
        return i
    
    i=0
    
    while True:
        i = toggle(i)
        oled.invert(i)
        oled.show()
        utime.sleep(1)
        
    
    
    
  • Using Loops to Iterate Over Data Structures in MicroPython on Raspberry Pi Pico

    MicroPython on Raspberry Pi Pico provides several data structures for storing and manipulating data. These include lists, tuples, sets, and dictionaries. Loops are a powerful tool for iterating over these data structures and performing operations on their elements.

    Let’s take a look at some examples of how loops can be used to iterate over data structures in MicroPython.

    1. Iterating over a List

    A list is a collection of items, and we can iterate over it using a for loop. Here’s an example:

    # Create a list of numbers
    numbers = [1, 2, 3, 4, 5]
    
    # Iterate over the list and print each number
    for number in numbers:
        print(number)

    In this example, we create a list of numbers and then iterate over it using a for loop. For each number in the list, we print it to the console.

    1. Iterating over a Tuple

    A tuple is similar to a list, but it is immutable, which means it cannot be modified once it is created. Here’s an example of how to iterate over a tuple using a for loop:

    # Create a tuple of fruits
    fruits = ('apple', 'banana', 'cherry')
    
    # Iterate over the tuple and print each fruit
    for fruit in fruits:
        print(fruit)

    In this example, we create a tuple of fruits and then iterate over it using a for loop. For each fruit in the tuple, we print it to the console.

    1. Iterating over a Set

    A set is an unordered collection of unique items. We can iterate over a set using a for loop just like we do with lists and tuples. Here’s an example:

    # Create a set of colors
    colors = {'red', 'green', 'blue'}
    
    # Iterate over the set and print each color
    for color in colors:
        print(color)

    In this example, we create a set of colors and then iterate over it using a for loop. For each color in the set, we print it to the console.

    1. Iterating over a Dictionary

    A dictionary is a collection of key-value pairs. We can iterate over a dictionary using a for loop, but we need to use the items() method to access both the keys and values. Here’s an example:

    # Create a dictionary of students and their grades
    grades = {'Alice': 85, 'Bob': 90, 'Charlie': 95}
    
    # Iterate over the dictionary and print each student and their grade
    for student, grade in grades.items():
        print(f'{student}: {grade}')

    In this example, we create a dictionary of students and their grades and then iterate over it using a for loop. For each student and their corresponding grade, we print them to the console.

  • Loop Control Statements in MicroPython on Raspberry Pi Pico

    Loop control statements are used to alter the normal flow of execution within loops. They can be used to skip iterations or terminate loops prematurely based on certain conditions. In MicroPython on Raspberry Pi Pico, there are three loop control statements: break, continue, and pass.

    1. Break statement:
      The break statement is used to terminate a loop prematurely. When a break statement is encountered within a loop, the loop is immediately exited and program execution continues with the statement immediately following the loop. The break statement can be used with both for and while loops.

    Here’s an example:

    for i in range(1, 11):
        if i == 5:
            break
        print(i)

    In this example, the loop will iterate over the values from 1 to 10. However, when i equals 5, the break statement is encountered and the loop is terminated prematurely. As a result, only the values from 1 to 4 will be printed.

    1. Continue statement:
      The continue statement is used to skip the current iteration of a loop and move on to the next iteration. When a continue statement is encountered within a loop, the remaining statements within the loop for that iteration are skipped and the loop moves on to the next iteration. The continue statement can be used with both for and while loops.

    Here’s an example:

    for i in range(1, 11):
        if i % 2 == 0:
            continue
        print(i)

    In this example, the loop will iterate over the values from 1 to 10. However, when i is even, the continue statement is encountered and the remaining statements for that iteration are skipped. As a result, only the odd values from 1 to 10 will be printed.

    1. Pass statement:
      The pass statement is used to do nothing. It can be used as a placeholder when a statement is required syntactically, but no action is needed. The pass statement is typically used when a block of code is not yet implemented but is required for the program to run without error.

    Here’s an example:

    for i in range(1, 11):
        pass

    In this example, the loop will iterate over the values from 1 to 10. However, the pass statement does nothing, so the loop will simply run through all iterations without doing anything. The pass statement can be used with both for and while loops.

    Loop control statements are a useful tool in programming, as they allow us to alter the normal flow of execution within loops based on certain conditions. The break statement can be used to terminate a loop prematurely, the continue statement can be used to skip the current iteration and move on to the next iteration, and the pass statement can be used as a placeholder when no action is needed.

    Sure, here is an example of how you can use continue, pass, and break statements in a loop:

    # Example of using loop control statements in MicroPython
    
    # Loop from 1 to 10
    for i in range(1, 11):
        # If i is even, skip to the next iteration
        if i % 2 == 0:
            continue
    
        # If i is 5, do nothing and continue to the next iteration
        if i == 5:
            pass
    
        # If i is greater than 8, break out of the loop
        if i > 8:
            break
    
        # Print the value of i
        print(i)

    In this example, the continue statement is used to skip over even numbers in the loop. The pass statement is used to do nothing and simply continue to the next iteration when the value of i is 5. Finally, the break statement is used to exit the loop when the value of i becomes greater than 8.

    When you run this code, you will see the following output:

    1
    3
    7

    As you can see, the even numbers (2, 4, 6, 8, and 10) are skipped over with the continue statement. The value of 5 does nothing with the pass statement, and the loop stops when the value of i reaches 9 because of the break statement.

  • Nested Loops in MicroPython on Raspberry Pi Pico

    Nested loops in MicroPython on Raspberry Pi Pico refer to the use of one loop inside another loop. The inner loop is executed multiple times for each iteration of the outer loop. This technique is useful when we want to perform repetitive tasks or calculations on a set of data.

    To create nested loops in MicroPython on Raspberry Pi Pico, we simply need to place one loop inside another loop. Here’s an example:

    for i in range(3):
        for j in range(2):
            print(i, j)

    In this example, we have an outer loop that iterates from 0 to 2, and an inner loop that iterates from 0 to 1. For each iteration of the outer loop, the inner loop is executed twice. The output of this code would be:

    0 0
    0 1
    1 0
    1 1
    2 0
    2 1

    We can also use nested loops to access and modify elements of a two-dimensional list or array. Here’s an example:

    matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
    
    for row in matrix:
        for element in row:
            print(element)

    In this example, we have a two-dimensional list called matrix. The outer loop iterates over each row of the matrix, while the inner loop iterates over each element in the current row. The output of this code would be:

    1
    2
    3
    4
    5
    6
    7
    8
    9

    Nested loops can also be used to perform more complex calculations or operations.

  • For Loops in MicroPython on Raspberry Pi Pico

    For loops are one of the most commonly used loops in programming, including MicroPython on Raspberry Pi Pico. They allow you to repeat a set of instructions a specific number of times, making your code more efficient and concise.

    In MicroPython, a for loop is used to iterate over a sequence of values, such as a list, tuple, or string. The general syntax for a for loop in MicroPython is as follows:

    for variable in sequence:
        # Code to execute for each item in the sequence
    

    Here, variable is a temporary variable that takes on the value of each item in the sequence. The code block under the for statement is executed for each item in the sequence, with variable taking on the value of each item in turn.

    For example, let’s say we have a list of numbers and we want to print each number in the list:

    numbers = [1, 2, 3, 4, 5]
    
    for num in numbers:
        print(num)
    

    In this code, num takes on the value of each item in the numbers list, and the print statement outputs each number in turn.

    In addition to lists, for loops can also be used with other sequences such as tuples and strings. For example:

    name = "John"
    
    for char in name:
        print(char)
    

    This code outputs each character in the string name, one character per line.

    You can also use the built-in range() function with for loops in MicroPython. The range() function returns a sequence of numbers starting from 0 (by default) and incrementing by 1, up to a specified number. For example:

    for i in range(5):
        print(i)
    

    This code outputs the numbers 0 through 4, one number per line.

    You can also specify a starting value and a step size for the range() function. For example:

    for i in range(1, 10, 2):
        print(i)
    

    This code outputs the odd numbers from 1 to 9, one number per line.

  • While Loops in MicroPython on Raspberry Pi Pico

    While loops in MicroPython on Raspberry Pi Pico are used to execute a block of code repeatedly as long as a certain condition is true. The general syntax for a while loop is:

    while condition:
        # code to execute
    

    The condition is checked at the beginning of each iteration. If the condition is true, the code inside the loop is executed. Once the code has been executed, the condition is checked again, and the loop continues until the condition is false.

    Here’s an example of a simple while loop:

    i = 0
    while i < 5:
        print(i)
        i += 1
    

    In this example, the loop will continue to execute as long as i is less than 5. Inside the loop, the current value of i is printed, and i is incremented by 1. The loop will continue until i reaches 5, at which point the condition i < 5 will be false, and the loop will terminate.

    It’s important to make sure that the condition in a while loop will eventually become false, otherwise the loop will continue to execute indefinitely, which is known as an infinite loop. An infinite loop can cause your program to hang or crash, so it’s important to make sure that your loop will eventually terminate.

    Here’s an example of an infinite loop:

    i = 0
    while i < 5:
        print(i)
    

    In this example, the condition i < 5 will always be true, since i is never incremented. This will cause the loop to continue to execute indefinitely, which is not what we want.

    While loops can be useful for a variety of tasks, such as reading data from sensors, controlling motors, or performing other repetitive tasks. By using while loops, you can make your code more efficient and easier to read.

  • Introduction to Loops in MicroPython on Raspberry Pi Pico

    Loops are an essential part of any programming language, including MicroPython on Raspberry Pi Pico. They allow you to execute a block of code repeatedly, saving you time and effort. In this article, we’ve introduced you to the two types of loops in MicroPython: for loops and while loops.

    What are Loops?
    A loop is a programming construct that allows you to execute a block of code repeatedly until a specific condition is met. There are two types of loops in MicroPython: for loops and while loops.

    For Loops
    A for loop is used when you want to execute a block of code a fixed number of times. The syntax of a for loop in MicroPython is as follows:

    for variable in sequence:
        # Code to execute

    The variable is assigned to each element of the sequence in turn, and the code inside the loop is executed. Here’s an example:

    for i in range(5):
        print(i)

    This code will print the numbers from 0 to 4.

    While Loops
    A while loop is used when you want to execute a block of code repeatedly until a specific condition is met. The syntax of a while loop in MicroPython is as follows:

    while condition:
        # Code to execute

    The code inside the loop will be executed repeatedly until the condition becomes false. Here’s an example:

    i = 0
    while i < 5:
        print(i)
        i += 1

    The code first initializes the value of i to 0. Then it enters the while loop and checks if the value of i is less than 5. Since i is initially 0, the condition is true and the loop begins.

    The loop prints the current value of i using the print() function and then increments the value of i by 1 using the += operator. This process repeats until the value of i is no longer less than 5, at which point the loop ends and the program continues with the rest of the code.

    When you run this code in a MicroPython environment such as Thonny IDE, the output will be:

    0 1 2 3 4

    This is because the loop executes five times, with the value of i being printed on each iteration.

  • Conditional Statements in MicroPython on Raspberry Pi Pico

    Conditional statements in MicroPython on Raspberry Pi Pico are used to make decisions based on certain conditions. They allow us to execute a block of code only if a certain condition is true, or to execute a different block of code if the condition is false.

    In MicroPython, we use the if, elif, and else keywords to create conditional statements. The general syntax for an if statement is:

    if condition:
        # Code to execute if condition is True
    

    If the condition is true, then the code inside the block is executed. If the condition is false, then the code inside the block is skipped.

    Here’s an example of an if statement:

    temperature = 25
    
    if temperature > 30:
        print("It's hot outside!")
    

    In this example, the condition temperature > 30 is false, so the code inside the block is not executed.

    We can also use the else keyword to specify what code should be executed if the condition is false:

    temperature = 25
    
    if temperature > 30:
        print("It's hot outside!")
    else:
        print("It's not that hot outside.")
    

    In this case, since the condition is false, the code inside the else block is executed, and the output would be “It’s not that hot outside.”

    We can also use the elif keyword to check multiple conditions:

    temperature = 25
    
    if temperature > 30:
        print("It's hot outside!")
    elif temperature > 20:
        print("It's warm outside.")
    else:
        print("It's not that hot outside.")
    

    In this example, the first condition is false, so the elif condition is checked. Since temperature > 20 is true, the code inside the elif block is executed, and the output would be “It’s warm outside.”

    Conditional statements can also be nested inside each other, to create more complex logic. For example:

    x = 5
    y = 10
    
    if x > 0:
        if y > 0:
            print("Both x and y are positive.")
        else:
            print("x is positive but y is not.")
    else:
        if y > 0:
            print("y is positive but x is not.")
        else:
            print("Both x and y are negative.")
    

    In this example, the output would be “Both x and y are positive.” since both x and y are greater than 0.

    elif statements can be nested in Python and MicroPython on Raspberry Pi Pico. You can use them to create more complex conditions that depend on multiple variables or factors.

    Here’s an example of nested elif statements in MicroPython on Raspberry Pi Pico:

    x = 5
    y = 10
    
    if x > y:
        print("x is greater than y")
    elif x < y:
        print("x is less than y")
        if x < 0:
            print("x is negative")
        elif x == 0:
            print("x is zero")
        else:
            print("x is positive")
    else:
        print("x is equal to y")

    In this example, if x is less than y, the program checks whether x is negative, zero, or positive using nested elif statements. If x is greater than y, the program prints a message saying so. And if x is equal to y, the program prints a message saying that as well.

    Note that when you nest elif statements, you must make sure that the indentation is correct to avoid syntax errors.

  • Variables and Data Types in MicroPython on Raspberry Pi Pico

    Variables and data types are fundamental concepts in programming. In MicroPython, just like in any programming language, variables are used to store data values and data types define the kind of data that can be stored.

    In this tutorial, we will explore variables and data types in MicroPython on Raspberry Pi Pico.

    Variables in MicroPython

    Variables in MicroPython are used to store data values such as numbers, strings, and boolean values. A variable is simply a named reference to a value.

    To create a variable, you simply assign a value to a name using the equals sign (=). For example:

    x = 5

    In this case, the variable x is assigned the value of 5.

    You can also assign values to multiple variables at once, like this:

    x, y, z = 5, "Hello", True
    

    This assigns the value of 5 to the variable x, the string “Hello” to the variable y, and the boolean value True to the variable z.

    Further Explanation

    x, y, z = 5, “Hello”, True is a way of assigning values to multiple variables at once in Python. In this case, the values 5, “Hello”, and True are assigned to the variables x, y, and z respectively.

    This syntax is known as “tuple unpacking”. The values on the right-hand side of the equals sign are packed into a tuple, which is then unpacked and assigned to the variables on the left-hand side.

    Essentially, it’s the same as writing:

    my_tuple = (5, "Hello", True)
    x = my_tuple[0]
    y = my_tuple[1]
    z = my_tuple[2]

    But using tuple unpacking is a more concise and readable way to assign values to multiple variables at once.

    Data Types in MicroPython

    MicroPython has several built-in data types that define the kind of data that can be stored in a variable. These include:

    • Integer: whole numbers, such as 5 or -3.
    • Float: decimal numbers, such as 3.14 or -2.5.
    • String: a sequence of characters, such as “Hello” or “123”.
    • Boolean: a value that is either True or False.
    • List: a collection of values, such as [1, 2, 3] or [“apple”, “banana”, “orange”].
    • Tuple: a collection of values, like a list, but cannot be modified once created, such as (1, 2, 3) or (“apple”, “banana”, “orange”).
    • Dictionary: a collection of key-value pairs, such as {“name”: “John”, “age”: 30}.

    To determine the data type of a variable, you can use the type() function, like this:

    This will output <class ‘int’>, indicating that x is an integer.

    x = 5
    print(type(x))  # Output: <class 'int'>
    
  • How to Read internal temperature sensor of Raspberry Pi Pico using Thonny IDE

    The internal temperature sensor of RP2040 is read using micropython. The Thonny IDE is used in Windows environment.

    The temperature sensor is connected to Channel number 4 of the ADC.

    But since this is a rather small implementation using Thonny IDE, it does most of the interfacing related code in the background.

    Code

    import machine
    import time
    
    """
    Function Name: Read internal temperature sensor
    Description: This function reads the internal temperature sensor of RP2040 chip.
                 The temperature sensor measures the Vbe voltage of a biased bipolar diode,
                 connected to the fifth ADC channel (AINSEL=4).
    """
    def read_internal_temperature_sensor():
        tsi = machine.ADC(machine.ADC.CORE_TEMP)
        temp = tsi.read_u16() * (3.3 / (65535))
        temp = 27 - (temp - 0.706)/0.001721
        return temp
    
    while True:
        #reads the temprature and prints it
        print("Temperature: ", read_internal_temperature_sensor())
        #Create a dealy of 1 second
        time.sleep(1)