物联网开发111 - Micropython ESP32 C3连接4x4矩阵按键模块操作

一、目的

        这一节我们来学习如何使用合宙ESP32 C3,连接0.96寸ssd1306屏幕、4x4 矩阵按键模块,进行两个小实验的演示。

二、环境

        ESP32 C3开发板(MicroPython v1.19.1 on 2022-06-18)+ I2C 0.96寸ssd1306屏幕模块+ 4x4 矩阵按键模块  + 几根杜邦线 + Win10商业版

        ESP32 C3和各个模块接线方法:

 三、示例代码1

演示将按下的按键名字显示在屏幕上

from machine import Pin,I2C
from ssd1306 import SSD1306_I2C
from ufont import BMFont
import time

# 创建I2C对象
i2c  = I2C(0,scl = Pin(5),sda = Pin(4),freq = 400_000)
# 创建oled屏幕对象
oled = SSD1306_I2C(128,64,i2c,0x3c)
# 定义字库文件
font = BMFont("fonts/unifont-14-12888-16.v3.bmf")
# 创建led对象
led = Pin(12,Pin.OUT)  # 板载led D4

# 行定义
R1 = Pin( 2,Pin.OUT)
R2 = Pin( 3,Pin.OUT)
R3 = Pin(10,Pin.OUT)
R4 = Pin( 6,Pin.OUT)

# 列第一
C1 = Pin( 7,Pin.IN,Pin.PULL_UP)
C2 = Pin( 8,Pin.IN,Pin.PULL_UP)
C3 = Pin(18,Pin.IN,Pin.PULL_UP)
C4 = Pin(19,Pin.IN,Pin.PULL_UP)

# 创建按键函数
def Key():
    
#     R1.value(0)
#     R2.value(1)
#     R3.value(1)
#     R4.value(1)
    
    key = 0
    bzw = 0
    
    # 第一行
    [R1.value(0),R2.value(1),R3.value(1),R4.value(1)]
    if(C1.value() == 0 or C2.value() == 0 or C3.value() == 0 or C4.value() == 0):
        
        time.sleep(0.020)
        
        if C1.value() == 0:
            bzw = 1
            key = 0
            while not C1.value():
                None
        elif C2.value() == 0:
            bzw = 1
            key = 1
            while not C2.value():
                None               
        elif C3.value() == 0:
            bzw = 1
            key = 2
            while not C3.value():
                None
        elif C4.value() == 0:
            bzw = 1
            key = 3
            while not C4.value():
                None
        else:
            
            key = 0
            bzw = 0
            R1.value(1)
            
    # 第二行
    [R1.value(1),R2.value(0),R3.value(1),R4.value(1)]
    if(C1.value() == 0 or C2.value() == 0 or C3.value() == 0 or C4.value() == 0):
        
        time.sleep(0.020)
        
        if C1.value() == 0:
            bzw = 1
            key = 4
            while not C1.value():
                None
        elif C2.value() == 0:
            bzw = 1
            key = 5
            while not C2.value():
                None               
        elif C3.value() == 0:
            bzw = 1
            key = 6
            while not C3.value():
                None
        elif C4.value() == 0:
            bzw = 1
            key = 7
            while not C4.value():
                None
        else:
            
            key = 0
            bzw = 0
            R1.value(1)
            
    # 第三行
    [R1.value(1),R2.value(1),R3.value(0),R4.value(1)]
    if(C1.value() == 0 or C2.value() == 0 or C3.value() == 0 or C4.value() == 0):
        
        time.sleep(0.020)
        
        if C1.value() == 0:
            bzw = 1
            key = 8
            while not C1.value():
                None
        elif C2.value() == 0:
            bzw = 1
            key = 9
            while not C2.value():
                None               
        elif C3.value() == 0:
            bzw = 1
            key = 10
            while not C3.value():
                None
        elif C4.value() == 0:
            bzw = 1
            key = 11
            while not C4.value():
                None
        else:
            
            key = 0
            bzw = 0
            R1.value(1)

    # 第四行
    [R1.value(1),R2.value(1),R3.value(1),R4.value(0)]
    if(C1.value() == 0 or C2.value() == 0 or C3.value() == 0 or C4.value() == 0):
        
        time.sleep(0.020)
        
        if C1.value() == 0:
            bzw = 1
            key = 12
            while not C1.value():
                None
        elif C2.value() == 0:
            bzw = 1
            key = 13
            while not C2.value():
                None               
        elif C3.value() == 0:
            bzw = 1
            key = 14
            while not C3.value():
                None
        elif C4.value() == 0:
            bzw = 1
            key = 15
            while not C4.value():
                None
        else:
            
            key = 0
            bzw = 0
            R1.value(1)


    if bzw == 1:
        bzw = 0
        
        if key == 3:
            led.value(not led.value())
            
        print("%d"%key)
        font.text(oled,"%.2d"%(key),48,16,color=1,font_size=24,reverse=False,clear=True,show=True,half_char=True, auto_wrap=True)
        time.sleep(0.1)
        
