简介
笔者在提交试用申请时填写的项目计划是制作一个物联网密码柜,本阶段的主要目标是驱动矩阵键盘和Oled显示器,为后续完整的物联网密码柜项目打下基础。采用Thonny编辑器+circuitpython进行开发,矩阵键盘驱动为自行编写,Oled驱动基于Adafruit SSD_1306库。
到本阶段为止已实现的功能:
- 矩阵键盘的输入与识别
- 密码校验
- 边缘检测及错误处理
- SSD1306显示器的驱动
后续需要进行完善的功能:
- 物联网密码柜其它外设的驱动
- 蓝牙服务的驱动,实现物联网
circuitpython固件的刷入及编辑器的设置
本次开发使用circuitpython进行开发,circuitpython开发便捷并且有众多开源库可以参考。
首先在circuitpython官网找到EFR32xG24 Explorer Kit的固件进行下载
下载完成后,再使用Silicon Labs的官方软件Simplicity Commander将circuitpython固件刷入开发板中,刷固件前记得先擦除整片flash
circuitpython固件刷写完成之后,保持开发板与电脑的连接,打开Thonny编辑器,选择circuitpython为解释器并选择开发板连接的串口
然后将有关代码提示的设置打开,方便后续开发
矩阵键盘的驱动
矩阵键盘的实现原理并不难,就是逐行扫描,由于硬件和成本的局限性和对实际密码输入场景的考量,这里仅考虑单一按键同时按下的情况(如果有多个按键同时按下,则按扫描顺序返回第一个按键)。
核心业务代码如下:
def scan_keyboard(self):
"""扫描矩阵键盘并返回按下的按键(row, col),如果按键已被按下则不重复返回"""
for i, row in enumerate(self.rows):
row.value = False
for j, col in enumerate(self.cols):
current_key = (i, j)
if not col.value:
time.sleep(0.01)
if not col.value:
row.value = True
if current_key != self.pressed_key:
self.pressed_key = current_key
return current_key
else:
if current_key == self.pressed_key:
self.pressed_key = None
row.value = True
return None
Oled屏幕的驱动
笔者所购0.96英寸Oled屏幕为SSD1315,对应的驱动实在难找,好在SSD1306与SSD1315十分相似,于是选择使用Adafruit SSD_1306驱动库进行驱动。
首先进入到circuitpython官网的文档库,找到SSD_1306有关的驱动
笔者这里使用基于framebuf的驱动库,可以看到这个驱动库需要先安装framebuf驱动库和bus device驱动库(circuitpython固件已内置),点击左侧的“Download from Github”进入下载链接
同理找到Framebuf Module驱动库,按照上述流程进行下载
下载完成后解压压缩包,将压缩包内lib文件夹下的py文件上传至开发板的lib文件夹
framebuf驱动库下的examples文件夹下有一个font5x8.bin,这是framebuf依赖的字符库,需要一同上传到lib文件夹下(在哪里调用就上传到哪)
示例代码如下:
def text(self, string, x, y, color, *, font_name="font5x8.bin", size=1):
"""Place text on the screen in variables sizes. Breaks on \\\\\\\\n to next line.
Does not break on line going off screen.
"""
frame_width = self.width
frame_height = self.height
if self.rotation in (1, 3):
frame_width, frame_height = frame_height, frame_width
for chunk in string.split("\\\\\\\\n"):
if not self._font or self._font.font_name != font_name:
self._font = BitmapFont(font_name)
width = self._font.font_width
height = self._font.font_height
for i, char in enumerate(chunk):
char_x = x + (i * (width + 1)) * size
if (
char_x + (width * size) > 0
and char_x < frame_width
and y + (height * size) > 0
and y < frame_height
):
self._font.draw_char(char, char_x, y, self, color, size=size)
y += height * size
依赖库准备完成后,定义oled显示方法,方便主程序调用
import board
import busio
import adafruit_ssd1306
class OledManager:
def __init__(self, width, height, i2c):
self.oled = adafruit_ssd1306.SSD1306_I2C(width, height, i2c)
self.bgColor = 0
def clear(self):
self.oled.fill(self.bgColor)
def show_text(self, text):
self.oled.text(text, 0, 0, not self.bgColor, font_name='font5x8.bin', size=1)
self.oled.show()
def show_star(self, num):
self.oled.text("*"*num, 0, 8, not self.bgColor, font_name='font5x8.bin', size=1)
self.oled.show()
def show_result(self, result=False):
if(result):
self.oled.text("Right!", 0, 16, not self.bgColor, font_name='font5x8.bin', size=2)
else:
self.oled.text("Wrong!", 0, 16, not self.bgColor, font_name='font5x8.bin', size=2)
self.oled.show()
由于笔者对oled的使用不太了解,加上又是第一次使用circuitpython进行开发,所以这里将密码校验的相关部分显示在哪个位置全部定死了,后续可能会考虑进行优化
密码校验核心业务代码
def check_pwd(password):
return password == saved_password
def handle_input(key, password):
"""处理密码输入逻辑"""
if key==(3, 1):
password = password[:-1]
return password
if len(password) < PASSWORD_MAX_LENGTH:
password += keyboard_char_map.get(key, '')
return password
def display_tip(oled, tip="Password:"):
oled.show_text(tip)
def display_password(oled, password):
oled.clear()
display_tip(oled)
oled.show_star(len(password))
def display_result(oled, result):
oled.clear()
display_tip(oled)
oled.show_result(result)
主程序核心业务代码
def main():
global password
display_tip(oled)
while True:
key = keyboard.scan_keyboard()
if key:
if key==(3,2):
display_result(oled, result=check_pwd(password))
password = ""
else:
password = handle_input(key, password)
display_password(oled, password)
time.sleep(0.01)
阶段性总结
本次使用circuitpython实现了对矩阵键盘和Oled显示屏的驱动以及密码校验部分,为后续物联网密码柜的制作打下了基础。
最后放一个密码输入演示视频。