【K210】K210学习笔记三——按键、LCD、LED的使用

【K210】K210学习笔记三——按键、LCD、LED的使用

  • 前言
  • 按键配置
  • LCD配置
  • LED配置
  • 测试环节
    • 测试按键能否正常工作
    • LCD能否显示图像、测试LED能否正常工作
  • 完整源码

前言

本人大四学生,电赛生涯已经走到尽头,一路上踩过不少坑,但运气也不错拿了两年省一,思来想去,决定开始写博客,将电赛经验分享一二,能力有限,高手轻喷。
往期的博客讲述了 K210 的感光元件模块 sensor 的配置,机器视觉模块 image 中部分函数的使用(目前是用 find_blobs 函数实现一些寻找不同颜色的目标点,寻找不同颜色的线,后面会更新更多 image 模块中的函数使用方法)
sensor 的学习笔记传送门
【K210】K210学习笔记一——sensor
image 的学习笔记传送门
【K210】K210学习笔记二——image
本文着重于 K210 的按键、LED、LCD的配置及使用方法。我在今年的TI杯省赛 送货无人机 题目中,就是用 K210 完成送货坐标点的输入,这就需要按键和LCD,因为按键都会有抖动,常规的消抖是使用延时,但延时多少时间是一个大问题,长了短了都不好,因此用LCD显示一下坐标值,确保输入的坐标值是对的。而LED可以作为一个在离开IDE下,判断摄像头能否正常识别的一个标志工具,比赛是多人协作的,我做识别,队友做无人机控制,那么出了问题,究竟是我识别不对,还是我队友控制没做好?因此我用LED来判断我的识别究竟有没有问题。

按键配置

定义按键需要引入一些模块,如下所示。utime 用于延时消抖,fm 和 GPIO 用于引脚注册(LED也会用到)。

import utime                                                # 导入延时模块 utime
from fpioa_manager import fm                                # 从 GPIO 模块中导入 引脚注册模块 fm
from Maix import GPIO                                       # 从 Maix 模块中导入 模块 GPIO

先定义一个按键控制类,保存按键操作过程中的一些信息。

#__________________________________________________________________
# 按键
# 定义按键控制类
class key_control():                                        # 定义按键控制类
    cnt     = 0                                             # 按键计数值
    cs      = 0                                             # 按键模式选择标志位
    csmax   = 0                                             # 按键模式上限
    csflag  = 0                                             # 按键模式切换标志位
    cinput  = 0                                             # 按键输入值保存位
    control = 0                                             # 按键确认及发送控制标志位
    

实例化按键类,设置按键模式上限为 4。

# 实例化按键类
key = key_control()                                         # 实例化按键控制类 key_control() 为 key
key.csmax = 4                                               # 按键模式上限为 4 即最多有 4 个模式

注册按键引脚,这个引脚是可以自行定义的,但需要注意不要和其他引脚冲突了。 我这里定义 16、18、19、20 的原因是因为这四个引脚在我这一块开发板上是相邻的,注册为 高速GPIO 的原因是我打算将按键输入作为外部中断输入,外部中断必须设置为高速GPIO口

# 注册按键引脚
fm.register(16, fm.fpioa.GPIOHS0, force = True)             # 配置 16 脚为 KEY0 使用高速 GPIO 口 强制注册
fm.register(18, fm.fpioa.GPIOHS1, force = True)             # 配置 18 脚为 KEY1 使用高速 GPIO 口 强制注册
fm.register(19, fm.fpioa.GPIOHS2, force = True)             # 配置 19 脚为 KEY2 使用高速 GPIO 口 强制注册
fm.register(20, fm.fpioa.GPIOHS3, force = True)             # 配置 20 脚为 KEY3 使用高速 GPIO 口 强制注册

然后就是用注册的引脚创建按键对象。

# 创建按键对象
KEY0 = GPIO(GPIO.GPIOHS0, GPIO.IN, GPIO.PULL_UP)            # 创建按键对象 KEY0
KEY1 = GPIO(GPIO.GPIOHS1, GPIO.IN, GPIO.PULL_UP)            # 创建按键对象 KEY1
KEY2 = GPIO(GPIO.GPIOHS2, GPIO.IN, GPIO.PULL_UP)            # 创建按键对象 KEY2
KEY3 = GPIO(GPIO.GPIOHS3, GPIO.IN, GPIO.PULL_UP)            # 创建按键对象 KEY3