def main():
    font.text(oled,str("矩阵按值"),32,24,color=1,font_size=16,reverse=False,clear=False,show=True,half_char=True, auto_wrap=True)
   
    while True:
        Key()
    
    
if __name__ == "__main__":
    main()

演示效果

 四、示例代码2

演示使用按键控制开关灯(板载led灯)

from machine import Pin,I2C
from key_matrix import KEY
from ssd1306 import SSD1306_I2C

from ufont import BMFont
import time

i2c  = I2C(0,scl = Pin(5),sda = Pin(4),freq = 400_000)
oled = SSD1306_I2C(128,64,i2c,0x3c)

font = BMFont("fonts/unifont-14-12888-16.v3.bmf")

#行
R1 = Pin(2,Pin.OUT)
R2 = Pin(3,Pin.OUT)
R3 = Pin(10,Pin.OUT)
R4 = Pin(6,Pin.OUT)

#列
C1 = Pin(7 ,Pin.IN,Pin.PULL_UP)
C2 = Pin(8 ,Pin.IN,Pin.PULL_UP)
C3 = Pin(18,Pin.IN,Pin.PULL_UP)
C4 = Pin(19,Pin.IN,Pin.PULL_UP)

#创建按键对象
Key = KEY(C1,C2,C3,C4,R1,R2,R3,R4)

led = Pin(12,Pin.OUT)

def Matrix():
    code = [
            ['0','1','2','3'],
            ['4','5','6','7'],
            ['8','9','a','b'],
            ['c','d','e','f'],
           ]
    
    #接收按键值
    value = Key.matrix()

    if value == code[3][3]:
        led.value(not led.value())
        if led.value():
            font.text(oled,"开灯",40,24,color=1,font_size=16,reverse=False,clear=True,show=True,half_char=True, auto_wrap=True)
        else :
            font.text(oled,"关灯",40,24,color=1,font_size=16,reverse=False,clear=True,show=True,half_char=True, auto_wrap=True)
        
        print("%s"%value)

def main():
    font.text(oled,str("矩阵按值"),32,24,color=1,font_size=16,reverse=False,clear=False,show=True,half_char=True, auto_wrap=True)
   
    while True:
        Matrix()
            
            
if __name__ == "__main__":
    main()

演示效果

五、key_matrix库

key_matrix.py

'''
#行只负责拉高和拉低电瓶,让交叉的列进行扫描 R简称行

R1 = Pin(2,Pin.OUT)
R2 = Pin(3,Pin.OUT)
R3 = Pin(10,Pin.OUT)
R4 = Pin(6,Pin.OUT)

#列负责进行交叉的键值检测,当按键被按下时读取对应值 C简称列

C1 = Pin(7 ,Pin.IN,Pin.PULL_UP)
C2 = Pin(8 ,Pin.IN,Pin.PULL_UP)
C3 = Pin(18,Pin.IN,Pin.PULL_UP)
C4 = Pin(19,Pin.IN,Pin.PULL_UP)

#创建按键对象
Key = KEY(C1,C2,C3,C4,R1,R2,R3,R4)

#接收按键值
temp = Key.matrix()

'''
from machine import Pin
import time

