美文网首页玩转树莓派树莓派张国平玩树莓派
树莓派基础实验8:振动开关实验

树莓派基础实验8:振动开关实验

作者: Maker张 | 来源:发表于2020-02-11 00:22 被阅读0次

    一、介绍

       振动开关也称为弹簧开关或振动传感器,是一种电子开关。它会产生振动力,并将结果传送给电路装置,从而触发其工作。它包含以下部分:导电振动弹簧,开关主体,触发销和包装壳。


    二、组件

    ★Raspberry Pi主板*1

    ★树莓派电源*1

    ★40P软排线*1

    ★振动开关传感器模块*1

    ★双色LED模块*1

    ★面包板*1

    ★跳线若干

    三、实验原理

    振动开关 振动传感器实验原理图

      在震动开关模块中,导电的振动弹簧和触发销被精确地放置在开关体中,并且通过粘合剂结合到固化位置。通常,弹簧和触发销不接触,一旦摇动,弹簧就会摇动并与触发器引脚接触,以传导并产生触发信号。
      在此实验中,将双色LED模块连接到树莓派以指示更改。敲击或敲击振动传感器时,它将打开,双色led将闪烁绿色,再次敲击它将变为红色,每一次敲击后会在两种颜色之间切换。

    四、实验步骤

      第1步:连接电路,该实验与实验6(轻触开关按键实验)相同。这里激光模块的实物与模块原理图的端口名称不一致,我们按照实物的端口名称来连接。

    树莓派 T型转接板 振动开关
    GPIO 0(序号11) GPIO 17 SIG(DO)
    5V 5V VCC
    GND GND GND
    树莓派 T型转接板 双色LED
    GPIO 1(序号12) GPIO 18 R(红色端口)
    GND GND GND
    GPIO 2(序号13) GPIO 27 G(绿色端口)
    振动开关实验电路图 振动开关实验实物连接图

      第2步:这次编程有两个函数要注意,是关于输入的高级应用。
      有多种方式将GPIO的输入导入到程序中,polling( 轮询 )式 和 interrupt( 中断 )式( edge detection 边缘检测 ),“轮询”式如果程序在错误的时间读取值,可能会错过输入。我们这里采用中断式。
      如果您没有将输入引脚连接到任何东西,它将“浮动”。换句话说,读取的值是未定义的,因为它没有连接到任何东西,直到你按下按钮或开关。它可能会由于接收电源干扰而改变很大的值。
      为了解决这个问题,我们使用一个向上拉或向下拉电阻器。这样,就可以设置输入的默认值。可以使用硬件或者软件实现上下拉电阻。在硬件方式中,常常在输入通道与3.3V(上拉)或0V(下拉)之间使用10K电阻。GPIO模块允许您在编程中这样配置:

    GPIO.setup(channel, GPIO.IN, pull_up_down=GPIO.PUD_UP)
      # or
    GPIO.setup(channel, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
    

      我们很多时候并不关心电平值, 而关心电平从低到高,或从高到低的变化(如编码器测速/按键按下弹开等), 为避免主程序忙于其它事情错过引脚的电平改变, 有两种方式:
      wait_for_edge() 函数
       event_detected() 函数
       wait_for_edge()函数是为了阻止程序的执行,直到检测到边缘为止。换句话说,等待按钮按下的示例可以改写成:

    GPIO.wait_for_edge(channel, GPIO.RISING)
    

       注意检测的边缘参数有 GPIO.RISING, GPIO.FALLING , GPIO.BOTH (上升沿, 下降沿 或 升降沿), 这样用几乎不占用CPU,如果你只希望在确定的时间段内查询,可以使用 timeout 参数:

    # wait for up to 5 seconds for a rising edge (timeout is in milliseconds)
    channel = GPIO.wait_for_edge(channel, GPIO_RISING, timeout=5000)
    if channel is None:
        print('Timeout occurred')
    else:
        print('Edge detected on channel', channel)
    

      event_detected()函数被设计用来与其他事物一起在循环中使用, 不同于polling轮询, 它不会在CPU忙于处理其他事物时错过输入状态的变化。 这使得使用Pygame 或 PyQt 时非常有用,因为其中有一个主循环监听和及时响应GUI事件的基础。
      只要检测到指定参数的边缘事件(上升沿, 下降沿 或 升降沿)发生时,调用GPIO.event_detected(channel)的值就为"ture"(真)。

    #Note that you can detect events for GPIO.RISING, GPIO.FALLING or GPIO.BOTH.
    GPIO.add_event_detect(channel, GPIO.RISING)  # add rising edge detection on a channel
    do_something()
    if GPIO.event_detected(channel):
        print('Button pressed')
    

      不过需要自己新建一个线程去循环检测event_detected()的值,还算是比较麻烦的。
      可采用另一种办法轻松检测状态,这种方式是直接传入一个回调函数:GPIO通过在add_event_detect()函数中添加callback参数,RPI.GPIO为回调函数运行第二个线程。这意味着回调函数可以与主程序同时运行,以立即响应边缘。
      For example:

    def my_callback(channel):
        print('This is a edge event callback function!')
        print('Edge detected on channel %s'%channel)
        print('This is run in a different thread to your main program')
    GPIO.add_event_detect(channel, GPIO.RISING, callback=my_callback) 
     # 这里添加了回调函数callback这个参数,就不需要GPIO.event_detected(channel)函数了
    

      如果你想要不止一个回调函数:

    def my_callback_one(channel):
        print('Callback one')
    def my_callback_two(channel):
        print('Callback two')
    GPIO.add_event_detect(channel, GPIO.RISING)
    GPIO.add_event_callback(channel, my_callback_one)
    GPIO.add_event_callback(channel, my_callback_two)
    

      请注意,在这种情况下,回调函数是按顺序运行的,而不是并发的。这是因为只有一个线程用于回调,其中每个回调都按照它们被定义的顺序运行。

      由于存在开关抖动(用示波器可以看到),每次按下开关会调用多次回调函数,这不是我们希望的,有两种方式处理开关抖动:
      ①在开关两个引脚之间添加一个0.1uF的电容
      ②软件消抖
      ③二者结合使用
      使用软件消抖时, 给回调函数添加一个弹跳时间的参数( bouncetime= ), 弹跳时间(参照单片机可以为10~20ms)在ms级别, 下面的程序用200ms来消抖:

    # add rising edge detection on a channel, ignoring further edges for 200ms for switch bounce handling
    GPIO.add_event_detect(channel, GPIO.RISING, callback=my_callback, bouncetime=200)
    

      由于某些原因, 你的程序可能不希望用边缘检测了,可以停止它们:

    GPIO.remove_event_detect(channel)
    

      第3步:正式编程。定义针脚参数和初始化设置函数setup(),其中就用到了上面讲解的GPIO输入高级应用,本次实验不使用检测函数GPIO.add_event_detect(),采用“轮询”式,在循环中直接查询GPIO.input(TiltPin)的值来判定是否振动。

    #!/usr/bin/env python
    import RPi.GPIO as GPIO
    import time
    
    VibratePin = 11
    Rpin   = 12
    Gpin   = 13
    
    tmp = 0
    
    def setup():
        GPIO.setmode(GPIO.BOARD)       # Numbers GPIOs by physical location
        GPIO.setup(Gpin, GPIO.OUT)     # Set Green Led Pin mode to output
        GPIO.setup(Rpin, GPIO.OUT)     # Set Red Led Pin mode to output
        GPIO.setup(VibratePin, GPIO.IN, pull_up_down=GPIO.PUD_UP) 
       # Set BtnPin's mode is input, and pull up to high level(3.3V)
    

      第4步:定义Led(x)函数,控制双色LED灯闪烁。定义Print(x),打印按键是否切换开关的提示消息。

    def Led(x): #控制双色LED灯闪烁的函数
        if x == 0:
            GPIO.output(Rpin, 1)    #红灯亮
            GPIO.output(Gpin, 0)    #绿灯灭
        if x == 1:
            GPIO.output(Rpin, 0)
            GPIO.output(Gpin, 1)
        
    
    def Print(x):   #打印按键是否切换开关的提示消息
        global tmp
        if x != tmp:
            if x == 0:
                print '    **********'
                print '    *     ON *'
                print '    **********'
        
            if x == 1:
                print '    **********'
                print '    * OFF    *'
                print '    **********'
            tmp = x
    

      第5步:当模块平稳没有振动时,GPIO.input(TiltPin)的值为0,IF语句不执行;
      当振动时,GPIO.input(TiltPin)的值为1,执行IF语句。每次执行IF语句时,Led(state)中的state值都与上次不同,所以LED的颜色会在红绿之间切换。

    def loop():
        state = 0
        while True:
            if GPIO.input(VibratePin):  #每当振动产生时
                state = state + 1
                if state > 1:
                    state = 0
                Led(state)
                Print(state)
                time.sleep(1)
    

      第6步:创建destroy()函数,清除LED状态。创建程序入口,并包含异常处理。

    def destroy():
        GPIO.output(Gpin, GPIO.LOW)       # Green led off
        GPIO.output(Rpin, GPIO.LOW)       # Red led off
        GPIO.cleanup()                     # Release resource
    
    if __name__ == '__main__':     # Program start from here
        setup()
        try:
            loop()
        except KeyboardInterrupt:  # When 'Ctrl+C' is pressed, the child program destroy() will be  executed.
            destroy()
    

    相关文章

      网友评论

        本文标题:树莓派基础实验8:振动开关实验

        本文链接:https://www.haomeiwen.com/subject/ghezxhtx.html