然后就是按键中断回调函数的定义,这里的代码是可以自行定义的,依据个人不同的需求。 我的定义就是,用 按键0 来控制不同的模式,按键1 来控制 输入值(增),按键2 来控制输入值(减),按键3 来确认,定义如下。

# 中断回调函数 KEY0 控制按键模式选择
def key0_switch(KEY0):
    utime.sleep_ms(10)                                      # 延时 10ms 消除按键抖动
    if KEY0.value() == 0:                                   # 确认 按键0 按下
        key.csflag = 1                                      # 标记按键模式切换
        if key.cs < key.csmax:                              # 控制按键模式选择 自增
            key.cs = key.cs + 1
        else:                                               # 若达到上限 则重新从 0 开始
            key.cs = 0

# 中断回调函数 KEY1 按键输入值自增
def key1_switch(KEY1):
    utime.sleep_ms(10)                                      # 延时 10ms 消除按键抖动
    if KEY1.value() == 0:                                   # 确认 按键1 按下
        key.cinput = key.cinput + 1                         # 按键输入值自增

# 中断回调函数 KEY2 按键输入值自减
def key2_switch(KEY2):
    utime.sleep_ms(10)                                      # 延时 10ms 消除按键抖动
    if KEY2.value() == 0:                                   # 确认 按键2 按下
        key.cinput = key.cinput - 1                         # 按键输入值自减

# 中断回调函数 KEY3 按键确认及发送控制标志位
def key3_switch(KEY3):
    utime.sleep_ms(10)                                      # 延时 10ms 消除按键抖动
    if KEY3.value() == 0:                                   # 确认按键按下
        key.control = 1                                     # 按键确认及发送控制标志位
        

然后打开中断即可。

# 开启中断 下降沿触发
KEY0.irq(key0_switch, GPIO.IRQ_FALLING)
KEY1.irq(key1_switch, GPIO.IRQ_FALLING)
KEY2.irq(key2_switch, GPIO.IRQ_FALLING)
KEY3.irq(key3_switch, GPIO.IRQ_FALLING)

接下来我用 2022年TI杯省赛送货无人机 中的 键盘输入获取坐标点 这一任务进行举例。首先定义一个目标点输入类,保存目标点的各种信息。

#__________________________________________________________________
# 目标点输入类 举例 对标 2022 年 TI 杯送货无人机 中的目标点输入部分
class point_input():
    point1  = 0                                             # 目标点 1
    point2  = 0                                             # 目标点 2
    cross   = 0                                             # 穿圈模式标志位
    send    = 0                                             # 目标点发送标志位
    

实例化类

point = point_input()                                       # 实例化目标点输入类 point_input() 为 point

通过按键操作,获取目标点值,逻辑如下。
在按键确认及发送标志位被置为1时,重置该标志位,此时如果为模式0,则将目标点发送标志位置为1,可作为串口发送判断的标志位,为1情况串口才开始发送。此时如果为模式1,则将按键输入值赋值给目标点1。此时如果为模式2,则将按键输入值赋值给目标点2。此时如果为模式3,则将按键输入值赋值给穿圈模式标志位。
同时,每一次按键模式切换,都将会重置按键输入值。
举例说明,比如要设置目标点1 为8,目标点2 为7(送货无人机题目的十二个目标地点名称是 1-12),那么需要这样操作。
按下按键0,让模式变为1,然后按下8次按键1,使输入值增加到8,然后按下按键3,确认。
再次按下按键0,让模式变为2,然后按下7次按键1,使输入值增加到7,然后按下按键3,确认。
再次按下几次按键0,直到模式变为0,然后按下按键3,即可发送。
按键2 减的作用是消除按键抖动的影响,因为按键抖动,按下8次,按键输入值不一定是8,可能是9,10等,此时就可以用按键2 来减,直到输入值为8,再按下按键3 确认。

