主板实验 |如何读取按键和拨码开关的状态?

\\\\\\\\r\\\\\\\\n

 

01 键和开关


一、前言

  在电路主板中,包含有按钮和拨码开关。 两个拨码开关可以用于程序功能的设置。  三个按键, 配合 LCD, 可以实现人机接口设计, 用于临时修改软件参数。 下面介绍一下读取按键和开关的示例程序。  通过熟悉这些开关的应用, 可以为编写更加灵活和复杂的程序提供帮助。

G5M1720935873_1920_1080.MP4|_-5

二、硬件原理

  首先, 让我们了解一下读取开关和按键状态的基本原理。  本质上, 按键和开关在单片机看来是相同的。 都是具有两种状态的开关。 只是按键是手工按动, 可以有多种变化。 开关则是相对静态的, 不会经常变化。  下面就以按键为例, 来说明单片机读取按键的基本原理。 

  根据主板的原理图, 可以找到三个按键对应的电路部分。  三个按键对应的器件标号 K0, K1, K2。 它们分别将三个单片机端口能够接地,  或者断开悬空。  此时, 对应的端口通过一个10k欧姆的电阻连接到 3.3V 电源,  对应这个端口的电位是高电平, 从单片机软件读取的逻辑数据对应 是 1。 如果按键按下, 对应的端口电平变低,  单片机软件读取端口的逻辑数据为 0。 

  三个按键对应端口编号为 P30, P31, 以及 P1。 这个编号很重要, 在软件中通过这个编号来确定读取的按键标号。  在OpenMV 模块管脚定义图中,  可以找到这三个标号对应的端口。  外部是单片机实际的端口, 通常情况下, 单片机端口在 MicroPython 编程中用不到,  外边则是表示该端口有可能对应的附加功能,  比如可能是 串口、 ADC端口, 或者 SPI 端口等。

G18M1720938208_1920_1080.MP4|_-18
  下面使用示波器,  观察一个按键两端的电压。 对于按键 K2, 它的左边是端口输入端, 通过电阻上拉到3.3V。 右边接地。  按动按键, 观察端口的电平变化,  可以看到按键按下之后, 端口电压变低; 抬起按键, 端口电压变高。

G5M1720938804_1920_1080.MP4|_-5

▲ 图1.2.1  按键按动对应的端口电平变化

▲ 图1.2.1 按键按动对应的端口电平变化

  在原理图中, 我们可以找到拨码开关对应的电路图。  重要的是, 拨码开关对应的 单片机端口分别为 P32, P33。

G2M1720939013_1920_1080.MP4|_-2

三、直接读取

  先介绍一个最基本的读取端口高低电平状态的方式。  这个程序不是在给定的学习资料中具备的。  首先从 pyb 库中引入 Pin 对象。 通过它可以读取或者设置单片机管脚的状态。 下面三个语句分别声明三个按键 实例,  通过 Pin 对象进行构造。 构造函数有三个参数,  第一个就是端口的名称, 这里保持与电路图中对应的端口标号一致。  第二个参数设定端口输入输出特性, 这里设置该端口为输入端口。  第三个参数设置端口偏置属性, 这里是端口被单片机内部上拉电阻置为高电平。  所以, 实际上电路中无需外部再增加一个上拉电阻了。  下面是循环程序段。  依次读取按键状态, 如果是低电平,  则通过 print 语句显示该端口为低电平。   查询一遍之后,  等待 0.2秒。  这是整个测试程序的内容。  下面来运行一下该程序。

G16M1720940267_1920_1080.MP4|_-16

from pyb                    import Pin
import time

key0 = Pin("P30", Pin.IN, Pin.PULL_UP)
key1 = Pin("P31", Pin.IN, Pin.PULL_UP)
key2 = Pin("P1", Pin.IN, Pin.PULL_UP)

while True:
    if key0.value() == 0:
        print("Key0 Down.")

    if key1.value() == 0:
        print("Key1 Down.")

    if key2.value() == 0:
        print("Key0 Down.")

    time.sleep(.2)

  为了观察程序中 print 输出字符, 需要将串口终端打开。  按动按键, 便可以看到程序输出检测到按键按动的信息。  读取拨码开关的方式, 与按键是相同的,  只要将对应的端口号修改成拨码开关对应的端口名称即可。

G4M1720940516_1920_1080.MP4|_-4