class KEY(object):
    
    def __init__(self,C1,C2,C3,C4,R1,R2,R3,R4):
        
        self.C1 = C1 
        self.C2 = C2
        self.C3 = C3
        self.C4 = C4
        
        self.R1 = R1 
        self.R2 = R2 
        self.R3 = R3 
        self.R4 = R4 
    
    #按键扫描函数
    def matrix(self):
        
        key = 0
        bzw = 0
        
        #设置第一行拉低
        [self.R1.value(0),self.R2.value(1),self.R3.value(1),self.R4.value(1)]
        #扫描每一列键值
        if(self.C1.value() == 0 or self.C2.value() == 0 or self.C3.value() == 0 or self.C4.value() == 0):
            
            time.sleep(0.020)
            
            if self.C1.value() == 0:                
                bzw = 1
                key = '0'
                while not self.C1.value():
                    pass
                    
            elif self.C2.value() == 0:
                bzw = 1
                key = '1'
                while not self.C2.value():
                    pass
                
            elif self.C3.value() == 0:
                bzw = 1
                key = '2'
                while not self.C3.value():
                    pass
                
            elif self.C4.value() == 0:
                bzw = 1
                key = '3'
                while not self.C4.value():
                    pass
            else:
                
                self.R1.value(1)
        
        #设置第二行拉低
        [self.R1.value(1),self.R2.value(0),self.R3.value(1),self.R4.value(1)]
        #扫描每一列键值
        if(self.C1.value() == 0 or self.C2.value() == 0 or self.C3.value() == 0 or self.C4.value() == 0):
            
            time.sleep(0.020)
            
            if self.C1.value() == 0:                
                bzw = 1
                key = '4'
                while not self.C1.value():
                    pass
                    
            elif self.C2.value() == 0:
                bzw = 1
                key = '5'
                while not self.C2.value():
                    pass
                
            elif self.C3.value() == 0:
                bzw = 1
                key = '6'
                while not self.C3.value():
                    pass
                
            elif self.C4.value() == 0:
                bzw = 1
                key = '7'
                while not self.C4.value():
                    pass
            else:
                
                key = 0
                bzw = 0
                self.R2.value(1)
                 
        #设置第三行拉低
        [self.R1.value(1),self.R2.value(1),self.R3.value(0),self.R4.value(1)]
        #扫描每一列键值
        if(self.C1.value() == 0 or self.C2.value() == 0 or self.C3.value() == 0 or self.C4.value() == 0):
            
            time.sleep(0.020)
            
            if self.C1.value() == 0:                
                bzw = 1
                key = '8'
                while not self.C1.value():
                    pass
                    
            elif self.C2.value() == 0:
                bzw = 1
                key = '9'
                while not self.C2.value():
                    pass
                
            elif self.C3.value() == 0:
                bzw = 1
                key = 'a'
                while not self.C3.value():
                    pass
                
            elif self.C4.value() == 0:
                bzw = 1
                key = 'b'
                while not self.C4.value():
                    pass
            else:
                
                key = 0
                bzw = 0
                self.R3.value(1)
                 
        #设置第四行拉低
        [self.R1.value(1),self.R2.value(1),self.R3.value(1),self.R4.value(0)]
        #扫描每一列键值
        if(self.C1.value() == 0 or self.C2.value() == 0 or self.C3.value() == 0 or self.C4.value() == 0):
            
            time.sleep(0.020)
            
            if self.C1.value() == 0:                
                bzw = 1
                key = 'c'
                while not self.C1.value():
                    pass
                    
            elif self.C2.value() == 0:
                bzw = 1
                key = 'd'
                while not self.C2.value():
                    pass
                
            elif self.C3.value() == 0:
                bzw = 1
                key = 'e'
                while not self.C3.value():
                    pass
                
            elif self.C4.value() == 0:
                bzw = 1
                key = 'f'
                while not self.C4.value():
                    pass
            else:
                
                key = 0
                bzw = 0
                self.R4.value(1)
                 
        if bzw == 1:
            bzw = 0
            
            return key
            #返回的的是字符串类型

六、字库和ssd1306驱动

        字库fonts/unifont-14-12888-16.v3.bmf和ssd1306驱动见这个文章

物联网开发107 - Micropython ESP32 C3接DS1307时钟模块在SSD1306屏幕上显示时间_魔都飘雪的博客-CSDN博客Micropython ESP32 C3连接DS1307时钟模块在SSD1306屏幕上显示时间https://blog.csdn.net/zhusongziye/article/details/130535482?spm=1001.2014.3001.5501ufont.py

__version__ = 3

import time
import struct

import framebuf

DEBUG = False


def timeit(f, *args, **kwargs):
    try:
        myname = str(f).split(' ')[1]
    except:
        myname = "UNKONW"

    def new_func(*args, **kwargs):
        if DEBUG:
            try:
                t = time.ticks_us()
                result = f(*args, **kwargs)
                delta = time.ticks_diff(time.ticks_us(), t)
                print('Function {} Time = {:6.3f}ms'.format(myname, delta / 1000))
            except AttributeError:
                t = time.perf_counter_ns()
                result = f(*args, **kwargs)
                delta = time.perf_counter_ns() - t
                print('Function {} Time = {:6.3f}ms'.format(myname, delta / 1000000))
            return result
        else:
            return f(*args, **kwargs)

    return new_func