# 按键控制下的目标点获取函数
def point_control(ckey):
    if ckey.control == 1:                                   # 按键确认及发送控制标志位为1 即 按键3 按下
        ckey.control = 0                                    # 重置标志位
        if ckey.cs == 0:                                    # 如果当前为模式 0
            point.send = 1                                  # 目标点发送标志置为 1 串口开始发送

        elif ckey.cs == 1:                                  # 如果当前为模式 1
            point.point1 = ckey.cinput                      # 将按键输入值赋值给目标点 1

        elif ckey.cs == 2:                                  # 如果当前为模式 2
            point.point2 = ckey.cinput                      # 将按键输入值赋值给目标点 2

        elif ckey.cs == 3:                                  # 如果当前为模式 3
            point.cross = ckey.cinput                       # 将按键输入值赋值给 穿圈模式标志位

    if ckey.csflag == 1:                                    # 如果检测到按键模式切换
        ckey.csflag = 0                                     # 重置按键模式切换标志位
        ckey.cinput = 0                                     # 重置按键输入值
        

LCD配置

需要导入LCD模块。

import lcd                                                  # 导入 LCD 模块

然后初始化LCD,定义按键信息及目标点信息显示函数,有了显示就可以确保按键输入不会出错。

#__________________________________________________________________
# LCD 初始化
lcd.init()                                                  # lcd初始化

# LCD 按键信息及目标点信息显示函数
def lcd_key():
    lcd.draw_string(0, 0,  "key_cs: "+str(key.cs), lcd.RED, lcd.WHITE)
    lcd.draw_string(0, 15, "cinput: "+str(key.cinput), lcd.RED, lcd.WHITE)
    lcd.draw_string(0, 30, "point1: "+str(point.point1), lcd.RED, lcd.WHITE)
    lcd.draw_string(0, 45, "point2: "+str(point.point2), lcd.RED, lcd.WHITE)
    lcd.draw_string(0, 60, "cross : "+str(point.cross), lcd.RED, lcd.WHITE)
    

LED配置

我这一块开发板的LED引脚是固定的,因此注册LED引脚和创建LED对象必须按照这样设置。

#__________________________________________________________________
# LED的使用
# 注册LED引脚
fm.register(14, fm.fpioa.GPIO2, force = True)               # 配置 14 脚为 LED_R 强制注册
fm.register(13, fm.fpioa.GPIO1, force = True)               # 配置 13 脚为 LED_G 强制注册
fm.register(12, fm.fpioa.GPIO0, force = True)               # 配置 12 脚为 LED_B 强制注册

# 创建LED对象
LED_R = GPIO(GPIO.GPIO2, GPIO.OUT)                          # 创建 LED_R 对象
LED_G = GPIO(GPIO.GPIO1, GPIO.OUT)                          # 创建 LED_G 对象
LED_B = GPIO(GPIO.GPIO0, GPIO.OUT)                          # 创建 LED_B 对象

然后就是定义LED控制函数,传入参数为 0 ,则打开所有灯(效果是呈现白色),传入参数为 1 ,则关闭所有灯,传入参数为 2 ,则红灯常亮,传入参数为 3 ,则绿灯常亮,传入参数为 4 ,则蓝灯常亮,不符合上述条件,亮紫灯。

# LED控制函数
def led_control(led_flag):                                  # LED控制函数 根据传入 led_flag 点亮对应的灯
    if led_flag == 0:                                       # 传入参数为 0 所有灯打开
        LED_R.value(0)
        LED_G.value(0)
        LED_B.value(0)

    elif led_flag == 1:                                     # 传入参数为 1 所有灯关闭
        LED_R.value(1)
        LED_G.value(1)
        LED_B.value(1)

    elif led_flag == 2:                                     # 传入参数为 2 红灯常亮
        LED_R.value(0)
        LED_G.value(1)
        LED_B.value(1)

    elif led_flag == 3:                                     # 传入参数为 3 绿灯常亮
        LED_R.value(1)
        LED_G.value(0)
        LED_B.value(1)

    elif led_flag == 4:                                     # 传入参数为 4 蓝灯常亮
        LED_R.value(1)
        LED_G.value(1)
        LED_B.value(0)

    else:                                                   # 其他情况 紫灯
        LED_R.value(0)
        LED_G.value(1)
        LED_B.value(0)
        

测试环节

主函数如下所示,这里做的主要事情是,摄像头会拍摄一张图片,然后会开始找红色色块,按键控制目标点获取,LCD显示图像及按键和目标点的信息,LED对红色色块寻找情况进行标记(如果亮红灯说明找到,白灯说明找不到),然后每间隔一定时间会打印调试信息。

