- 项目描述(项目介绍、设计思路、框图和软件流程图)
此次基于树莓派Pico的嵌入式系统学习平台实现项目1制作一个反应测试器.整体硬件框架如下:
两个按键用于开始结束/响应 ,OLED 用于显示 ,W2812 用于触发响应测试
整体思路如下:
1.点击KEY1 触发状态机开始,OLED 进行相应的提示
2.软件开始随机定时,触发随机的w2812 进行点亮,同时开始计时
3.等待用户点击Key2 ,点击后,将计算的反应时间显示到屏幕上
- 简单的硬件介绍
此次核心板采用树莓派pico rp2040芯片控制器, 双核m0 最高运行133M。学习资源比较丰富,支持C/C++ 开发 支持micopython 开发 支持arduino 开发等多种方式,创客们玩的比较多,片上资源也比较丰富,SPI I2C PWM GPIO PIO 等一应俱全。
搭配硬核提供的扩展板,可以学习ADC 采集 OLED 显示 W2812控制 按键 麦克风采集 PWM 蜂鸣器驱动等功能,非常适合大家进行学习 探讨。
- 实现的功能及图片展示此次主要基于硬核提供的micropython 进行功能开发,已完成基本的oled 显示,按键触发、w2812驱动,随机数产生等功能,实现项目1 就是依据前面定的状态逻辑图进行功能组合,整体实现状态如下图
- 主要代码片段及说明按键驱动 主要进行管脚指定,设定上升沿触发,200ms 进行延迟消抖
import time
from board import pin_cfg
from machine import Pin
class button:
def __init__(self, pin, callback=None, trigger=Pin.IRQ_RISING, min_ago=200):
#print("button init")
self.callback = callback
self.min_ago = min_ago
self._next_call = time.ticks_add(time.ticks_ms(), self.min_ago)
self.pin = Pin(pin, Pin.IN, Pin.PULL_UP)
self.pin.irq(trigger=trigger, handler=self.debounce_handler)
self._is_pressed = False
def call_callback(self, pin):
#print("call_callback")
self._is_pressed = True
if self.callback is not None:
self.callback(pin)
def debounce_handler(self, pin):
#print("debounce")
if time.ticks_diff(time.ticks_ms(), self._next_call) > 0:
self._next_call = time.ticks_add(time.ticks_ms(), self.min_ago)
self.call_callback(pin)
def value(self):
p = self._is_pressed
self._is_pressed = False
return p
k1 = button(pin_cfg.k1)
k2 = button(pin_cfg.k2)
oled 显示 基于ssd1306 实现屏幕显示驱动,指定spi 管脚,SSD1306寄存器配置等。
spi = SPI(1, 100000, mosi=Pin(pin_cfg.spi1_mosi), sck=Pin(pin_cfg.spi1_sck))
oled = SSD1306_SPI(128, 64, spi, Pin(pin_cfg.spi1_dc),Pin(pin_cfg.spi1_rstn), Pin(pin_cfg.spi1_cs))
oled.rotate(1)
由于需要输入中文,自己实现了中英文混输的方法,大概步骤如下:
1.使用pctolcd2000提取字模数据,设置格式如下:
提取到的数组如下:
fonts= {
字模型:[0x00,0x00,0x00,0x08,0x38,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x3E,0x00,0x00],#10
字模型:[0x00,0x00,0x00,0x3C,0x42,0x42,0x42,0x02,0x04,0x08,0x10,0x20,0x42,0x7E,0x00,0x00],#21
字模型:[0x00,0x00,0x00,0x3C,0x42,0x42,0x02,0x04,0x18,0x04,0x02,0x42,0x42,0x3C,0x00,0x00],#32
字模型:[0x00,0x00,0x00,0x04,0x0C,0x0C,0x14,0x24,0x24,0x44,0x7F,0x04,0x04,0x1F,0x00,0x00],#43
字模型:[0x00,0x00,0x00,0x7E,0x40,0x40,0x40,0x78,0x44,0x02,0x02,0x42,0x44,0x38,0x00,0x00],#54
字模型:[0x00,0x00,0x00,0x18,0x24,0x40,0x40,0x5C,0x62,0x42,0x42,0x42,0x22,0x1C,0x00,0x00],#65
字模型:[0x00,0x00,0x00,0x7E,0x42,0x04,0x04,0x08,0x08,0x10,0x10,0x10,0x10,0x10,0x00,0x00],#76
字模型:[0x00,0x00,0x00,0x3C,0x42,0x42,0x42,0x24,0x18,0x24,0x42,0x42,0x42,0x3C,0x00,0x00],#87
字模型:[0x00,0x00,0x00,0x38,0x44,0x42,0x42,0x42,0x46,0x3A,0x02,0x02,0x24,0x18,0x00,0x00],#98
字模型:[0x00,0x00,0x00,0x18,0x24,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x24,0x18,0x00,0x00],#09
}
编写了一个批量替换字典索引的python 脚本,功能是将上面的txt中"字模型"批量替换成对应字的utf-8 编码,用于程序使用时索引。使用时只需更新in_file idx_txt 即可
#输入文件
in_file = "1.txt"
txt_idx = "字模型"
idx_txt = "1234567890"
hex_data =[]
def txt2hex(ch_str):
global in_file
global txt_idx
global hex_data
for k in ch_str:
code = 0x00
data_code = k.encode("utf-8")
size = len(data_code)
code |= data_code[0] << 16
if size ==1:
code = code
elif size ==2:
code |= data_code[1] << 8
else:
code |= data_code[1] << 8
code |= data_code[2]
#print(k+" "+hex(code))
hex_data.append(str(hex(code)))
file = open (in_file,'r',encoding="utf-8")
lines = file.readlines()
file.close()
file = open(in_file,'w',encoding="utf-8")
idx =0
for con in lines:
#print(con)
if txt_idx in con:
con = con.replace(txt_idx,hex_data[idx])
idx=idx +1
file.write(con)
file.close()
txt2hex(idx_txt)
python 中实际调用接口函数
def str2lcd(self,ch_str,xx,yy):
for k in ch_str:
if k in ("1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijlkmnopqrstuvwxyz,.!(): "):
#8*16 字符模型
code =0x00
data_code = k.encode("utf-8")
#print("bytedata size ",len(data_code))
byte_data = fonts[data_code[0]<<16]
for y in range(0,16):
left8 = bin(byte_data[y]).replace('0b', '')
left8 = ('00000000'+left8)[-8:] #如果不足8位,直接补齐8位,如从0010,补齐成00000010,代表汉字每一行左半部分8个像素点。0代表像素点不亮,1代表像素点亮
for x in range(0,8):
self.pixel(xx+x,yy+y,int(left8[x]))
xx=xx+8
else:
code = 0x00 # 将中文转成16进制编码
data_code = k.encode("utf-8")
code |= data_code[0] << 16
code |= data_code[1] << 8
code |= data_code[2]
byte_data = fonts[code]
for y in range(0, 16):
left8 = bin(byte_data[y]).replace('0b', '')
left8 = ('00000000'+left8)[-8:] #如果不足8位,直接补齐8位,如从0010,补齐成00000010,代表汉字每一行左半部分8个像素点。0代表像素点不亮,1代表像素点亮
right8 = bin(byte_data[y+16]).replace('0b', '')
right8 = ('00000000'+right8)[-8:] #代表汉字每一行右半部分8个像素点
all16 = left8+right8 #拼成每一行16个像素点
#print(all16)
for x in range(0, 16): #开始循环检测,如果是1,则在这个位置点亮像素点
'''
if all16[x] == "1" :
self.pixel(xx+x,yy+y,255)
'''
self.pixel(xx+x,yy+y,int(all16[x]))
xx=xx+16 #显示完一个汉字,显示下一个时,x位置向右移16像素
- 遇到的主要难题及解决方法
最初只使用单键进行功能实现,后来发现逻辑有漏洞,后续增加开始结束按键,使整个逻辑判断更加严谨。
按键延迟不能调的太长,否则会与真是成绩有偏差
- 未来的计划或建议后面多多举办这样的活动,让更多小伙伴们可以加入,一起学习交流