Starting work on C++
This commit is contained in:
parent
12560f784e
commit
6707c4d19f
14 changed files with 206 additions and 2 deletions
212
micropython/lib/lcd_api.py
Normal file
212
micropython/lib/lcd_api.py
Normal file
|
@ -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
|
86
micropython/lib/pico_i2c_lcd.py
Normal file
86
micropython/lib/pico_i2c_lcd.py
Normal file
|
@ -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()
|
141
micropython/main.py
Normal file
141
micropython/main.py
Normal file
|
@ -0,0 +1,141 @@
|
|||
from machine import Pin, I2C
|
||||
from onewire import OneWire
|
||||
from ds18x20 import DS18X20
|
||||
from time import sleep_ms, ticks_ms, ticks_diff
|
||||
from lcd_api import LcdApi
|
||||
from pico_i2c_lcd import I2cLcd
|
||||
|
||||
# Version
|
||||
VERSION = "1.0.0"
|
||||
|
||||
# Relais
|
||||
relais = Pin(18, machine.Pin.OUT, value = 1)
|
||||
#led_onboard = Pin(25, machine.Pin.OUT, value = 0)
|
||||
|
||||
# Temperature
|
||||
temp_sensor = DS18X20(OneWire(Pin(28)))
|
||||
sensor_id = temp_sensor.scan()[0]
|
||||
|
||||
# LCD Display
|
||||
i2c = I2C(1, sda=Pin(26), scl=Pin(27), freq=400000)
|
||||
I2C_ADDR = 0x27
|
||||
I2C_NUM_ROWS = 2
|
||||
I2C_NUM_COLS = 16
|
||||
lcd = I2cLcd(i2c, I2C_ADDR, I2C_NUM_ROWS, I2C_NUM_COLS)
|
||||
|
||||
# Custom characters
|
||||
degree = (
|
||||
0b00111,
|
||||
0b00101,
|
||||
0b00111,
|
||||
0b00000,
|
||||
0b00000,
|
||||
0b00000,
|
||||
0b00000,
|
||||
0b00000,
|
||||
)
|
||||
umlaut_a = (
|
||||
0b01010,
|
||||
0b00000,
|
||||
0b01110,
|
||||
0b00001,
|
||||
0b01111,
|
||||
0b10001,
|
||||
0b01111,
|
||||
0b00000,
|
||||
)
|
||||
|
||||
def ctrl_relais(active = True):
|
||||
if active:
|
||||
relais.value(0)
|
||||
#led_onboard.on()
|
||||
else:
|
||||
relais.value(1)
|
||||
#led_onboard.off()
|
||||
|
||||
lcd.backlight_on()
|
||||
lcd.clear()
|
||||
lcd.custom_char(0, degree)
|
||||
lcd.custom_char(1, umlaut_a)
|
||||
|
||||
temp_tgt = 28.0
|
||||
temp_gap = 0.5
|
||||
is_heating = False
|
||||
heat_string = ""
|
||||
system_on = False
|
||||
system_on_string = "OFF"
|
||||
temp_curr = 0
|
||||
|
||||
lcd.move_to(0, 0)
|
||||
lcd.putstr(" G" + chr(1) + "rbox Manager\n (Ver. "+ VERSION + ")")
|
||||
sleep_ms(3000)
|
||||
|
||||
# Buttons
|
||||
PIN_BUTTON_1 = 17
|
||||
PIN_BUTTON_2 = 16
|
||||
PIN_BUTTON_3 = 15
|
||||
button1 = Pin(PIN_BUTTON_1, Pin.IN, Pin.PULL_DOWN)
|
||||
button2 = Pin(PIN_BUTTON_2, Pin.IN, Pin.PULL_DOWN)
|
||||
button3 = Pin(PIN_BUTTON_3, Pin.IN, Pin.PULL_DOWN)
|
||||
|
||||
button1_last = ticks_ms()
|
||||
button2_last = ticks_ms()
|
||||
button3_last = ticks_ms()
|
||||
|
||||
def button_action(pin):
|
||||
global temp_tgt
|
||||
global button1_last
|
||||
global button2_last
|
||||
global button3_last
|
||||
global system_on
|
||||
global system_on_string
|
||||
|
||||
if pin is button1:
|
||||
if ticks_diff(ticks_ms(), button1_last) > 750:
|
||||
temp_tgt -= 0.5
|
||||
#lcd.move_to(5, 1)
|
||||
#lcd.putstr("{0:3.1f}".format(temp_tgt))
|
||||
button1_last = ticks_ms()
|
||||
elif pin is button2:
|
||||
if ticks_diff(ticks_ms(), button2_last) > 750:
|
||||
temp_tgt += 0.5
|
||||
#lcd.move_to(5, 1)
|
||||
#lcd.putstr("{0:3.1f}".format(temp_tgt))
|
||||
button2_last = ticks_ms()
|
||||
elif pin is button3:
|
||||
if ticks_diff(ticks_ms(), button3_last) > 750:
|
||||
system_on = not system_on
|
||||
if system_on == True:
|
||||
system_on_string = "ON "
|
||||
else:
|
||||
system_on_string = "OFF"
|
||||
#lcd.move_to(13, 1)
|
||||
#lcd.putstr(system_on_string)
|
||||
button3_last = ticks_ms()
|
||||
|
||||
button1.irq(trigger = Pin.IRQ_RISING, handler = button_action)
|
||||
button2.irq(trigger = Pin.IRQ_RISING, handler = button_action)
|
||||
button3.irq(trigger = Pin.IRQ_RISING, handler = button_action)
|
||||
|
||||
while True:
|
||||
temp_sensor.convert_temp()
|
||||
sleep_ms(750)
|
||||
temp_curr = temp_sensor.read_temp(sensor_id)
|
||||
|
||||
if system_on == True and temp_curr < temp_tgt - temp_gap:
|
||||
is_heating = True
|
||||
elif system_on == True and temp_curr > temp_tgt + temp_gap:
|
||||
is_heating = False
|
||||
elif system_on == False:
|
||||
is_heating = False
|
||||
|
||||
ctrl_relais(is_heating)
|
||||
|
||||
if is_heating == True:
|
||||
heat_string = ">H<"
|
||||
else:
|
||||
heat_string = " "
|
||||
|
||||
lcd.move_to(0, 0)
|
||||
lcd.putstr("ACT: {0:3.1f}".format(temp_curr) + chr(0) + "C " + heat_string +
|
||||
"\nTGT: {0:3.1f}".format(temp_tgt) + chr(0) + "C " + system_on_string)
|
Loading…
Add table
Add a link
Reference in a new issue