#__________________________________________________________________
# 主函数
while(True):

    clock.tick()                                            # 跟踪运行时间

    img = sensor.snapshot()                                 # 拍摄一张照片
    #opv_find_blobs(black,1)                                # 找黑色色块 led标志为1 表示黑色
    opv_find_blobs(red,2)                                   # 找红色色块 led标志为2 表示红色

    point_control(key)                                      # 按键控制下的目标点获取函数

    lcd.display(img)                                        # LCD 显示图像
    lcd_key()                                               # LCD 显示按键信息及目标点信息

    led_control(red.led_flag)                               # LED 标记色块识别情况

    if mycnt == 0:                                          # 如果 mycnt 等于 0 此步骤的目的是控制打印周期 不要打印的太快
        mycnt = 1                                           # 将 1 赋值给 mycnt 使下一次不再满足 mycnt == 0 进入 elif
        print_sensor()                                      # 打印sensor参数
        print_blobs_property(black,"Black-")                # 打印黑色色块参数
        print_blobs_property(red,  "Red-  ")                # 打印红色色块参数

    elif mycnt < mycnt_max:                                 # 计数变量 小于 计数上限 则 计数变量 自增
        mycnt = mycnt + 1

    else:                                                   # 计数变量 超出 计数上限 则 将0赋值给 mycnt 使下一次进入 if
        mycnt = 0

#__________________________________________________________________

测试按键能否正常工作

先说一下按键怎么连接,我这里是因为手头上没有按键,所以才用32开发板上的按键进行连接,手头上有按键的完全没必要这样连接。 按键连接的方法就是,按键的一端接 16、18、19、20,另一端接地即可(接K210的地,所以我将32开发板和K210共地了,这样才能正常工作,而绿线本来是接PA0的,但32开发板的PA0另一端是VCC,所以接PA0的话按下按键是没有反应的,我就将它接到32的地了,通过插拔的方式模拟按下按键这一操作)。

这里随便按几个值测试一下按键能否正常工作,我这里按了一下32开发板的按键2(K210开发板16脚所接按键),让key.cs为1,然后按了1下32开发板的按键1(K210开发板19脚所接按键),让按键输入值cinput减为-1,然后按下32开发板的按键0(K210开发板20脚所接按键),于是point1就被赋值为-1了。而插拔的方式控制按键增,不够稳定,我插拔一次就加到十几,所以手头有按键的一定要用按键哦!
【K210】K210学习笔记三——按键、LCD、LED的使用_第1张图片
然后我又按了一下32开发板的按键2(K210开发板16脚所接按键),让key.cs为2,即切换到模式2,可以看到cinput被重置为0了,这样方便设置目标点2,以此类推就可以设置各个目标点的属性了。
【K210】K210学习笔记三——按键、LCD、LED的使用_第2张图片

LCD能否显示图像、测试LED能否正常工作

然后是LCD显示屏的测试,可以看到能正确显示图像,并且还能标记色块中心坐标,这样一来就很方便离开IDE调试了。
【K210】K210学习笔记三——按键、LCD、LED的使用_第3张图片
然后能识别到目标点的话,红色灯是会亮的。
【K210】K210学习笔记三——按键、LCD、LED的使用_第4张图片
如果识别不到目标点,红色灯就会熄灭,变成白色灯。如果画面中有目标,但灯在红白之间交替闪烁,那就说明阈值有问题哦!或者就是色块像素个数阈值那些设置的太大了,调小就能解决问题了。这样一来就很方便我们快速找到问题所在了!
【K210】K210学习笔记三——按键、LCD、LED的使用_第5张图片

完整源码

完整源码如下所示,大家可以复制该源码,进行测试,下一次学习笔记将会记录K210定时器的使用,我们下期再见~!

# KEY_V1.0 - By: FITQY - 周一 8 月 22 日 2022
#__________________________________________________________________
# 导入模块
import sensor, time, image                                  # 导入感光元件模块 sensor 跟踪运行时间模块 time 机器视觉模块 image
import utime                                                # 导入延时模块 utime
from fpioa_manager import fm                                # 从 GPIO 模块中导入 引脚注册模块 fm
from Maix import GPIO                                       # 从 Maix 模块中导入 模块 GPIO
import lcd                                                  # 导入 LCD 模块

