commit 763e5fbe5111e3c6b79937b3d12edf9bd2364e4f Author: gabriel becker Date: Fri Aug 19 15:56:49 2022 -0300 Initial setup, all inputs configured. diff --git a/README.md b/README.md new file mode 100644 index 0000000..2ff2411 --- /dev/null +++ b/README.md @@ -0,0 +1,11 @@ +# references + - https://www.circuitschools.com/interfacing-16x2-lcd-module-with-raspberry-pi-pico-with-and-without-i2c/ + - Interrupts [ref](https://docs.micropython.org/en/latest/library/machine.Pin.html#machine.Pin.irq) \ +Pin.irq(handler=None, trigger=Pin.IRQ_FALLING | Pin.IRQ_RISING, *, priority=1, wake=None, hard=False) +``` python +SW3 = Pin(("GPIO_0", 4), Pin.IN) +SW3.irq(lambda t: print("SW3 changed")) +``` + - [Using flash memory as non-volatile storage on the Pi Pico microcontroller](https://kevinboone.me/picoflash.html?i=2) + - https://pypi.org/project/littlefs-python/ + - [buzzer reference](https://www.tomshardware.com/how-to/buzzer-music-raspberry-pi-pico) \ No newline at end of file diff --git a/src/lcd_api.py b/src/lcd_api.py new file mode 100644 index 0000000..5512b3d --- /dev/null +++ b/src/lcd_api.py @@ -0,0 +1,212 @@ +"""Provides an API for talking to HD44780 compatible character LCDs.""" + +import time + +class LcdApi: + """Implements the API for talking with HD44780 compatible character LCDs. + This class only knows what commands to send to the LCD, and not how to get + them to the LCD. + + It is expected that a derived class will implement the hal_xxx functions. + """ + + # The following constant names were lifted from the avrlib lcd.h + # header file, however, I changed the definitions from bit numbers + # to bit masks. + # + # HD44780 LCD controller command set + + LCD_CLR = 0x01 # DB0: clear display + LCD_HOME = 0x02 # DB1: return to home position + + LCD_ENTRY_MODE = 0x04 # DB2: set entry mode + LCD_ENTRY_INC = 0x02 # --DB1: increment + LCD_ENTRY_SHIFT = 0x01 # --DB0: shift + + LCD_ON_CTRL = 0x08 # DB3: turn lcd/cursor on + LCD_ON_DISPLAY = 0x04 # --DB2: turn display on + LCD_ON_CURSOR = 0x02 # --DB1: turn cursor on + LCD_ON_BLINK = 0x01 # --DB0: blinking cursor + + LCD_MOVE = 0x10 # DB4: move cursor/display + LCD_MOVE_DISP = 0x08 # --DB3: move display (0-> move cursor) + LCD_MOVE_RIGHT = 0x04 # --DB2: move right (0-> left) + + LCD_FUNCTION = 0x20 # DB5: function set + LCD_FUNCTION_8BIT = 0x10 # --DB4: set 8BIT mode (0->4BIT mode) + LCD_FUNCTION_2LINES = 0x08 # --DB3: two lines (0->one line) + LCD_FUNCTION_10DOTS = 0x04 # --DB2: 5x10 font (0->5x7 font) + LCD_FUNCTION_RESET = 0x30 # See "Initializing by Instruction" section + + LCD_CGRAM = 0x40 # DB6: set CG RAM address + LCD_DDRAM = 0x80 # DB7: set DD RAM address + + LCD_RS_CMD = 0 + LCD_RS_DATA = 1 + + LCD_RW_WRITE = 0 + LCD_RW_READ = 1 + + def __init__(self, num_lines, num_columns): + self.num_lines = num_lines + if self.num_lines > 4: + self.num_lines = 4 + self.num_columns = num_columns + if self.num_columns > 40: + self.num_columns = 40 + self.cursor_x = 0 + self.cursor_y = 0 + self.implied_newline = False + self.backlight = True + self.display_off() + self.backlight_on() + self.clear() + self.hal_write_command(self.LCD_ENTRY_MODE | self.LCD_ENTRY_INC) + self.hide_cursor() + self.display_on() + + def clear(self): + """Clears the LCD display and moves the cursor to the top left + corner. + """ + self.hal_write_command(self.LCD_CLR) + self.hal_write_command(self.LCD_HOME) + self.cursor_x = 0 + self.cursor_y = 0 + + def show_cursor(self): + """Causes the cursor to be made visible.""" + self.hal_write_command(self.LCD_ON_CTRL | self.LCD_ON_DISPLAY | + self.LCD_ON_CURSOR) + + def hide_cursor(self): + """Causes the cursor to be hidden.""" + self.hal_write_command(self.LCD_ON_CTRL | self.LCD_ON_DISPLAY) + + def blink_cursor_on(self): + """Turns on the cursor, and makes it blink.""" + self.hal_write_command(self.LCD_ON_CTRL | self.LCD_ON_DISPLAY | + self.LCD_ON_CURSOR | self.LCD_ON_BLINK) + + def blink_cursor_off(self): + """Turns on the cursor, and makes it no blink (i.e. be solid).""" + self.hal_write_command(self.LCD_ON_CTRL | self.LCD_ON_DISPLAY | + self.LCD_ON_CURSOR) + + def display_on(self): + """Turns on (i.e. unblanks) the LCD.""" + self.hal_write_command(self.LCD_ON_CTRL | self.LCD_ON_DISPLAY) + + def display_off(self): + """Turns off (i.e. blanks) the LCD.""" + self.hal_write_command(self.LCD_ON_CTRL) + + def backlight_on(self): + """Turns the backlight on. + + This isn't really an LCD command, but some modules have backlight + controls, so this allows the hal to pass through the command. + """ + self.backlight = True + self.hal_backlight_on() + + def backlight_off(self): + """Turns the backlight off. + + This isn't really an LCD command, but some modules have backlight + controls, so this allows the hal to pass through the command. + """ + self.backlight = False + self.hal_backlight_off() + + def move_to(self, cursor_x, cursor_y): + """Moves the cursor position to the indicated position. The cursor + position is zero based (i.e. cursor_x == 0 indicates first column). + """ + self.cursor_x = cursor_x + self.cursor_y = cursor_y + addr = cursor_x & 0x3f + if cursor_y & 1: + addr += 0x40 # Lines 1 & 3 add 0x40 + if cursor_y & 2: # Lines 2 & 3 add number of columns + addr += self.num_columns + self.hal_write_command(self.LCD_DDRAM | addr) + + def putchar(self, char): + """Writes the indicated character to the LCD at the current cursor + position, and advances the cursor by one position. + """ + if char == '\n': + if self.implied_newline: + # self.implied_newline means we advanced due to a wraparound, + # so if we get a newline right after that we ignore it. + self.implied_newline = False + else: + self.cursor_x = self.num_columns + else: + self.hal_write_data(ord(char)) + self.cursor_x += 1 + if self.cursor_x >= self.num_columns: + self.cursor_x = 0 + self.cursor_y += 1 + self.implied_newline = (char != '\n') + if self.cursor_y >= self.num_lines: + self.cursor_y = 0 + self.move_to(self.cursor_x, self.cursor_y) + + def putstr(self, string): + """Write the indicated string to the LCD at the current cursor + position and advances the cursor position appropriately. + """ + for char in string: + self.putchar(char) + + def custom_char(self, location, charmap): + """Write a character to one of the 8 CGRAM locations, available + as chr(0) through chr(7). + """ + location &= 0x7 + self.hal_write_command(self.LCD_CGRAM | (location << 3)) + self.hal_sleep_us(40) + for i in range(8): + self.hal_write_data(charmap[i]) + self.hal_sleep_us(40) + self.move_to(self.cursor_x, self.cursor_y) + + def hal_backlight_on(self): + """Allows the hal layer to turn the backlight on. + + If desired, a derived HAL class will implement this function. + """ + pass + + def hal_backlight_off(self): + """Allows the hal layer to turn the backlight off. + + If desired, a derived HAL class will implement this function. + """ + pass + + def hal_write_command(self, cmd): + """Write a command to the LCD. + + It is expected that a derived HAL class will implement this + function. + """ + raise NotImplementedError + + def hal_write_data(self, data): + """Write data to the LCD. + + It is expected that a derived HAL class will implement this + function. + """ + raise NotImplementedError + + # This is a default implementation of hal_sleep_us which is suitable + # for most micropython implementations. For platforms which don't + # support `time.sleep_us()` they should provide their own implementation + # of hal_sleep_us in their hal layer and it will be used instead. + def hal_sleep_us(self, usecs): + """Sleep for some time (given in microseconds).""" + time.sleep_us(usecs) # NOTE this is not part of Standard Python library, specific hal layers will need to override this diff --git a/src/main.py b/src/main.py new file mode 100644 index 0000000..bda5dba --- /dev/null +++ b/src/main.py @@ -0,0 +1,80 @@ + +from machine import ADC, I2C, Pin, PWM +import time +from pico_i2c_lcd import I2cLcd + +pressure_sensor = ADC(Pin(26, mode=Pin.IN)) +hall_sensor = Pin(27, Pin.IN, Pin.PULL_UP) +btnn_reset = Pin(22, Pin.IN) +lcd = False +buzzer_satus = False +ii = 0 + + +def interruption_handler(*args, **kargs): + global ii + ii += 1 + +hall_sensor.irq( + handler=interruption_handler, + trigger=Pin.IRQ_RISING, +) +previous_time = time.ticks_ms() + + +def setup(): + global pressure_sensor, lcd, buzzer + i2c = I2C(0, sda=Pin(0), scl=Pin(1), freq=100000) + I2C_ADDR = i2c.scan()[0] + lcd = I2cLcd(i2c, I2C_ADDR, 2, 16) + buzzer = PWM(Pin(15)) + buzzer.duty_u16(0) + + +def get_rotation_frequency(): + global ii, previous_time + frequency = float(ii) / (time.ticks_ms() - previous_time) * 1e3 + previous_time = time.ticks_ms() + ii = 0 + return frequency + + +def get_pressure(): + global pressure_sensor + pressure_measure = float(pressure_sensor.read_u16()) / 65535 * 3.3 + return pressure_measure + + +def loop(): + global lcd, buzzer, buzzer_satus + pressure_measure = get_pressure() + lcd.clear() + str_pressure = "{:.3f}".format(pressure_measure) + lcd.putstr('Preassure: ' + str_pressure + '\n') + frequency = get_rotation_frequency() + str_frequency = "{:.3f}".format(frequency) + lcd.putstr('Frequency: ' + str_frequency) + time.sleep(.07) + buzzer_satus = not buzzer_satus + if buzzer_satus: + buzzer.duty_u16(220) + else: + buzzer.duty_u16(0) + + + +def handle_error(): + global lcd + lcd.putstr('Exception') + + +if __name__ == "__main__": + setup() + try: + while(True): + loop() + except: + handle_error() + while True: + pass + diff --git a/src/pico_i2c_lcd.py b/src/pico_i2c_lcd.py new file mode 100644 index 0000000..fd83b8b --- /dev/null +++ b/src/pico_i2c_lcd.py @@ -0,0 +1,86 @@ +import utime +import gc + +from lcd_api import LcdApi +from machine import I2C + +# PCF8574 pin definitions +MASK_RS = 0x01 # P0 +MASK_RW = 0x02 # P1 +MASK_E = 0x04 # P2 + +SHIFT_BACKLIGHT = 3 # P3 +SHIFT_DATA = 4 # P4-P7 + +class I2cLcd(LcdApi): + + #Implements a HD44780 character LCD connected via PCF8574 on I2C + + def __init__(self, i2c, i2c_addr, num_lines, num_columns): + self.i2c = i2c + self.i2c_addr = i2c_addr + self.i2c.writeto(self.i2c_addr, bytes([0])) + utime.sleep_ms(20) # Allow LCD time to powerup + # Send reset 3 times + self.hal_write_init_nibble(self.LCD_FUNCTION_RESET) + utime.sleep_ms(5) # Need to delay at least 4.1 msec + self.hal_write_init_nibble(self.LCD_FUNCTION_RESET) + utime.sleep_ms(1) + self.hal_write_init_nibble(self.LCD_FUNCTION_RESET) + utime.sleep_ms(1) + # Put LCD into 4-bit mode + self.hal_write_init_nibble(self.LCD_FUNCTION) + utime.sleep_ms(1) + LcdApi.__init__(self, num_lines, num_columns) + cmd = self.LCD_FUNCTION + if num_lines > 1: + cmd |= self.LCD_FUNCTION_2LINES + self.hal_write_command(cmd) + gc.collect() + + def hal_write_init_nibble(self, nibble): + # Writes an initialization nibble to the LCD. + # This particular function is only used during initialization. + byte = ((nibble >> 4) & 0x0f) << SHIFT_DATA + self.i2c.writeto(self.i2c_addr, bytes([byte | MASK_E])) + self.i2c.writeto(self.i2c_addr, bytes([byte])) + gc.collect() + + def hal_backlight_on(self): + # Allows the hal layer to turn the backlight on + self.i2c.writeto(self.i2c_addr, bytes([1 << SHIFT_BACKLIGHT])) + gc.collect() + + def hal_backlight_off(self): + #Allows the hal layer to turn the backlight off + self.i2c.writeto(self.i2c_addr, bytes([0])) + gc.collect() + + def hal_write_command(self, cmd): + # Write a command to the LCD. Data is latched on the falling edge of E. + byte = ((self.backlight << SHIFT_BACKLIGHT) | + (((cmd >> 4) & 0x0f) << SHIFT_DATA)) + self.i2c.writeto(self.i2c_addr, bytes([byte | MASK_E])) + self.i2c.writeto(self.i2c_addr, bytes([byte])) + byte = ((self.backlight << SHIFT_BACKLIGHT) | + ((cmd & 0x0f) << SHIFT_DATA)) + self.i2c.writeto(self.i2c_addr, bytes([byte | MASK_E])) + self.i2c.writeto(self.i2c_addr, bytes([byte])) + if cmd <= 3: + # The home and clear commands require a worst case delay of 4.1 msec + utime.sleep_ms(5) + gc.collect() + + def hal_write_data(self, data): + # Write data to the LCD. Data is latched on the falling edge of E. + byte = (MASK_RS | + (self.backlight << SHIFT_BACKLIGHT) | + (((data >> 4) & 0x0f) << SHIFT_DATA)) + self.i2c.writeto(self.i2c_addr, bytes([byte | MASK_E])) + self.i2c.writeto(self.i2c_addr, bytes([byte])) + byte = (MASK_RS | + (self.backlight << SHIFT_BACKLIGHT) | + ((data & 0x0f) << SHIFT_DATA)) + self.i2c.writeto(self.i2c_addr, bytes([byte | MASK_E])) + self.i2c.writeto(self.i2c_addr, bytes([byte])) + gc.collect()