MicroPython 中的按钮 (GPIO) 按下逻辑

Button (GPIO) Pressing Logic in MicroPython

我有另一个关于迭代菜单逻辑的问题,这个问题演变成按钮逻辑,所以我将它们分开,因为原来的问题已经真正解决了。

我的代码如下:

""" fit: a productivity logger """
import time
import sys
import os
import uhashlib
import machine
import framebuf
from ssd1306 import SSD1306_I2C

def final_print(sec,final_hash,final_survey):
    """ leaves the summary on the screen before shutting down """
    mins = sec // 60
    sec = sec % 60
    hours = mins // 60
    mins = mins % 60
    short_sec = int(sec)
    duration = (str(hours) + "/" + str(mins) + "/" + str(short_sec))
    oled_show("> fit the"+str(final_hash),str(final_survey),"//"+str(duration))
    time.sleep(30)
    oled_blank()

def timer_down(f_seconds,timer_focus):
    """ counts down for defined period """
    now = time.time()
    end = now + f_seconds
    while now < end:
        now = time.time()
        fit_progress(now,end,timer_focus,f_seconds)
        time.sleep(0.01)
#        if button1.value() == 0:
#             oled_show("","Ended Manually!","")
#             time.sleep(2)
#             break

def timer_up(timer_focus):
    """ counts up for indefinite period """
    now = time.time()
    while True:
        minutes = int((time.time() - now) / 60)
        oled_show(str(timer_focus)," for ",str(minutes))
        time.sleep(0.01)
#         if button1.value() == 0:
#             oled_show("","Ended Manually!","")
#             time.sleep(2)
#             break

def fit_progress(now,end,timer_focus,f_seconds):
    """ tracks progress of a count-down fit and prints to screen """
    remain = end - now
    f_minutes = int((remain)/60)
    j = 1 - (remain / f_seconds)
    pct = int(100*j)
    oled_show(str(timer_focus),str(f_minutes)+" min",str(pct)+"%")

def debounce(btn):
    """ some debounce control """
    count = 2
    while count > 0:
        if btn.value():
            count = 2
        else:
            count -= 1
        time.sleep(0.01)

def multi_choice(options):
    """ provides multi-choice menus for two-button navigation """
    for i in options:
        oled_show("> fit",i,"1:yes  2:next")
        # Wait for any button press.
        while 1:
            b1pressed = button1.value()
            b2pressed = button2.value()
            if b1pressed or b2pressed:
                break
        if b1pressed:
            print( i, "chosen" )
            debounce(button1)
            return i
        # We know B2 was pressed.
        debounce(button2)

def oled_show(message1,message2,message3):
    """ displays a three line message """
    oled.fill(0) # clear the display
    oled.text(message1,5,5)
    oled.text(message2,5,15)
    oled.text(message3,5,25)
    oled.show()

def oled_blank():
    """ blanks the oled display to avoid burn in """
    oled.fill(0)
    oled.show()

sda = machine.Pin(4)
scl = machine.Pin(5)
i2c = machine.I2C(0,sda=sda, scl=scl, freq=400000)
oled = SSD1306_I2C(128, 32, i2c)

button1 = machine.Pin(2, machine.Pin.IN, machine.Pin.PULL_UP)
button2 = machine.Pin(3, machine.Pin.IN, machine.Pin.PULL_UP)

F_TYPE = multi_choice(['30-minute fit','60-minute fit','indefinite fit'])

F_FOCUS = multi_choice(['personal fit','work fit','learn fit','admin fit'])

fStart = time.time()

if F_TYPE == "30-minute fit":
    timer_down(1800,F_FOCUS)
elif F_TYPE == "60-minute fit":
    timer_down(3600,F_FOCUS)
elif F_TYPE == "indefinite fit":
    timer_up(F_FOCUS)
else:
    sys.exit()

fEnd = time.time()

F_SURVEY = multi_choice(['went well','went ok','went poorly'])

fDuration = fEnd - fStart

F_HASH = uhashlib.sha256(str(fEnd).encode('utf-8')).digest()
F_HASH_SHORT = F_HASH[0:3]

fitdb = open("data.csv","a")
fitdb.write(str(F_HASH)+","+str(F_TYPE)+","+str(F_FOCUS)+","+str(F_SURVEY)+","+str(fStart)+","+str(fEnd)+","+str(fDuration)+"\n")
fitdb.close()

final_print(fDuration,F_HASH_SHORT,F_SURVEY)

特别是,你可以看到我定义了两个按钮:

button1 = machine.Pin(2, machine.Pin.IN, machine.Pin.PULL_UP)
button2 = machine.Pin(3, machine.Pin.IN, machine.Pin.PULL_UP)

它们主要用于 select 具有多种选择的菜单:

def debounce(btn):
    """ some debounce control """
    count = 2
    while count > 0:
        if btn.value():
            count = 2
        else:
            count -= 1
        time.sleep(0.01)

def multi_choice(options):
    """ provides multi-choice menus for two-button navigation """
    for i in options:
        oled_show("> fit",i,"1:yes  2:next")
        # Wait for any button press.
        while 1:
            b1pressed = button1.value()
            b2pressed = button2.value()
            if b1pressed or b2pressed:
                break
        if b1pressed:
            print( i, "chosen" )
            debounce(button1)
            return i
        # We know B2 was pressed.
        debounce(button2)