#__________________________________________________________________
# 感光元件设置
sensor.reset()                                              # 重置并初始化感光元件 默认设置为 摄像头频率 24M 不开启双缓冲模式
#sensor.reset(freq=24000000, dual_buff=True)                # 设置摄像头频率 24M 开启双缓冲模式 会提高帧率 但内存占用增加

sensor.set_pixformat(sensor.RGB565)                         # 设置图像格式为 RGB565 (彩色) 除此之外 还可设置格式为 GRAYSCALE 或者 YUV422
sensor.set_framesize(sensor.QVGA)                           # 设置图像大小为 QVGA (320 x 240) 像素个数 76800 K210最大支持格式为 VGA

sensor.set_auto_exposure(1)                                 # 设置自动曝光
#sensor.set_auto_exposure(0, exposure=120000)               # 设置手动曝光 曝光时间 120000 us

sensor.set_auto_gain(0, gain_db = 12)                       # 设置画面增益 17 dB 影响实时画面亮度
sensor.set_auto_whitebal(0, rgb_gain_db = (0,0,0))          # 设置RGB增益 0 0 0 dB 影响画面色彩呈现效果 在 K210 上无法调节增益 初步判定是感光元件 ov2640 无法支持

#sensor.set_contrast(0)                                     # 设置对比度 0 这个参数无法读取 且调这个参数对画面似乎不会产生影响 暂时注释
#sensor.set_brightness(0)                                   # 设置亮度 0 这个参数无法读取 且调这个参数对画面似乎不会产生影响 暂时注释
#sensor.set_saturation(0)                                   # 设置饱和度 0 这个参数无法读取 且调这个参数对画面似乎不会产生影响 暂时注释

sensor.set_vflip(1)                                         # 打开垂直翻转 如果是 01Studio 的 K210 不开启会导致画面方向与运动方向相反
sensor.set_hmirror(1)                                       # 打开水平镜像 如果是 01Studio 的 K210 不开启会导致画面方向与运动方向相反

sensor.skip_frames(time = 2000)                             # 延时跳过2s 等待感光元件稳定

#__________________________________________________________________
# 创建时钟对象
clock = time.clock()                                        # 创建时钟对象 clock

#__________________________________________________________________
# 打印sensor参数
def print_sensor():
    print("Exposure: "+str(sensor.get_exposure_us()))       # 打印 曝光时间
    print("Gain: "+str(sensor.get_gain_db()))               # 打印 画面增益
    print("RGB: "+str(sensor.get_rgb_gain_db()))            # 打印 RGB 增益

#__________________________________________________________________
# 目标点输入类 举例 对标 2022 年 TI 杯送货无人机 中的目标点输入部分
class point_input():
    point1  = 0                                             # 目标点 1
    point2  = 0                                             # 目标点 2
    cross   = 0                                             # 穿圈模式标志位
    send    = 0                                             # 目标点发送标志位

point = point_input()                                       # 实例化目标点输入类 point_input() 为 point

# 按键控制下的目标点获取函数
def point_control(ckey):
    if ckey.control == 1:                                   # 按键确认及发送控制标志位为1 即 按键3 按下
        ckey.control = 0                                    # 重置标志位
        if ckey.cs == 0:                                    # 如果当前为模式 0
            point.send = 1                                  # 目标点发送标志置为 1 串口开始发送

        elif ckey.cs == 1:                                  # 如果当前为模式 1
            point.point1 = ckey.cinput                      # 将按键输入值赋值给目标点 1

        elif ckey.cs == 2:                                  # 如果当前为模式 2
            point.point2 = ckey.cinput                      # 将按键输入值赋值给目标点 2

        elif ckey.cs == 3:                                  # 如果当前为模式 3
            point.cross = ckey.cinput                       # 将按键输入值赋值给 穿圈模式标志位

    if ckey.csflag == 1:                                    # 如果检测到按键模式切换
        ckey.csflag = 0                                     # 重置按键模式切换标志位
        ckey.cinput = 0                                     # 重置按键输入值

