简介
合宙esp32C3,128*64 I2C oled,硬件i2c,将下面两个py文件放入esp32.
ssd1306.py是我优化后的,为了避免错误,使用我提供的ssd1306驱动
只支持128*64的I2C oled
代码
main.py
import network
import urequests
import ujson
import time
from machine import RTC,Pin,I2C,Timer
from ssd1306 import SSD1306_I2C
#实例化oled屏
i2c=I2C(0,scl=Pin(5),sda=Pin(4))
oled=SSD1306_I2C(i2c)
#联网设置
url='http://worldtimeapi.org/api/timezone/Asia/Shanghai'
rtc=RTC()
wifi=network.WLAN(network.STA_IF)
wifi.active(True)
#连接wifi,有一定几率连接失败
while not wifi.isconnected():
wifi.connect('szsb','55555555')
oled.fill(0)
oled.text('connecting...',0,0)
oled.show()
#更新显示连接wifi信息
oled.fill(0)
oled.text('connect to szsb',0,0)
oled.show()
#获取网络时钟
response=urequests.get(url)
if response.status_code==200:
parsed=ujson.loads(response.text)#用json处理获取的文本
datetime_str=str(parsed['datetime'])
year=int(datetime_str[0:4])
month=int(datetime_str[5:7])
day=int(datetime_str[8:10])
hour=int(datetime_str[11:13])
minute=int(datetime_str[14:16])
second=int(datetime_str[17:19])
msecond=int(datetime_str[20:26])
#将(年,月,日,星期,小时,分钟,秒,毫秒)赋值给内部实时时钟RTC
rtc.datetime((year,month,day,parsed['day_of_week'],hour,minute,second,msecond))
#定时器回调函数,从已经初始化的RTC读取时间信息并显示到oled屏
def gain_time():
date_str='{:4}/{:02}/{:02}'.format(rtc.datetime()[0],rtc.datetime()[1],rtc.datetime()[2])
time_str='{:02}:{:02}:{:02}'.format(rtc.datetime()[4],rtc.datetime()[5],rtc.datetime()[6])
oled.fill(0)
oled.text('SCAU Clock',20,0)
oled.text('Date:'+date_str,0,25)
oled.text('Time:'+time_str,0,35)
oled.text('week:'+str(rtc.datetime()[3]+1),0,45)
oled.show()
#死循环,1秒调用1次回调函数
while True:
tim=Timer(0)
tim.init(period=1000, mode=Timer.PERIODIC, callback=gain_time())
ssd1306.py
import framebuf
# 寄存器定义
SET_CONTRAST = const(0x81)
SET_ENTIRE_ON = const(0xa4)
SET_NORM_INV = const(0xa6)
SET_MEM_ADDR = const(0x20)
SET_COL_ADDR = const(0x21)
SET_PAGE_ADDR = const(0x22)
SET_DISP_START_LINE = const(0x40)
SET_DISP = const(0xae)
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,external_vcc):
self.width = 128
self.height = 64
self.external_vcc = external_vcc
self.pages = 8
self.init_display()
def init_display(self):
for cmd in (
SET_DISP | 0x00, #熄屏
SET_MEM_ADDR, 0x00, #水平寻址
SET_DISP_START_LINE | 0x00,#显示起始行地址
SET_SEG_REMAP | 0x01, # column addr 127 mapped to SEG0
SET_MUX_RATIO, 63,
SET_COM_OUT_DIR | 0x08, # scan from COM[N] to COM0
SET_DISP_OFFSET, 0x00,
SET_COM_PIN_CFG, 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,
0x2e, # 禁止滚动
0xae | 0x01): #开屏
self.write_cmd(cmd)
self.fill(0)
self.show()
def v_scroll(self, d=1):
self.write_cmd(0x2e) # 关闭滚动
if d:
self.write_cmd(0x26) # 向左
self.write_cmd(0x00)
self.write_cmd(0x07) # 起始页
self.write_cmd(0x00) # 滚动帧率
self.write_cmd(0x00) # 结束页
else:
self.write_cmd(0x27) # 向左
self.write_cmd(0x00)
self.write_cmd(0x00) # 起始页
self.write_cmd(0x00) # 滚动帧率
self.write_cmd(0x07) # 结束页
self.write_cmd(0x00)
self.write_cmd(0xff)
self.write_cmd(0x2f) # 开启滚动
def poweroff(self):
self.write_cmd(const(0xae) | 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):
self.write_cmd(SET_COL_ADDR)
self.write_cmd(0)
self.write_cmd(127)
self.write_cmd(SET_PAGE_ADDR)
self.write_cmd(0)
self.write_cmd(63)
self.write_framebuf()
def fill(self, c):
self.framebuf.fill(c)
def pixel(self, x, y, c):
self.framebuf.pixel(x, y, c)
def text(self, string, x, y, c=1):
self.framebuf.text(string, x, y, c)
def hline(self,x,y,w,c=1):
self.framebuf.hline(x,y,w,c)
def vline(self,x,y,h,c=1):
self.framebuf.vline(x,y,h,c)
def line(self,x1,y1,x2,y2,c=1):
self.framebuf.line(x1,y1,x2,y2,c)
def rect(self,x,y,w,h,c=1,f=False):
self.framebuf.rect(x,y,w,h,c,f)
def ellipse(self,x,y,xr,yr,c,f=False,m=15):
self.framebuf.ellipse(x,y,xr,yr,c,f,m)
def cube(self,x,y,l):
self.rect(x,y,l,l)
self.rect(x+int(0.5*l),int(y-0.5*l),l,l)
self.line(x,y,int(x+0.5*l),int(y-0.5*l),1)
self.line(x+l,y,int(x+1.5*l),int(y-0.5*l),1)
self.line(x,y+l,int(x+0.5*l),int(y+0.5*l),1)
self.line(x+l,y+l,int(x+1.5*l),int(y+0.5*l),1)
def p8(self,page,x,y):
for e in range(8):
byte=bin(page[e]).replace('0b','')
while len(byte)<8:
byte='0'+byte
for i in range(8):
if byte[i]=='1':
self.pixel(x+e,y+i,int(byte[i]))
def p16(self,page,x,y):
for e in range(32):
byte=bin(page[e]).replace('0b','')
while len(byte)<8:
byte='0'+byte
for i in range(8):
if byte[i] and e<16:
self.pixel(x+e,y+i,int(byte[i]))
elif byte[i] and e>=16:
self.pixel(x-16+e,y+8+i,int(byte[i]))
def p32(self,page,x,y):
for e in range(128):
byte=bin(page[e]).replace('0b','')
while len(byte)<8:
byte='0'+byte
for i in range(8):
if byte[i] and e<32:
self.pixel(x+e,y+i,int(byte[i]))
elif byte[i] and 32<=e<64:
self.pixel(x+e-32,y+8+i,int(byte[i]))
elif byte[i] and 64<=e<96:
self.pixel(x+e-64,y+16+i,int(byte[i]))
elif byte[i] and 96<=e<128:
self.pixel(x+e-96,y+24+i,int(byte[i]))
class SSD1306_I2C(SSD1306):
def __init__(self,i2c, addr=0x3c, external_vcc=False):
self.i2c = i2c
self.addr = addr
self.temp = bytearray(2)
# buffer需要8 * 128的显示字节加1字节命令
self.buffer = bytearray(8 * 128 + 1)
self.buffer[0] = 0x40 # Co=0, D/C=1
self.framebuf = framebuf.FrameBuffer1(memoryview(self.buffer)[1:], 128, 64)
super().__init__(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):
self.i2c.writeto(self.addr, self.buffer)