四、按键类

  相比与拨码开关, 按键的功能稍微要复杂一些。 比如, 为了扩展一个按键输入信息的功能, 可以定义按键有三种输入模式, 一种是普通的按动一次, 第二种是双击按动, 也就是快速按动两次, 第三种就是长时间按动。 这样就可以把一个按键的功能变成三个按键功能。 有的时候, 还需要对按键进行消除抖动。   在软件编程方面, 这就需要编写额外的代码来处理按键信号。  在给定的学习资料中, 有一个 LQ Module 文件,  它内部定义了一些 程序类。  封装了很多有用的功能。 大家在应用这个软件包之前, 需要把它先拷贝到 OpenMV 对应的 U 盘内。   下面浏览一下这个文件中的内容。   这个文件中 主要定义了 三个 类, 一个是用于控制电机运行的类, motor; 第二个是读取编码器的类, ENCODER AB; 第三个就是按键类别。 对于初学者, 在这里先不展开讨论这个模块中的类别的实现方式。 大家可以把它和其他软件包一样来应用就可以了。 只要在调用程序中 导入它即可。

G7M1720941954_1920_1080.MP4|_-7

"""
# 调用示例,
注意:需了解 所用管脚pin_pwm为定时器timer几的通道chl几

# 从自定义模块LQ_Motor中导入两个自定义电机对象
import LQ_Motor
from LQ_Motor import motor,motor_brushless   # 不使用此句则需要在对象前加 模块名. LQ_Motor.motor(...)

#参数(self, timer, chl, freq, pin_pwm, pin_io)

motor1 = motor(timer=4, chl=3, freq=10000, pin_pwm="P9", pin_io="P24")
motor1.run(cnt)
motor1.run_percent(cnt)   # PWM 百分比 计
motor1.run(cnt)           # 实际脉宽24000满

#LQ 无刷驱动 在50Hz 下1~2ms范围2000~4000, 算上驱动死区可控范围约在 2240 ~3800

M1= motor_brushless(4, 1, 50, "P7")  #参数(self, timer, chl, freq, pin_pwm)
M1.run(2300)

"""
import pyb,time
from pyb import Pin, Timer,ExtInt

class motor:
    def __init__(self, timer, chl, freq, pin_pwm, pin_io):
        self.io = Pin(pin_io, Pin.OUT_PP, Pin.PULL_NONE)
        self.chl = chl
        self.timer = timer
        self.freq = freq
        self.duty = 0
        self.tim = Timer(self.timer, freq=self.freq)
        self.pwm = self.tim.channel(self.chl, Timer.PWM, pin=Pin(pin_pwm), pulse_width_percent=self.duty)

    def run_percent(self, duty):
        duty = int(duty)
        if(duty<0):
            self.duty = -duty
            self.io.value(1)
            self.pwm.pulse_width_percent(self.duty)
        else:
            self.duty = duty
            self.io.value(0)
            self.pwm.pulse_width_percent(self.duty)

    def run(self, duty):
        duty = int(duty)
        if(duty<0):
            self.duty = -duty
            self.io.value(1)
            self.pwm.pulse_width(self.duty)
        else:
            self.duty = duty
            self.io.value(0)
            self.pwm.pulse_width(self.duty)

class motor_brushless:
    def __init__(self, timer, chl, freq, pin_pwm):
        self.chl = chl
        self.timer = timer
        self.freq = freq
        self.duty = 0
        self.tim = Timer(self.timer, freq=self.freq)
        self.pwm = self.tim.channel(self.chl, Timer.PWM, pin=Pin(pin_pwm), pulse_width_percent=self.duty)

    def run(self, duty):
        duty = int(duty)         #pulse_width只接受int类型的参数
        if(duty<0):      #abs
            self.duty = -duty
        else:
            self.duty = duty
        self.pwm.pulse_width(self.duty)

#____LQ_Motor end_____

"""
#调用示例

import pyb, time, LQ_Enc
from pyb import Pin, Timer
from LQ_Enc import Enc_AB, Encoder

#初始化  定时器,频率(多久读一次),管脚, 适用于AB和带方向的编码器以及单一脉冲的编码器

#带方向的
Enc1 = Enc_AB(Timer(12, freq=10), Enc_A="P24", Enc_B="P23")

#不带方向的
Enc2 = Encoder(Timer(14, freq=10), Encpin="P23")

while True:
    time.sleep_ms(30)   # 延时多久无所为

    print(Enc1.Get(), Enc2.Get())

"""
class Enc_AB:
    def __init__(self, timer, Enc_A, Enc_B):
        self.pin_A = Pin(Enc_A, Pin.IN, Pin.PULL_DOWN)
        self.pin_B = Pin(Enc_B, Pin.IN, Pin.PULL_DOWN)
        self.counter = 0
        self.cnt = 0
        self.set_callbacks()
        timer.callback(self.Enc_tick)

    def __ENC_cnt(self, line):
        if(self.pin_B.value()):
            self.counter += 1
        else:
            self.counter -= 1

    def Enc_tick(self, tim):
        self.cnt = self.counter
        self.counter = 0