#__________________________________________________________________
# 按键
# 定义按键控制类
class key_control():                                        # 定义按键控制类
    cnt     = 0                                             # 按键计数值
    cs      = 0                                             # 按键模式选择标志位
    csmax   = 0                                             # 按键模式上限
    csflag  = 0                                             # 按键模式切换标志位
    cinput  = 0                                             # 按键输入值保存位
    control = 0                                             # 按键确认及发送控制标志位

# 实例化按键类
key = key_control()                                         # 实例化按键控制类 key_control() 为 key
key.csmax = 4                                               # 按键模式上限为 4 即最多有 4 个模式

# 注册按键引脚
fm.register(16, fm.fpioa.GPIOHS0, force = True)             # 配置 16 脚为 KEY0 使用高速 GPIO 口 强制注册
fm.register(18, fm.fpioa.GPIOHS1, force = True)             # 配置 18 脚为 KEY1 使用高速 GPIO 口 强制注册
fm.register(19, fm.fpioa.GPIOHS2, force = True)             # 配置 19 脚为 KEY2 使用高速 GPIO 口 强制注册
fm.register(20, fm.fpioa.GPIOHS3, force = True)             # 配置 20 脚为 KEY3 使用高速 GPIO 口 强制注册

# 创建按键对象
KEY0 = GPIO(GPIO.GPIOHS0, GPIO.IN, GPIO.PULL_UP)            # 创建按键对象 KEY0
KEY1 = GPIO(GPIO.GPIOHS1, GPIO.IN, GPIO.PULL_UP)            # 创建按键对象 KEY1
KEY2 = GPIO(GPIO.GPIOHS2, GPIO.IN, GPIO.PULL_UP)            # 创建按键对象 KEY2
KEY3 = GPIO(GPIO.GPIOHS3, GPIO.IN, GPIO.PULL_UP)            # 创建按键对象 KEY3

# 中断回调函数 KEY0 控制按键模式选择
def key0_switch(KEY0):
    utime.sleep_ms(10)                                      # 延时 10ms 消除按键抖动
    if KEY0.value() == 0:                                   # 确认 按键0 按下
        key.csflag = 1                                      # 标记按键模式切换
        if key.cs < key.csmax:                              # 控制按键模式选择 自增
            key.cs = key.cs + 1
        else:                                               # 若达到上限 则重新从 0 开始
            key.cs = 0

# 中断回调函数 KEY1 按键输入值自增
def key1_switch(KEY1):
    utime.sleep_ms(10)                                      # 延时 10ms 消除按键抖动
    if KEY1.value() == 0:                                   # 确认 按键1 按下
        key.cinput = key.cinput + 1                         # 按键输入值自增

# 中断回调函数 KEY2 按键输入值自减
def key2_switch(KEY2):
    utime.sleep_ms(10)                                      # 延时 10ms 消除按键抖动
    if KEY2.value() == 0:                                   # 确认 按键2 按下
        key.cinput = key.cinput - 1                         # 按键输入值自减

# 中断回调函数 KEY3 按键确认及发送控制标志位
def key3_switch(KEY3):
    utime.sleep_ms(10)                                      # 延时 10ms 消除按键抖动
    if KEY3.value() == 0:                                   # 确认按键按下
        key.control = 1                                     # 按键确认及发送控制标志位

# 开启中断 下降沿触发
KEY0.irq(key0_switch, GPIO.IRQ_FALLING)
KEY1.irq(key1_switch, GPIO.IRQ_FALLING)
KEY2.irq(key2_switch, GPIO.IRQ_FALLING)
KEY3.irq(key3_switch, GPIO.IRQ_FALLING)

#__________________________________________________________________
# LCD 初始化
lcd.init()                                                  # lcd初始化

# LCD 按键信息及目标点信息显示函数
def lcd_key():
    lcd.draw_string(0, 0,  "key_cs: "+str(key.cs), lcd.RED, lcd.WHITE)
    lcd.draw_string(0, 15, "cinput: "+str(key.cinput), lcd.RED, lcd.WHITE)
    lcd.draw_string(0, 30, "point1: "+str(point.point1), lcd.RED, lcd.WHITE)
    lcd.draw_string(0, 45, "point2: "+str(point.point2), lcd.RED, lcd.WHITE)
    lcd.draw_string(0, 60, "cross : "+str(point.cross), lcd.RED, lcd.WHITE)

