# MicroPython SSD1306 OLED driver, I2C and SPI interfaces
from micropython import const
import framebuf
from machine import Pin,SoftI2C,ADC,PWM
import time
#使用X1,即18引脚。
S1 = PWM(Pin(15), freq=50, duty=0) # Servo1的引脚是18
'''
说明:舵机控制函数
功能:180度舵机:angle:-90至90 表示相应的角度
360连续旋转度舵机:angle:-90至90 旋转方向和速度值。
'''
def Servo(servo,angle):
S1.duty(int(((angle+90)*2/180+0.5)/20*1023))
def run_servo(data):
#-90度
network_subtext3=[['back','m.initText(subtext)']]
m.initText(network_subtext3)
oled.text("Connect Success!", 0, 30)
Servo(S1,-90)
oled.show()
# 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)
# Subclassing FrameBuffer provides support for graphics primitives
# http://docs.micropython.org/en/latest/pyboard/library/framebuf.html
class SSD1306(framebuf.FrameBuffer):
def __init__(self, width, height, external_vcc):
self.width = width
self.height = height
self.external_vcc = external_vcc
self.pages = self.height // 8
self.buffer = bytearray(self.pages * self.width)
super().__init__(self.buffer, self.width, self.height, framebuf.MONO_VLSB)
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 poweron(self):
self.write_cmd(SET_DISP | 0x01)
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_data(self.buffer)
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)
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_data(self, buf):
self.temp[0] = self.addr << 1
self.temp[1] = 0x40 # Co=0, D/C#=1
self.i2c.start()
self.i2c.write(self.temp)
self.i2c.write(buf)
self.i2c.stop()
class SSD1306_SPI(SSD1306):
def __init__(self, width, height, spi, dc, res, cs, external_vcc=False):
self.rate = 10 * 1024 * 1024
dc.init(dc.OUT, value=0)
res.init(res.OUT, value=0)
cs.init(cs.OUT, value=1)
self.spi = spi
self.dc = dc
self.res = res
self.cs = cs
import time
self.res(1)
time.sleep_ms(1)
self.res(0)
time.sleep_ms(10)
self.res(1)
super().__init__(width, height, external_vcc)
def write_cmd(self, cmd):
self.spi.init(baudrate=self.rate, polarity=0, phase=0)
self.cs(1)
self.dc(0)
self.cs(0)
self.spi.write(bytearray([cmd]))
self.cs(1)
def write_data(self, buf):
self.spi.init(baudrate=self.rate, polarity=0, phase=0)
self.cs(1)
self.dc(1)
self.cs(0)
self.spi.write(buf)
self.cs(1)
# MicroPython menu driver on ssd1306 interfaces
#Code By WMD 2019-4-16 21:18:28
from micropython import const
class menu:
def __init__(self,display,x,y,w,h):
'''
Init menu bar area in a screen.
Arg display is the ssd1306 object
X and y is the start point of the screen
w and h set the width and height of the menu.
Tips: You can create a menu area which not use all of the screen space,so that you can use remaining area to display other views.
Warning: This area couldn't bigger than the screen display area
'''
self.display=display
self.hightlightnum=0
self.menux=x
self.menuy=y
self.menuw=w
self.menuh=h
def initText(self,TextList,offset=0,hightlightnum=0):
'''
Init menuText in menu bar.
this function will refresh menu area to new TextList
arg TextList should be a list. The first element is the text to display, and the second element is
arg offset is use to display middle parts of the menu.
the command.When submenu is needed, the command should be 'initText(theSubTextList)'
'''
self.display.fill_rect(self.menux,self.menuy,self.menuw,self.menuh,0) #clear old menu
self.menuoffset=offset #Save offset value
self.nowlist=TextList
for i in range(len(TextList)):
if (i+1)*10>self.menuh: #Text is out of range
break
self.display.text(TextList[i+offset][0],self.menux+1,self.menuy+i*10+1,1)
self.moveHighLight(hightlightnum)
def moveHighLight(self,num):
'''
Select HightLight num
The argument num is relative the manu bar, not equal to Selected element
'''
self.display.rect(self.menux, self.menuy+self.hightlightnum*10, self.menuw, 10,0) #clear old rect
self.hightlightnum=num
self.display.rect(self.menux, self.menuy+self.hightlightnum*10, self.menuw, 10,1) #set new rect
def moveDown(self):
'''
User function.
Make menu downside one element
'''
if(self.menuoffset+self.hightlightnum == len(self.nowlist)-1): ## equal to max value
return
if (self.hightlightnum+2)*10>self.menuh: #Text is out of range
self.initText(self.nowlist,self.menuoffset+1,self.hightlightnum) #refresh the Text List
else:
self.moveHighLight(self.hightlightnum+1)
def moveUp(self):
'''
User function.
Make menu upside one element
'''
if(self.menuoffset+self.hightlightnum == 0): ## equal to min value
return
if self.hightlightnum==0: #Text is out of range
self.initText(self.nowlist,self.menuoffset-1,self.hightlightnum) #refresh the Text List
else:
self.moveHighLight(self.hightlightnum-1)
def click(self):
'''
User function.
run the selected element command.
'''
#if self.nowlist[self.menuoffset+self.hightlightnum][1][0]=='@': #this point to another menu
# tmp=self.nowlist[self.menuoffset+self.hightlightnum][1].lstrip('@')
# self.initText()
eval(self.nowlist[self.menuoffset+self.hightlightnum][1])
def clickSpecial(self):
'''
User function.
run the selected element command.
it can be use like a "long press"
'''
if self.nowlist[self.menuoffset+self.hightlightnum][2] is True:
eval(self.nowlist[self.menuoffset+self.hightlightnum][2])
def a():
print('hello')
oled_iic=SoftI2C(sda=Pin(4),scl=Pin(5)) #edit to your IIC OLED Pin
oled=SSD1306_I2C(128,64,oled_iic) #edit to your IIC OLED DPI
oled.fill(0xff)
text=[['music','print("perform a music")'],['photo','m.initText(subtext)','print("Special click detacted")'],['game','a']]
subtext=[['back','m.initText(text)'],['see photo a','run_servo(1)']]
m=menu(oled,0,0,128,64)
m.initText(text) # main menu
oled.show()
event_ctrl={1:m.moveUp,2:m.moveDown,3:m.click}
event_id=0
lock=0
event_id0=0
event_ctrl[2]()
oled.show()
time.sleep(0.3)
event_ctrl[3]()
oled.show()
time.sleep(0.3)
event_ctrl[2]()
oled.show()
time.sleep(0.3)
event_ctrl[3]()
oled.show()
time.sleep(0.3)
event_ctrl[1]()
oled.show()
time.sleep(0.3)
# while True:
# for i in range(1,4):
# event_ctrl[i]()
# event_id0=0
# oled.show()
# time.sleep(0.3)