#        print(self.cnt)

    def set_callbacks(self):

        ExtInt(self.pin_A, ExtInt.IRQ_RISING, self.pin_A.PULL_DOWN, self.__ENC_cnt)

    def Get(self):
        return  self.cnt

class Encoder:
    def __init__(self, timer, Encpin):
        self.pin_A = Pin(Encpin, Pin.IN, Pin.PULL_DOWN)
        self.cntr = 0
        self.Ecnt = 0
        self.set_Init()
        timer.callback(self.Enc_tims)

    def ENC_cntr(self, line):
        self.cntr += 1

    def Enc_tims(self, tim):
        self.Ecnt = self.cntr
        self.cntr = 0

    def set_Init(self):
        ExtInt(self.pin_A, ExtInt.IRQ_RISING, self.pin_A.PULL_DOWN, self.ENC_cntr)

    def Get(self):
        return  self.Ecnt
# ______ LQ_Enc  end __________

"""_class_key
"""
class key:
    def __init__(self, key_pin, timeout = 650):
        self.pin = Pin(key_pin, Pin.IN, Pin.PULL_UP)
        self.count = 0
        self.flag = 0
        self.status = 0
        self.timeout = timeout

    def down(self):
        if(self.flag == 0):
            if(self.pin.value() == 0):
                return 1
            else:
                return 0
        else:
            return 0
    def up(self):
        if(self.flag == 0):
            if(self.pin.value() == 0):
                while(self.pin.value() == 0):
                    pass
                return 1
            else:
                return 0
        else:
            return 0

    def value(self):
        return self.pin.value()

    def hold(self):
        if(self.pin.value() == 0):              # 按键按下
            if(self.flag == 0):                 # 判断标志位是否为长按状态下 否-往下执行
                for i in range(self.timeout):
                    self.count = 1              # 按键按下标志为1
                    time.sleep_ms(1)            # 延时
                    if(self.pin.value() == 1):  # 再次判断按键是否按下
                        return 0
                self.flag = 1                   # 长按标志位置1
                return self.flag                # 返回标志位

            else:
                if(self.pin.value() == 1):
                    self.count = 0
                    self.flag = 0
                    return 0
                else:
                    return 1
        else:
            self.count = 0
            self.flag = 0
            return 0
# ______ LQ_key  end __________

  下面打开给定学习资料中, 按键目录的 button 程序,  这个程序就是应用了 LQ Module 中的 程序类 。 程序开始仍然导入 Pin 类, 这里从 LQ Module中 导入 key 类。 注意, 需要将 LQ Module 文件事先拷贝到 OpenMV U 盘根目录下。  定义三个 LED, 用于显示 按键的状态。  使用 key 程序类 定义三个按键,   构造函数参数, 说明按键对应的单片机端口号。  前面是三个按键 实例变量。  在后面的循环体中, 顺序检查三个按键的状态。  如果调用 按键对象成员函数 down, 返回为 1 时, 说明该按键按下,  点亮对应的LED, 同时输出字符串。  否则, 关闭对应的LED。  其它两个按键处理方式都是相同的。  每次循环延时 0.2 秒。

G14M1720942519_1920_1080.MP4|_-14
  下载这个程序, 打开串口终端。 按动按键, 可以看到串口终端输出对应的字符串。   OpenMV 板上的 RGB LED 也会点亮对应的 LED。   说实在的, 在 Module 模块中定义的 key 程序类, 功能不是很好。 另外定义的 motor, 和 编码器 对应的类别的功能还是可以的。

G3M1720942750_1920_1080.MP4|_-3

 

  结 ※


  文介绍了如何读取按键和拨码开关的状态。 大家可以根据这里的实验, 对于给定资料中 Button 目录下的其它两个示例程序进行实验, 查看一下它们各自功能实现的 原理。   通过读取按键和拨码开关, 可以有效动态更改程序的功能, 或者运行参数,  在软件调试的过程中, 可以节省大量的时间。   通过对示例程序的模仿和测试, 也可以提高 MicroPython 编程的能力。

G4M1720943071_1920_1080.MP4|_-4


■ 相关文献链接:

● 相关图表链接:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

卓晴

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值