#__________________________________________________________________
# LED的使用
# 注册LED引脚
fm.register(14, fm.fpioa.GPIO2, force = True)               # 配置 14 脚为 LED_R 强制注册
fm.register(13, fm.fpioa.GPIO1, force = True)               # 配置 13 脚为 LED_G 强制注册
fm.register(12, fm.fpioa.GPIO0, force = True)               # 配置 12 脚为 LED_B 强制注册

# 创建LED对象
LED_R = GPIO(GPIO.GPIO2, GPIO.OUT)                          # 创建 LED_R 对象
LED_G = GPIO(GPIO.GPIO1, GPIO.OUT)                          # 创建 LED_G 对象
LED_B = GPIO(GPIO.GPIO0, GPIO.OUT)                          # 创建 LED_B 对象

# LED控制函数
def led_control(led_flag):                                  # LED控制函数 根据传入 led_flag 点亮对应的灯
    if led_flag == 0:                                       # 传入参数为 0 所有灯打开
        LED_R.value(0)
        LED_G.value(0)
        LED_B.value(0)

    elif led_flag == 1:                                     # 传入参数为 1 所有灯关闭
        LED_R.value(1)
        LED_G.value(1)
        LED_B.value(1)

    elif led_flag == 2:                                     # 传入参数为 2 红灯常亮
        LED_R.value(0)
        LED_G.value(1)
        LED_B.value(1)

    elif led_flag == 3:                                     # 传入参数为 3 绿灯常亮
        LED_R.value(1)
        LED_G.value(0)
        LED_B.value(1)

    elif led_flag == 4:                                     # 传入参数为 4 蓝灯常亮
        LED_R.value(1)
        LED_G.value(1)
        LED_B.value(0)

    else:                                                   # 其他情况 紫灯
        LED_R.value(0)
        LED_G.value(1)
        LED_B.value(0)

#__________________________________________________________________
# 寻找色块
# 定义类
class color_property():
    cx                      =  0                            # 色块 x轴 中心坐标
    cy                      =  0                            # 色块 y轴 中心坐标
    flag                    =  0                            # 色块标志位 1 找到 0 未找到
    color                   =  0                            # 色块颜色标志位 例如 你可以用 1 来表示 黑色
    density                 =  0                            # 色块密度比 反映色块锁定程度 值越大 锁定程度越好
    pixels_max              =  0                            # 色块像素最大值
    led_flag                =  0                            # LED标志位 方便调试用

    color_threshold         = (0, 0, 0, 0, 0, 0)            # 色块颜色阈值
    color_roi               = (0,0,320,240)                 # 色块寻找区域(感兴趣区域)
    color_x_stride          =  1                            # 色块 x轴 像素最小宽度 色块如果比较大可以调大此参数 提高寻找速度
    color_y_stride          =  1                            # 色块 y轴 像素最小宽度 色块如果比较大可以调大此参数 提高寻找速度
    color_pixels_threshold  =  100                          # 色块 像素个数阈值 例如调节此参数为100 则可以滤除色块像素小于100的色块
    color_area_threshold    =  100                          # 色块 被框面积阈值 例如调节此参数为100 则可以滤除色块被框面积小于100的色块
    color_merge             =  True                         # 是否合并寻找到的色块 True 则合并 False 则不合并
    color_margin            =  1                            # 色块合并间距 例如调节此参数为1 若上面选择True合并色块 且被找到的色块有多个 相距1像素 则会将这些色块合并

# 实例化类
# 黑色
black = color_property()
black.color_threshold         = (0, 50, -10, 10, -10, 10)
black.color_roi               = (0,0,320,240)
black.color_x_stride          =  1
black.color_y_stride          =  1
black.color_pixels_threshold  =  100
black.color_area_threshold    =  100
black.color_merge             =  True
black.color_margin            =  1

# 红色
red   = color_property()
red.color_threshold           = (0, 100, 20, 127, -10, 127)

#red.color_roi                = (0,0,320,240)
red.color_roi                 = (0,110,320,20)

red.color_x_stride            =  1
red.color_y_stride            =  1

#red.color_pixels_threshold   =  100
#red.color_area_threshold     =  100
red.color_pixels_threshold    =  10
red.color_area_threshold      =  10