class BMFont:
    @staticmethod
    def _list_to_byte(arr):
        b = 0
        for a in arr:
            b = (b << 1) + a
        return bytes([b])

    @timeit
    def _bit_list_to_byte_data(self, bit_list):
        """将点阵转换为字节数据

        Args:
            bit_list:

        Returns:

        """
        byte_data = b''
        for _col in bit_list:
            for i in range(0, len(_col), 8):
                byte_data += self._list_to_byte(_col[i:i + 8])
        return byte_data

    @timeit
    def __init__(self, font_file):
        self.font_file = font_file

        self.font = open(font_file, "rb", buffering=0xff)

        self.bmf_info = self.font.read(16)

        if self.bmf_info[0:2] != b"BM":
            raise TypeError("字体文件格式不正确: " + font_file)

        self.version = self.bmf_info[2]
        if self.version != 3:
            raise TypeError("字体文件版本不正确: " + str(self.version))

        self.map_mode = self.bmf_info[3]  # 映射方式
        self.start_bitmap = struct.unpack(">I", b'\x00' + self.bmf_info[4:7])[0]  # 位图开始字节
        self.font_size = self.bmf_info[7]  # 字体大小
        self.bitmap_size = self.bmf_info[8]  # 点阵所占字节

    @timeit
    def _to_bit_list(self, byte_data, font_size, *, _height=None, _width=None):
        """将字节数据转换为点阵数据

        Args:
            byte_data: 字节数据
            font_size: 字号大小
            _height: 字体原高度
            _width: 字体原宽度

        Returns:

        """
        _height = _height or self.font_size
        _width = _width or self.bitmap_size // self.font_size * 8
        new_bitarray = [[0 for j in range(font_size)] for i in range(font_size)]
        for _col in range(len(new_bitarray)):
            for _row in range(len(new_bitarray[_col])):
                _index = int(_col / (font_size / _height)) * _width + int(_row / (font_size / _width))
                new_bitarray[_col][_row] = byte_data[_index // 8] >> (7 - _index % 8) & 1
        return new_bitarray

    @timeit
    def _color_render(self, bit_list, color):
        """将二值点阵图像转换为 RGB565 彩色字节图像

        Args:
            bit_list:
            color:

        Returns:

        """
        color_array = b""
        for _col in range(len(bit_list)):
            for _row in range(len(bit_list)):
                color_array += struct.pack("<H", color) if bit_list[_col][_row] else b'\x00\x00'
        return color_array

    @timeit
    def _get_index(self, word):
        """获取索引

        Args:
            word: 字符

        Returns:

        """
        word_code = ord(word)
        start = 0x10
        end = self.start_bitmap

        while start <= end:
            mid = ((start + end) // 4) * 2
            self.font.seek(mid, 0)
            target_code = struct.unpack(">H", self.font.read(2))[0]
            if word_code == target_code:
                return (mid - 16) >> 1
            elif word_code < target_code:
                end = mid - 2
            else:
                start = mid + 2
        return -1

    @timeit
    def get_bitmap(self, word):
        """获取点阵图

        Args:
            word: 字符

        Returns:
            bytes 字符点阵
        """
        index = self._get_index(word)
        if index == -1:
            return b'\xff\xff\xff\xff\xff\xff\xff\xff\xf0\x0f\xcf\xf3\xcf\xf3\xff\xf3\xff\xcf\xff?\xff?\xff\xff\xff' \
                   b'?\xff?\xff\xff\xff\xff'

        self.font.seek(self.start_bitmap + index * self.bitmap_size, 0)
        return self.font.read(self.bitmap_size)

    @timeit
    def text(self, display, string, x, y, color=1, *, font_size=None, reverse=False, clear=False, show=False,
             half_char=True, auto_wrap=False, **kwargs):
        """通过显示屏显示文字

        使用此函数显示文字,必须先确认显示对象是否继承与 framebuf.FrameBuffer。
        如果显示对象没有 clear 方法,需要自行调用 fill 清屏

        Args:
            display: 显示实例
            string: 字符串
            x: 字体左上角 x 轴
            y: 字体左上角 y 轴
            color: 颜色
            font_size: 字号
            reverse: 是否反转背景
            clear: 是否清除之前显示的内容
            show: 是否立刻显示
            half_char: 是否半字节显示 ASCII 字符
            auto_wrap: 自动换行
            **kwargs:

        Returns:
            None
        """
        font_size = font_size or self.font_size
        initial_x = x

        # 清屏
        try:
            display.clear() if clear else 0
        except AttributeError:
            print("请自行调用 display.fill(*) 清屏")

        for char in range(len(string)):
            # 是否自动换行
            if auto_wrap:
                if auto_wrap and ((x + font_size // 2 >= display.width and ord(string[char]) < 128 and half_char) or
                                  (x + font_size >= display.width and (not half_char or ord(string[char]) > 128))):
                    y += font_size
                    x = initial_x

            # 回车
            if string[char] == '\n':
                y += font_size
                x = initial_x
                continue
            # Tab
            elif string[char] == '\t':
                x = ((x // font_size) + 1) * font_size + initial_x % font_size
                continue
            # 其它的控制字符不显示
            elif ord(string[char]) < 16:
                continue

            # 超过范围的字符不会显示*
            if x > display.width or y > display.height:
                continue

            byte_data = list(self.get_bitmap(string[char]))

            # 反转
            if reverse:
                for _pixel in range(len(byte_data)):
                    byte_data[_pixel] = ~byte_data[_pixel] & 0xff

            # 缩放和色彩*
            if color > 1 or font_size != self.font_size:
                bit_data = self._to_bit_list(byte_data, font_size)
                if color > 1:
                    display.blit(
                        framebuf.FrameBuffer(bytearray(self._color_render(bit_data, color)), font_size, font_size,
                                             framebuf.RGB565), x, y)
                else:
                    display.blit(
                        framebuf.FrameBuffer(bytearray(self._bit_list_to_byte_data(bit_data)), font_size, font_size,
                                             framebuf.MONO_HLSB), x, y)
            else:
                display.blit(framebuf.FrameBuffer(bytearray(byte_data), font_size, font_size, framebuf.MONO_HLSB), x, y)

            # 英文字符半格显示
            if ord(string[char]) < 128 and half_char:
                x += font_size // 2
            else:
                x += font_size

        display.show() if show else 0

    def char(self, char, color=1, font_size=None, reverse=False):
        """ 获取字体字节数据

        在没有继承 framebuf.FrameBuffer 的显示驱动,或者内存不足以将一整个屏幕载入缓存帧时
        可以直接获取单字的字节数据,局部更新
        Args:
            char: 单个字符
            color: 颜色
            font_size: 字体大小
            reverse: 反转

        Returns:
            bytearray
        """
        font_size = font_size or self.font_size
        byte_data = list(self.get_bitmap(char))

        # 反转
        if reverse:
            for _pixel in range(len(byte_data)):
                byte_data[_pixel] = ~byte_data[_pixel] & 0xff
        if color > 1 or font_size != self.font_size:
            bit_data = self._to_bit_list(byte_data, font_size)
            if color > 1:
                return self._color_render(bit_data, color)
            else:
                return self._bit_list_to_byte_data(bit_data)
        else:
            return bytearray(byte_data)


if __name__ == '__main__':
    def show_bitmap(arr):
        """
        显示点阵字 MONO_HLSB
        :return:
        """
        for row in arr:
            for i in row:
                if i:
                    print('* ', end=' ')
                else:
                    print('. ', end=' ')
            print()


    font = BMFont("unifont-14-12888-16.v3.bmf")
    print("16 ----")
    bd = font.char("我", reverse=True, color=0xffff, font_size=16)
    print("24 ----")
    bd = font.char("我", reverse=True, color=0xffff, font_size=24)
    print("16 ----")
    # font._with_color(zoom(byte_to_bit(font.get_bitmap("我"), 16), 24), 0xff00)
    font._color_render(font._to_bit_list(font.get_bitmap("我"), 24), 0xff00)

七、4x4矩阵按键购买

        4x4 按键模块 矩阵模块 键盘模块 单片机 外围模块

https://detail.tmall.com/item.htm?_u=ip01rchfc25&id=538152113118&spm=a1z09.2.0.0.7f5e2e8dCdkoWOicon-default.png?t=N4HBhttps://detail.tmall.com/item.htm?_u=ip01rchfc25&id=538152113118&spm=a1z09.2.0.0.7f5e2e8dCdkoWO我收到的实物图和卖家详情页的不一样,但是可以使用。

 

 

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

魔都飘雪

您的1毛奖励是我创作的源源动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值