init
This commit is contained in:
commit
21233d4258
139
conways_game_of_life.py
Normal file
139
conways_game_of_life.py
Normal file
@ -0,0 +1,139 @@
|
||||
from time import sleep_ms
|
||||
from framebuf import FrameBuffer1
|
||||
from urandom import getrandbits
|
||||
|
||||
class ConwaysGameOfLife:
|
||||
def __init__(self, lcd):
|
||||
# High score
|
||||
self.best = 0
|
||||
# PCD8544 (Nokia 5110) LCD
|
||||
self.lcd = lcd
|
||||
self.width = 84
|
||||
self.height = 48
|
||||
self.pages = self.height // 8
|
||||
self.buffer = bytearray(self.pages * self.width)
|
||||
self.framebuf = FrameBuffer1(self.buffer, self.width, self.height)
|
||||
|
||||
def draw(self):
|
||||
self.lcd.data(self.buffer)
|
||||
|
||||
def intro(self):
|
||||
self.framebuf.fill(0)
|
||||
self.framebuf.text("Conway's", 10, 8, 1)
|
||||
self.framebuf.text("Game", 26, 16, 1)
|
||||
self.framebuf.text("of", 34, 24, 1)
|
||||
self.framebuf.text("Life", 26, 32, 1)
|
||||
self.draw()
|
||||
|
||||
def end(self, score, best, size):
|
||||
# The 8x8 font is too wide to fit "Generations", so I called it "Score"
|
||||
self.framebuf.fill(0)
|
||||
self.framebuf.text("Score", 0, 0, 1)
|
||||
self.framebuf.text(str(score), 0, 8, 1)
|
||||
self.framebuf.text("Best score", 0, 16, 1)
|
||||
self.framebuf.text(str(best), 0, 24, 1)
|
||||
self.framebuf.text("Pixel size", 0, 32, 1)
|
||||
self.framebuf.text(str(size), 0, 40, 1)
|
||||
self.draw()
|
||||
|
||||
def begin(self, size=4, delay=20):
|
||||
# Size of lifeforms in pixels
|
||||
self.size = size
|
||||
# Delay in ms between generations
|
||||
self.delay = delay
|
||||
|
||||
# Localised to avoid self lookups
|
||||
# Possible performance optimisation, TBC
|
||||
draw = self.draw
|
||||
delay = self.delay
|
||||
tick = self.tick
|
||||
|
||||
# Randomise initial pixels
|
||||
self.randomise()
|
||||
|
||||
# Begin
|
||||
generations = 0
|
||||
try:
|
||||
while tick():
|
||||
generations = generations + 1
|
||||
draw()
|
||||
sleep_ms(delay)
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
|
||||
# New high score?
|
||||
if generations > self.best:
|
||||
self.best = generations
|
||||
|
||||
# End
|
||||
self.end(generations, self.best, self.size)
|
||||
|
||||
def randomise(self):
|
||||
size = self.size
|
||||
width = self.width
|
||||
height = self.height
|
||||
cell = self.cell
|
||||
|
||||
self.framebuf.fill(0)
|
||||
|
||||
for x in range(0, width, size):
|
||||
for y in range(0, height, size):
|
||||
# random bit: 0 = pixel off, 1 = pixel on
|
||||
cell(x, y, getrandbits(1))
|
||||
|
||||
self.draw()
|
||||
|
||||
def cell(self, x, y, colour):
|
||||
size = self.size
|
||||
buf = self.framebuf
|
||||
|
||||
for i in range(size):
|
||||
for j in range(size):
|
||||
buf.pixel(x + i, y + j, colour)
|
||||
|
||||
def get(self, x, y):
|
||||
if not 0 <= x < self.width or not 0 <= y < self.height:
|
||||
return 0
|
||||
return self.framebuf.pixel(x, y) & 1
|
||||
|
||||
def tick(self):
|
||||
size = self.size
|
||||
width = self.width
|
||||
height = self.height
|
||||
get = self.get
|
||||
cell = self.cell
|
||||
|
||||
# If no pixels are born or die, the game ends
|
||||
something_happened = False
|
||||
|
||||
for x in range(0, width, size):
|
||||
for y in range(0, height, size):
|
||||
|
||||
# Is the current cell alive
|
||||
alive = get(x, y)
|
||||
|
||||
# Count number of neighbours
|
||||
neighbours = (
|
||||
get(x - size, y - size) +
|
||||
get(x, y - size) +
|
||||
get(x + size, y - size) +
|
||||
get(x - size, y) +
|
||||
get(x + size, y) +
|
||||
get(x + size, y + size) +
|
||||
get(x, y + size) +
|
||||
get(x - size, y + size)
|
||||
)
|
||||
|
||||
# Apply the game rules
|
||||
if alive and not 2 <= neighbours <= 3:
|
||||
# This pixel dies
|
||||
cell(x, y, 0)
|
||||
if not something_happened:
|
||||
something_happened = True
|
||||
elif not alive and neighbours == 3:
|
||||
# A new pixel is born
|
||||
cell(x, y, 1)
|
||||
if not something_happened:
|
||||
something_happened = True
|
||||
|
||||
return something_happened
|
70
main.py
Normal file
70
main.py
Normal file
@ -0,0 +1,70 @@
|
||||
import network
|
||||
sta_if = network.WLAN(network.STA_IF)
|
||||
ap_if = network.WLAN(network.AP_IF)
|
||||
|
||||
from machine import Pin, SPI
|
||||
import upcd8544
|
||||
|
||||
spi = SPI(1, baudrate=80000000, polarity=0, phase=0)
|
||||
RST = Pin(2)
|
||||
CE = Pin(15)
|
||||
DC = Pin(0)
|
||||
BC = Pin(16)
|
||||
|
||||
lcd = upcd8544.PCD8544(spi, RST, CE, DC, BC)
|
||||
import framebuf
|
||||
width = 84
|
||||
height = 48
|
||||
pages = height // 8
|
||||
buffer = bytearray(pages * width)
|
||||
framebuf = framebuf.FrameBuffer1(buffer, width, height)
|
||||
framebuf.fill(0)
|
||||
framebuf.text("EIK ROBO", 10, 0, 1)
|
||||
lcd.data(buffer)
|
||||
import time
|
||||
framebuf.text("Wifi conn", 5, 10, 1)
|
||||
lcd.data(buffer)
|
||||
s = 0
|
||||
dots = ('|', '/', '-', '\\')
|
||||
while not sta_if.isconnected():
|
||||
framebuf.fill_rect(30, 20, 8, 8, 0)
|
||||
framebuf.text(dots[s], 30, 20, 1)
|
||||
print(dots[s])
|
||||
lcd.data(buffer)
|
||||
s += 1
|
||||
if s == len(dots):
|
||||
s = 0
|
||||
time.sleep(0.05)
|
||||
framebuf.fill_rect(30, 20, 8, 8, 0)
|
||||
ip = sta_if.ifconfig()[0].split(".")
|
||||
framebuf.text("IP:"+ip[0]+"."+ip[1], 0, 20, 1)
|
||||
framebuf.text("."+ip[2]+"."+ip[3], 16, 30, 1)
|
||||
print(sta_if.ifconfig())
|
||||
lcd.data(buffer)
|
||||
framebuf.text("get time", 0, 40, 1)
|
||||
lcd.data(buffer)
|
||||
import ntptime
|
||||
retry = 5
|
||||
while retry:
|
||||
try:
|
||||
ntptime.settime()
|
||||
break
|
||||
except:
|
||||
retry -= 1
|
||||
time.sleep(0.5)
|
||||
|
||||
if retry == 0:
|
||||
framebuf.fill_rect(0, 40, width, 8, 0)
|
||||
framebuf.text("error", 0, 40, 1)
|
||||
time.sleep(5)
|
||||
import utime
|
||||
while True:
|
||||
framebuf.fill_rect(0, 40, width, 8, 0)
|
||||
t = time.localtime()
|
||||
timezone = +2
|
||||
hours = t[3]+timezone
|
||||
if hours > 23:
|
||||
hours -= 24
|
||||
framebuf.text(str(hours)+":"+str(t[4])+":"+str(t[5]), 12, 40, 1)
|
||||
lcd.data(buffer)
|
||||
time.sleep(1)
|
36
ntptime.py
Normal file
36
ntptime.py
Normal file
@ -0,0 +1,36 @@
|
||||
try:
|
||||
import usocket as socket
|
||||
except:
|
||||
import socket
|
||||
try:
|
||||
import ustruct as struct
|
||||
except:
|
||||
import struct
|
||||
|
||||
# (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60
|
||||
NTP_DELTA = 3155673600
|
||||
|
||||
host = "pool.ntp.org"
|
||||
|
||||
def time():
|
||||
NTP_QUERY = bytearray(48)
|
||||
NTP_QUERY[0] = 0x1b
|
||||
addr = socket.getaddrinfo(host, 123)[0][-1]
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
s.settimeout(1)
|
||||
res = s.sendto(NTP_QUERY, addr)
|
||||
msg = s.recv(48)
|
||||
s.close()
|
||||
val = struct.unpack("!I", msg[40:44])[0]
|
||||
return val - NTP_DELTA
|
||||
|
||||
# There's currently no timezone support in MicroPython, so
|
||||
# utime.localtime() will return UTC time (as if it was .gmtime())
|
||||
def settime():
|
||||
t = time()
|
||||
import machine
|
||||
import utime
|
||||
tm = utime.localtime(t)
|
||||
tm = tm[0:3] + (0,) + tm[3:6] + (0,)
|
||||
machine.RTC().datetime(tm)
|
||||
print(utime.localtime())
|
287
upcd8544.py
Normal file
287
upcd8544.py
Normal file
@ -0,0 +1,287 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
MicroPython PCD8544 driver
|
||||
(for Nokia 5110 displays)
|
||||
"""
|
||||
|
||||
__author__ = "Markus Birth"
|
||||
__copyright__ = "Copyright 2015, Markus Birth"
|
||||
__credits__ = ["Markus Birth"]
|
||||
__license__ = "MIT"
|
||||
__version__ = "1.0"
|
||||
__maintainer__ = "Markus Birth"
|
||||
__email__ = "markus@birth-online.de"
|
||||
__status__ = "Production"
|
||||
|
||||
# Datasheet: https://www.sparkfun.com/datasheets/LCD/Monochrome/Nokia5110.pdf
|
||||
# Inspiration from:
|
||||
# - https://github.com/inaugurator/upyd5110
|
||||
# - https://github.com/rm-hull/pcd8544/blob/master/src/lcd.py
|
||||
#
|
||||
# PINOUT
|
||||
# WiPy/pyBoard display function
|
||||
#
|
||||
# 3V3 or any Pin => VCC 3.3V logic voltage (0=off, 1=on)
|
||||
# MOSI => DIN data flow (Master out, Slave in)
|
||||
# SCK => CLK SPI clock
|
||||
# any Pin => RST Reset pin (0=reset, 1=normal)
|
||||
# any Pin => CE Chip Enable (0=listen for input, 1=ignore input)
|
||||
# any Pin => DC Data/Command (0=commands, 1=data)
|
||||
# any Pin => LIGHT Light (0=on, 1=off)
|
||||
# GND => GND
|
||||
#
|
||||
# pyBoard "Y" side
|
||||
# SPI = pyb.SPI(1)
|
||||
# RST = pyb.Pin('Y4')
|
||||
# CE = pyb.Pin('Y5')
|
||||
# DC = pyb.Pin('Y3')
|
||||
# LIGHT = pyb.Pin('Y2')
|
||||
# PWR = pyb.Pin('Y1')
|
||||
#
|
||||
# pyBoard "X" side
|
||||
# SPI = pyb.SPI(2)
|
||||
# RST = pyb.Pin('X4')
|
||||
# CE = pyb.Pin('X5')
|
||||
# DC = pyb.Pin('X3')
|
||||
# LIGHT = pyb.Pin('X2')
|
||||
# PWR = pyb.Pin('X1')
|
||||
#
|
||||
# WiPy (on Exp board, SD and User-LED jumper have to be removed!)
|
||||
# SPI = machine.SPI(0) # GP14 (CLK) + GP16 (MOSI->DIN), User-LED jumper removed!
|
||||
# RST = machine.Pin('GP24')
|
||||
# CE = machine.Pin('GP12')
|
||||
# DC = machine.Pin('GP22')
|
||||
# LIGHT = machine.Pin('GP23')
|
||||
# PWR = directly from 3V3 pin of the WiPy
|
||||
|
||||
#try:
|
||||
# import pyb as machine
|
||||
#except:
|
||||
# # WiPy
|
||||
# import machine
|
||||
#
|
||||
#try:
|
||||
# import struct
|
||||
#except:
|
||||
# # ESP8266
|
||||
# import ustruct as struct
|
||||
|
||||
# ESP8266
|
||||
import machine
|
||||
import ustruct as struct
|
||||
|
||||
import time
|
||||
|
||||
class PCD8544:
|
||||
ADDRESSING_HORIZ = 0x00
|
||||
ADDRESSING_VERT = 0x02
|
||||
INSTR_BASIC = 0x00
|
||||
INSTR_EXT = 0x01
|
||||
POWER_UP = 0x00
|
||||
POWER_DOWN = 0x04
|
||||
DISPLAY_BLANK = 0x08
|
||||
DISPLAY_ALL = 0x09
|
||||
DISPLAY_NORMAL = 0x0c
|
||||
DISPLAY_INVERSE = 0x0d
|
||||
TEMP_COEFF_0 = 0x04
|
||||
TEMP_COEFF_1 = 0x05
|
||||
TEMP_COEFF_2 = 0x06
|
||||
TEMP_COEFF_3 = 0x07
|
||||
BIAS_1_4 = 0x17 # 1/4th
|
||||
BIAS_1_5 = 0x16 # 1/5th
|
||||
BIAS_1_6 = 0x15 # 1/6th
|
||||
BIAS_1_7 = 0x14 # 1/7th
|
||||
BIAS_1_8 = 0x13 # 1/8th
|
||||
BIAS_1_9 = 0x12 # 1/9th
|
||||
BIAS_1_10 = 0x11 # 1/10th
|
||||
BIAS_1_11 = 0x10 # 1/11th
|
||||
|
||||
def __init__(self, spi, rst, ce, dc, light, pwr=None):
|
||||
self.width = 84
|
||||
self.height = 48
|
||||
self.power = self.POWER_DOWN
|
||||
self.addressing = self.ADDRESSING_HORIZ
|
||||
self.instr = self.INSTR_BASIC
|
||||
self.display_mode = self.DISPLAY_BLANK
|
||||
self.temp_coeff = self.TEMP_COEFF_0
|
||||
self.bias = self.BIAS_1_11
|
||||
self.voltage = 3060
|
||||
|
||||
# init the SPI bus and pins
|
||||
#spi.init(spi.MASTER, baudrate=328125, bits=8, polarity=0, phase=1, firstbit=spi.MSB)
|
||||
spi.init(baudrate=328125)
|
||||
if "OUT_PP" in dir(rst):
|
||||
# pyBoard style
|
||||
rst.init(rst.OUT_PP, rst.PULL_NONE) # Reset line
|
||||
ce.init(ce.OUT_PP, ce.PULL_NONE) # Chip Enable
|
||||
dc.init(dc.OUT_PP, dc.PULL_NONE) # Data(1) / Command(0) mode
|
||||
light.init(light.OUT_PP, light.PULL_NONE)
|
||||
if pwr:
|
||||
pwr.init(pwr.OUT_PP, pwr.PULL_NONE)
|
||||
else:
|
||||
# WiPy style
|
||||
rst.init(rst.OUT, None)
|
||||
ce.init(ce.OUT, None)
|
||||
dc.init(dc.OUT, None)
|
||||
light.init(light.OUT, None)
|
||||
if pwr:
|
||||
pwr.init(pwr.OUT, None)
|
||||
|
||||
self.spi = spi
|
||||
self.rst = rst
|
||||
self.ce = ce
|
||||
self.dc = dc
|
||||
self.light = light
|
||||
self.pwr = pwr
|
||||
|
||||
self.light_off()
|
||||
self.power_on()
|
||||
self.ce.value(1) # set chip to disable (don't listen to input)
|
||||
self.reset()
|
||||
self.set_contrast(0xbf)
|
||||
self.clear()
|
||||
|
||||
def _set_function(self):
|
||||
""" Write current power/addressing/instructionset values to lcd. """
|
||||
value = 0x20 | self.power | self.addressing | self.instr
|
||||
self.command([value])
|
||||
|
||||
def set_power(self, power, set=True):
|
||||
""" Sets the power mode of the LCD controller """
|
||||
assert power in [self.POWER_UP, self.POWER_DOWN], "Power must be POWER_UP or POWER_DOWN."
|
||||
self.power = power
|
||||
if set:
|
||||
self._set_function()
|
||||
|
||||
def set_adressing(self, addr, set=True):
|
||||
""" Sets the adressing mode """
|
||||
assert addr in [self.ADDRESSING_HORIZ, self.ADDRESSING_VERT], "Addressing must be ADDRESSING_HORIZ or ADDRESSING_VERT."
|
||||
self.addressing = addr
|
||||
if set:
|
||||
self._set_function()
|
||||
|
||||
def set_instr(self, instr, set=True):
|
||||
""" Sets instruction set (basic/extended) """
|
||||
assert instr in [self.INSTR_BASIC, self.INSTR_EXT], "Instr must be INSTR_BASIC or INSTR_EXT."
|
||||
self.instr = instr
|
||||
if set:
|
||||
self._set_function()
|
||||
|
||||
def set_display(self, display_mode):
|
||||
""" Sets display mode (blank, black, normal, inverse) """
|
||||
assert display_mode in [self.DISPLAY_BLANK, self.DISPLAY_ALL, self.DISPLAY_NORMAL, self.DISPLAY_INVERSE], "Mode must be one of DISPLAY_BLANK, DISPLAY_ALL, DISPLAY_NORMAL or DISPLAY_INVERSE."
|
||||
assert self.instr == self.INSTR_BASIC, "Please switch to basic instruction set first."
|
||||
self.display_mode = display_mode
|
||||
self.command([display_mode])
|
||||
|
||||
def set_temp_coeff(self, temp_coeff):
|
||||
""" Sets temperature coefficient (0-3) """
|
||||
assert 4 <= temp_coeff < 8, "Temperature coefficient must be one of TEMP_COEFF_0..TEMP_COEFF_3."
|
||||
assert self.instr == self.INSTR_EXT, "Please switch to extended instruction set first."
|
||||
self.temp_coeff = temp_coeff
|
||||
self.command([temp_coeff])
|
||||
|
||||
def set_bias(self, bias):
|
||||
""" Sets the LCD bias. """
|
||||
assert 0x10 <= bias <= 0x17, "Bias must be one of BIAS_1_4..BIAS_1_11."
|
||||
assert self.instr == self.INSTR_EXT, "Please switch to extended instruction set first."
|
||||
self.bias = bias
|
||||
self.command([bias])
|
||||
|
||||
def set_voltage(self, millivolts):
|
||||
""" Sets the voltage of the LCD charge pump in millivolts. """
|
||||
assert 3060 <= millivolts <= 10680, "Voltage must be between 3,060 and 10,680 mV."
|
||||
assert self.instr == self.INSTR_EXT, "Please switch to extended instruction set first."
|
||||
self.voltage = millivolts
|
||||
basevoltage = millivolts - 3060
|
||||
incrementor = basevoltage // 60
|
||||
code = 0x80 & incrementor
|
||||
self.command([code])
|
||||
|
||||
def set_contrast(self, value):
|
||||
""" set LCD voltage, i.e. contrast """
|
||||
assert 0x80 <= value <= 0xff, "contrast value must be between 0x80 and 0xff"
|
||||
self.command([0x21, self.TEMP_COEFF_2, self.BIAS_1_7, value, 0x20, self.DISPLAY_NORMAL])
|
||||
# 0x21 - enter extended instruction set (H=1)
|
||||
# 0x06 - set temperature coefficient 2
|
||||
# 0x14 - set BIAS system to n=3 (recomm. mux rate 1:40/1:34)
|
||||
# value - (80-ff) - set Vop (80 = 3.00V, ff = 10.68V), 8b seems to work (0x3b/d70: 3.00+(70*0.06)=7.2V)
|
||||
# 0x20 - back to basic instruction set
|
||||
# 0x0c - normal display mode
|
||||
|
||||
def position(self, x, y):
|
||||
""" set cursor to bank y, column x """
|
||||
assert 0 <= x < self.width, "x must be between 0 and 83"
|
||||
assert 0 <= y < self.height // 8, "y must be between 0 and 5"
|
||||
assert self.instr == self.INSTR_BASIC, "Please switch to basic instruction set first."
|
||||
self.command([x + 0x80, y + 0x40])
|
||||
|
||||
def clear(self):
|
||||
""" clear screen """
|
||||
self.position(0, 0)
|
||||
self.data([0] * (self.height * self.width // 8))
|
||||
self.position(0, 0)
|
||||
|
||||
def sleep_ms(self, mseconds):
|
||||
try:
|
||||
time.sleep_ms(mseconds)
|
||||
except AttributeError:
|
||||
machine.delay(mseconds)
|
||||
|
||||
def sleep_us(self, useconds):
|
||||
try:
|
||||
time.sleep_us(useconds)
|
||||
except AttributeError:
|
||||
machine.udelay(useconds)
|
||||
|
||||
def power_on(self):
|
||||
if self.pwr:
|
||||
self.pwr.value(1)
|
||||
self.reset()
|
||||
|
||||
def reset(self):
|
||||
""" issue reset impulse to reset the display """
|
||||
self.rst.value(0) # RST on
|
||||
self.sleep_us(100) # reset impulse has to be >100 ns and <100 ms
|
||||
self.rst.value(1) # RST off
|
||||
# Defaults after reset:
|
||||
self.power = self.POWER_DOWN
|
||||
self.addressing = self.ADDRESSING_HORIZ
|
||||
self.instr = self.INSTR_BASIC
|
||||
self.display_mode = self.DISPLAY_BLANK
|
||||
self.temp_coeff = self.TEMP_COEFF_0
|
||||
self.bias = self.BIAS_1_11
|
||||
self.voltage = 3060
|
||||
|
||||
def power_off(self):
|
||||
self.clear()
|
||||
self.command([0x20, 0x08])
|
||||
# 0x20 - basic instruction set
|
||||
# 0x08 - set display to blank (doesn't delete contents)
|
||||
self.sleep_ms(10)
|
||||
if self.pwr:
|
||||
self.pwr.value(0) # turn off power
|
||||
|
||||
def command(self, arr):
|
||||
""" send bytes in command mode """
|
||||
self.bitmap(arr, 0)
|
||||
|
||||
def data(self, arr):
|
||||
""" send bytes in data mode """
|
||||
self.bitmap(arr, 1)
|
||||
|
||||
def bitmap(self, arr, dc):
|
||||
self.dc.value(dc)
|
||||
buf = struct.pack('B'*len(arr), *arr)
|
||||
self.ce.value(0) # set chip to listening/enable
|
||||
try:
|
||||
self.spi.send(buf)
|
||||
except AttributeError:
|
||||
self.spi.write(buf)
|
||||
self.ce.value(1) # set chip to disable
|
||||
|
||||
def light_on(self):
|
||||
self.light.value(0) # pull to GND
|
||||
|
||||
def light_off(self):
|
||||
self.light.value(1) # set to HIGH
|
Loading…
Reference in New Issue
Block a user