一、前言
跟着b站王铭东老师学了几天基于microPython的esp32,想着不能光学习不总结,于是在这水一篇文章,简单讲讲自己对于显示二维码的理解。具体课程大家可以去b站找王老师的视频学习:课程链接
在进行esp32控制显示二维码之前有一些准备工作需要完成。由于是用microPython开发,所以我们首先需要一个舒适的开发环境,这里我们选择的是Thonny(也不知道还有没有其他的)。Thonny的下载链接我放这里了:Thonny,启动!。
二、ESP32介绍
ESP32 是集成 2.4 GHz Wi-Fi 和蓝牙双模的单芯片方案,采用台积电 (TSMC) 超低功耗的 40 纳米工艺,具有超高的射频性能、稳定性、通用性和可靠性,以及超低的功耗,满足不同的功耗需求,适用于各种应用场景。
市面上有很多不同型号的esp32开发板,这让作为初学者的我在选择时犯了难,在翻越诸多大佬的文章后,选择了ESP32 DEVKIT DOIT作为学习的开发板。正好王老师的课程用的也是这个型号,还没购买的小伙伴可以在这个链接购买:淘宝,启动!,在拿到板子后还需要更新固件,具体教程王老师在课程里都有相应的讲解:基础01-Thonny+MicroPython+ESP32环境搭建_哔哩哔哩_bilibili
三、屏幕
显示屏用的是淘宝购买的套件里自带的一块240x240tft屏幕,采用SPI通信协议。
1.引脚接线
屏幕有8个引脚,具体说明如下图所示:
为了正常控制该屏幕的显示,需按照下图接线:
2.驱动库
使用王铭东老师发在b站上的开源库:https://doc.itprojects.cn/0006.zhishi.esp32/01.download/new/st7789_itprojects.py
下载后,上载到esp32,并在main.py中导入该包即可使用。
四、显示二维码
1.产生二维码
在电脑端使用qrcode模块可以轻易得到二维码。但该模块不能直接用到MicroPython上,所幸有国外的大佬已经为我们做好了移植工作,我们直接下载python文件并放入Thonny即可使用:qrcode模块下载
国外大佬提供的使用demo如下:
from uQR import QRCode #导入
qr = QRCode() #创建一个QR对象
qr.add_data('uQR rocks!') #使用方法添加数据(在这里添加什么数据,扫二维码显示的就是什么数据)
matrix = qr.get_matrix() #取出文字内容编码成二维码后的数据(得到一串列表)
#返回列表中 True代表黑色 False代表白色
当我们使用这个库将所需要的数据转换成二维码形式后就能得到一串列表,其内容由True 和 False构成,True代表黑色,False代表白色,接下来我们只需要将对应的颜色显示在屏幕上就能构成一块二维码 了。
2.显示二维码
我们打印上一步产生的列表就可以发现它本质上是一个n*n的嵌套列表,根据列表值,我们只需将屏幕上的对应的点设置成黑或白色即可。这里还需要考虑一个问题:生成的二维码大约为20-40行大小,直接按照行列显示在240x240的屏幕上会显得很小,不便扫码,因此可以对其进行适当的放大。我这里产生了一个29x29的二维码,考虑到屏幕大小为240x240,因此我把二维码放大8倍显示,即显示232*232。放大的代码如下:
#放大倍数
scale_rate = 8
for row in range(row_len * scale_rate):
for col in range(col_len * scale_rate):
if matrix[row//scale_rate][col//scale_rate]:
tft.pixel(row, col, st7789_itprojects.color565(0, 0, 0)) #将该点设置为黑色
else:
tft.pixel(row, col, st7789_itprojects.color565(255, 255, 255)) #将该点设置为白色
col = col + 1
row = row + 1
在实际显示的时候,我们可以先打印查看一下产生的matrix列表的大小,再选择合适的放大倍数。至此,二维码成功显示。
五、完整代码
from uQR import QRCode
from machine import Pin, SPI
import st7789_itprojects
tft = st7789_itprojects.ST7889_Image(SPI(2,80000000), dc = Pin(2), cs = Pin(5), rst = Pin(15)) #创建屏幕对象
tft.fill(st7789_itprojects.color565(255,255,255)) #设置背景为白色
qr = QRCode(border = 2) #创建qr对象
qr.add_data('赶紧爬去学习') #添加内容
matrix = qr.get_matrix() #生成二维码
#计算行列数
row_len = len(matrix)
col_len = len(matrix)
print('row = {}, col = {}'.format(row_len,col_len))
#放大倍数
scale_rate = 8
for row in range(row_len * scale_rate):
for col in range(col_len * scale_rate):
if matrix[row//scale_rate][col//scale_rate]:
tft.pixel(row, col, st7789_itprojects.color565(0, 0, 0)) #将该点设置为黑色
else:
tft.pixel(row, col, st7789_itprojects.color565(255, 255, 255)) #将该点设置为白色
col = col + 1
row = row + 1
六、总结与改进
根据上述流程,我们已经成功用esp32控制屏幕显示了二维码,但在实际使用过程中可以观察到二维码在屏幕显示过程中极其缓慢,这是由于在显示二维码时,我们使用了两层for循环,每次只向st7789传输1个点的显示数据,这就造成完整显示一张二维码需要进行四万多次的传输,而Python毕竟不如C快,所以为了提升显示的效率,我们需要相应地减少数据发送的次数。
这里的处理思路是:将黑色和白色的信息存入我们预先设定的符合放大后一个点大小的列表里存储即scale_rate * scale_rate * 2(一个颜色信息由两个字节组成,放大倍数为scale_rate)。在显示二维码时,我们只需按照生成二维码的原有尺寸进行遍历,但这次我们传输的数据是原来的scale_rate * scale_rate 倍。我原先设定的放大倍数是8,因此数据传输效率提升至了原来的64倍,我们可以清晰的观察到二维码显示速度提升了。
from uQR import QRCode
from machine import Pin, SPI
import st7789_itprojects
tft = st7789_itprojects.ST7889_Image(SPI(2,80000000), dc = Pin(2), cs = Pin(5), rst = Pin(15)) #创建屏幕对象
tft.fill(st7789_itprojects.color565(255,255,255)) #设置背景为白色
qr = QRCode(border = 2) #创建qr对象
qr.add_data('赶紧爬去学习') #添加内容
matrix = qr.get_matrix() #生成二维码
#计算行列数
row_len = len(matrix)
col_len = len(matrix)
print('row = {}, col = {}'.format(row_len,col_len))
#放大倍数
scale_rate = 8
#准备白色、黑色数据
buffer_black = bytearray(scale_rate * scale_rate * 2) #每个点pixel有2个字节表示颜色
buffer_white = bytearray(scale_rate * scale_rate * 2) #以上两句相当于开辟出一个8*8的空间,每个空间可以存放2个字节的颜色数据
color_black = st7789_itprojects.color565(0, 0, 0) #含两个字节
color_black_byte1 = color_black & 0xff00 >> 8 #取出高字节
color_black_byte2 = color_black & 0xff #取出低字节
color_white = st7789_itprojects.color565(255,255,255)
color_white_byte1 = color_white & 0xff00 >> 8 #取出高字节
color_white_byte2 = color_white & 0xff #取出低字节
for i in range(0, scale_rate * scale_rate * 2, 2):
buffer_black[i] = color_black_byte1
buffer_black[i + 1] = color_black_byte2
buffer_white[i] = color_white_byte1
buffer_white[i + 1] = color_white_byte2
#循环次数不再增加,只增加每次发送的数据量,每次发送scale_rate * scale_rate 个点的颜色信息
for row in range(row_len):
for col in range(col_len):
if matrix[row][col]:
#tft.pixel(row, col, st7789_itprojects.color565(0, 0, 0)) #将该点设置为黑色
tft.show_img(row * scale_rate, col * scale_rate, row * scale_rate + scale_rate - 1, col * scale_rate + scale_rate - 1, buffer_black)
else:
#tft.pixel(row, col, st7789_itprojects.color565(255, 255, 255)) #将该点设置为白色
tft.show_img(row * scale_rate, col * scale_rate, row * scale_rate + scale_rate - 1,