但是,我遇到了只能交替按下按钮的问题。也就是说,当 multi_choice 功能开始时,我可以按 button1 到 select 第一个选项,或者我可以按 button2 滚动到下一个选项,但是,如果我按 button2,例如,它将不会注册第二次按下(到 select 第二个选项),我只能然后按下按钮 1...如果我这样做,我只能然后按下按钮 2。

我确定这只是我没有看到的逻辑问题。

这些按钮是 GPIO 引脚 2 和 3 上的普通瞬时闭合 Cherry MX 开关。它们确实可靠地工作,但这种逻辑有些不可靠。

下面的测试工作正常,所以不是按钮...

import machine
import time

button1 = machine.Pin(2, machine.Pin.IN, machine.Pin.PULL_UP)
button2 = machine.Pin(3, machine.Pin.IN, machine.Pin.PULL_UP)

while True:
    b1pressed = button1.value()
    b2pressed = button2.value()
    time.sleep(0.01)
    b1released = button1.value()
    b2released = button2.value()
    if b1pressed and not b1released:
        print('Button1 pressed!')
    if b2pressed and not b2released:
        print('Button2 pressed!')
    if not b2pressed and b2released:
        print('Button2 released!')
    elif not b1pressed and b1released:
        print('Button1 released!')

我添加了一些打印语句来对此进行调试,我可以看到按钮获取和保持值。我觉得我需要调整人工重置,也许这​​是我可以在去抖动中做的事情?我尝试了一些方法,但到目前为止我没有取得进展。

def debounce(btn):
    """ some debounce control """
    count = 2
    while count > 0:
        if btn.value():
            count = 2
        else:
            count -= 1
        time.sleep(0.01)

def multi_choice(options):
    """ provides multi-choice menus for two-button navigation """
    for i in options:
        print("below for")
        print("button 1 below for",button1.value())
        print("button 2 below for",button2.value())
        oled_show("      fit",i,"1:sel    2:next")
        while 1:
            print("below while")
            print("button 1 below while",button1.value())
            print("button 2 below while",button2.value())
            b1pressed = button1.value()
            b2pressed = button2.value()
            if b1pressed or b2pressed:
                print("below first if")
                print("button 1 first if",button1.value())
                print("button 2 first if",button2.value())
                break
        if b1pressed:
            print("below second if")
            print("button 1 second if",button1.value())
            print("button 2 second if",button2.value())
            debounce(button1)
            return i
        debounce(button2)

以上调试打印的输出:

>>> %Run -c $EDITOR_CONTENT
below for
button 1 below for 0
button 2 below for 1
below while
button 1 below while 0
button 2 below while 1
below first if
button 1 first if 0
button 2 first if 1
below for
button 1 below for 1
button 2 below for 0
below while
button 1 below while 1
button 2 below while 0
below first if
button 1 first if 1
button 2 first if 0
below second if
button 1 second if 1
button 2 second if 0
below for
button 1 below for 0
button 2 below for 1
below while
button 1 below while 0
button 2 below while 1
below first if
button 1 first if 0
button 2 first if 1
below for
button 1 below for 1
button 2 below for 0
below while
button 1 below while 1
button 2 below while 0
below first if
button 1 first if 1
button 2 first if 0
below second if
button 1 second if 1
button 2 second if 0

将你的两个按钮都接地,并使用 PULL_UP 代码只是:

import machine

button1 = machine.Pin(2, machine.Pin.IN, machine.Pin.PULL_UP)
button2 = machine.Pin(3, machine.Pin.IN, machine.Pin.PULL_UP)

while True:
    print('Button1 down!') if not button1.value() else print('Button1 up!') 
    print('Button2 down!') if not button2.value() else print('Button2 up!')

逻辑很简单。您的按钮一端接地,另一端拉起。当您按下该按钮时,它会将 MCU 的引脚接地。按下按钮时 value() 将为零,释放时 value() 将为一。如果您希望 value() 在按下按钮时为正,则需要将按钮连接到 Vcc 轨并在 MCU 引脚上使用 PULL_DOWN

所有的去抖动代码可能都不是必需的,即使有必要创建一个循环来处理它也不是答案。如果你的按钮没有弹起怎么办~现在你只是陷入了一个循环。如果您担心弹跳,请获取 74HC14 或制作一个简单的 RC 网络。将所有这些任意值分配给按钮状态并将按钮粘在阻塞其他按钮的循环中只是一堆噪音。很简单:你有一个问题想问两次。 “这个按钮按下了吗”~所以只要“问”这个问题两次然后继续。不需要 20 行代码就可以确定某物是 1 还是 0。

旁白: 您没有单独的“GND”。您所有的“GND”引脚都连接到同一个“GND”。你只有一个电源吗?嗯,一个是一个。把一个蛋糕切成 8 块不会给你 8 个蛋糕。

好的,在大家的帮助下,我想通了。只需要添加一点睡眠以避免之前 while 循环的按键溢出。

def multi_choice(options):
    """ provides multi-choice menus for two-button navigation """
    for i in options:
        oled_show("      fit",i,"1:sel    2:next")
        time.sleep(0.5)
        while 1:
            if not button1.value():
                return i
            if not button2.value():
                break

谢谢大家!