red.color_merge               =  True
red.color_margin              =  1

# 绿色 预留
green = color_property()

# 蓝色 预留
blue  = color_property()

# 定义寻找色块函数
def opv_find_blobs(color,led_flag):
    color.pixels_max = 0                                    # 重置 色块 最大像素数量
    color.flag       = 0                                    # 重置 色块 标志位
    color.led_flag   = 0                                    # 重置 led 标志位

    for blobs in img.find_blobs([color.color_threshold],    # 色块颜色阈值
    roi = color.color_roi,                                  # 色块寻找区域(感兴趣区域)
    x_stride = color.color_x_stride,                        # 色块 x轴 像素最小宽度 色块如果比较大可以调大此参数 提高寻找速度
    y_stride = color.color_y_stride,                        # 色块 y轴 像素最小宽度 色块如果比较大可以调大此参数 提高寻找速度
    pixels_threshold = color.color_pixels_threshold,        # 色块 像素个数阈值 例如调节此参数为100 则可以滤除色块像素小于100的色块
    area_threshold = color.color_area_threshold,            # 色块 被框面积阈值 例如调节此参数为100 则可以滤除色块被框面积小于100的色块
    merge = color.color_merge,                              # 是否合并寻找到的色块 True 则合并 False 则不合并
    margin = color.color_margin):                           # 色块合并间距 例如调节此参数为1 若上面选择True合并色块 且被找到的色块有多个 相距1像素 则会将这些色块合并
        img.draw_rectangle(blobs[0:4])                      # 圈出找到的色块
        if color.pixels_max < blobs.pixels():               # 找到面积最大的色块
            color.pixels_max = blobs.pixels()
            color.cx = blobs.cx()                           # 将面积最大的色块的 x轴 中心坐标值 赋值给 color
            color.cy = blobs.cy()                           # 将面积最大的色块的 y轴 中心坐标值 赋值给 color
            color.flag = 1                                  # 标志画面中有找到色块
            color.density = blobs.density()                 # 将面积最大的色块的 色块密度比 赋值给 color
            color.led_flag = led_flag                       # 将控制led颜色的标志位的值 赋值给 color

    if color.flag == 1:                                     # 标记画面中被找到的最大色块的中心坐标
        img.draw_cross(color.cx,color.cy, color=127, size = 15)
        img.draw_circle(color.cx,color.cy, 15, color = 127)

# 定义打印色块参数函数
def print_blobs_property(color,name):
    print(name,"cx:",color.cx,"cy:",color.cy,"flag:",color.flag,"color:",color.color,"density:",color.density,"led_flag:",color.led_flag)

#__________________________________________________________________
# 调试区
mycnt       = 0                                             # 计数变量
mycnt_max   = 30                                            # 计数上限 此值越大 计数周期越长

#__________________________________________________________________
# 主函数
while(True):

    clock.tick()                                            # 跟踪运行时间

    img = sensor.snapshot()                                 # 拍摄一张照片
    #opv_find_blobs(black,1)                                # 找黑色色块 led标志为1 表示黑色
    opv_find_blobs(red,2)                                   # 找红色色块 led标志为2 表示红色

    point_control(key)                                      # 按键控制下的目标点获取函数

    lcd.display(img)                                        # LCD 显示图像
    lcd_key()                                               # LCD 显示按键信息及目标点信息

    led_control(red.led_flag)                               # LED 标记色块识别情况

    if mycnt == 0:                                          # 如果 mycnt 等于 0 此步骤的目的是控制打印周期 不要打印的太快
        mycnt = 1                                           # 将 1 赋值给 mycnt 使下一次不再满足 mycnt == 0 进入 elif
        print_sensor()                                      # 打印sensor参数
        print_blobs_property(black,"Black-")                # 打印黑色色块参数
        print_blobs_property(red,  "Red-  ")                # 打印红色色块参数

    elif mycnt < mycnt_max:                                 # 计数变量 小于 计数上限 则 计数变量 自增
        mycnt = mycnt + 1

    else:                                                   # 计数变量 超出 计数上限 则 将0赋值给 mycnt 使下一次进入 if
        mycnt = 0

#__________________________________________________________________

你可能感兴趣的:(学习,嵌入式硬件,单片机,图像处理,python)