笔者在提交试用申请时填写的项目计划是制作一个物联网密码柜,本阶段的主要目标是驱动矩阵键盘和Oled显示器,为后续完整的物联网密码柜项目打下基础。采用Thonny编辑器+circuitpython进行开发,矩阵键盘驱动为自行编写,Oled驱动基于Adafruit SSD_1306库。
到本阶段为止已实现的功能:
后续需要进行完善的功能:
本次开发使用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):
# 当前行IO拉低
row.value = False
# 逐列检查
for j, col in enumerate(self.cols):
current_key = (i, j)
# 按键按下
if not col.value:
time.sleep(0.01) #延迟10ms消抖
if not col.value:
# 重新拉高行IO
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
# 重新拉高行IO
row.value = True
# 没有按键按下
return None
笔者所购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.
"""
# determine our effective width/height, taking rotation into account
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:
# load the font!
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) # 防止CPU占用过高
本次使用circuitpython实现了对矩阵键盘和Oled显示屏的驱动以及密码校验部分,为后续物联网密码柜的制作打下了基础。
最后放一个密码输入演示视频。
更多回帖