树莓派使用Python检测连续脉冲

树莓派使用Python检测连续脉冲

1、应用场景

使用树莓派作为智能小车主控制器时,需要对轮子进行测速,采用的是马达+霍尔传感器的形式,小车运动时霍尔传感器会输出连续脉冲信号,通过转换就可以得到小车的速度,前行的距离等等。本博文用于流量传感器检测连续脉冲场景,通过转换可以得到流量大小。

2、检测方式

使用到了树莓派GPIO的输入(Input)功能,可分为以下几种情况(需要先安装RPi.GPIO)。

# Python 2.X
pip install RPi.GPIO
# Python 3.X
pip3 install RPi.GPIO

上拉/下拉电阻

当GPIO没有连接任何元件时,其状态是不可控的,为解决这一问题,需要使用到上拉和下拉电阻,用于设定输入的默认值。使用硬件方式,通常需要将一个 10K 的电阻连接在输入通道与 3.3V(上拉)或 0V(下拉)之间。而树莓派可以通过软件实现GPIO的上拉和下拉:

GPIO.setup(channel, GPIO.IN, pull_up_down``=``GPIO.PUD_UP)

或者

GPIO.setup(channel, GPIO.IN, pull_up_down``=``GPIO.PUD_DOWN)

轮询(Polling)

可在某一时刻获取GPIO输入值:

if GPIO.input(channel):
    print('Input was HIGH')
else:
    print('Input was LOW')

也可以循环判断:

while GPIO.input(channel) == GPIO.LOW:
    time.sleep(0.01)# 为 CPU 留出 10 毫秒,供其处理其它事物

中断和边缘检测

可使用中断或者边缘检测监测GPIO状态,可用到以下两个函数:

  • wait_for_edge() 函数
  • event_detected() 函数

wait_for_edge()

用于在检测到边缘之前阻止程序的运行。换句话说,上面的示例中,等待按钮被按下的语句可以改写为:

GPIO.wait_for_edge(channel, GPIO.RISING)
  • GPIO.RISING:上升沿触发
  • GPIO.FALLING:下降沿触发
  • GPIO.BOTH:都触发

event_detected()

设计用于循环中有其它东西时使用,但不同于轮询的是,它不会错过当 CPU 忙于处理其它事物时输入状态的改变。这在类似使用 Pygame 或 PyQt 时主循环实时监听和响应 GUI 的事件是很有用的。

GPIO.add_event_detect(channel, GPIO.RISING) # 在通道上添加上升临界值检测
do_something()
if GPIO.event_detected(channel):
    print('Button pressed')

触发方式也有三种,同上。

线程回调

RPi.GPIO 在第二条线程中执行回调函数。这意味着回调函数可以同您的主程序同时运行,并且可以立即对边缘进行响应。例如:

def my_callback(channel):
    print('这是一个边缘事件回调函数!')
    print('在通道 %s 上进行边缘检测'%channel)
    print('该程序与您的主程序运行在不同的进程中')
GPIO.add_event_detect(channel, GPIO.RISING, callback=my_callback) # 在通道上添加上升临界值检测``... 其它程序代码 ...

如果您需要多个回调函数:

def my_callback_one(channel):
    print('回调 1')
def my_callback_two(channel):
    print('回调 2')
GPIO.add_event_callback(channel, my_callback_one)
GPIO.add_event_callback(channel, my_callback_two)

【注意】在该示例中,回调函数为顺序运行而不是同时运行。这是因为当前只有一个进程供回调使用,而回调的运行顺序是依据它们被定义的顺序。

开关防抖

按键按下时,回调操作调用不止一次,这种现象称为“开关抖动”,有两种方式可以解决:

  • 将一个0.1uf电容连接到开关上
  • 软件去抖

软件去抖可以在回调函数中添加bouncetime参数:

# 在通道上添加上升临界值检测,忽略由于开关抖动引起的小于 200ms 的边缘操作
GPIO.add_event_detect(channel, GPIO.RISING, callback = my_callback, bouncetime = 200)

或者

GPIO.add_event_callback(channel, my_callback, bouncetime=200)
remove_event_detect()

由于某种原因,您不希望您的程序检测边缘事件,您可以将它停止:

GPIO.remove_event_detect(channel)

3、检测代码

#霍尔脉冲读取函数
GPIO.setup(18, GPIO.IN,pull_up_down=GPIO.PUD_UP)   #通过18号引脚读取左轮脉冲数据
GPIO.setup(35, GPIO.IN,pull_up_down=GPIO.PUD_UP)   #通过35号引脚读取右轮脉冲数据
counter=0      #左轮脉冲初值
counter1=0     #右轮脉冲初值
def my_callback(channel):          #边缘检测回调函数,详情在参见链接中
    global counter                 #设置为全局变量
    if GPIO.event_detected(18):        #检测到一个脉冲则脉冲数加1
        counter=counter+1
#这里的channel和channel1无须赋确定值,不能不写。
def my_callback1(channel1):            
    global counter1
    if GPIO.event_detected(35):
        counter1=counter1+1
GPIO.add_event_detect(18,GPIO.RISING,callback=my_callback) #在引脚上添加上升临界值检测再回调
GPIO.add_event_detect(35,GPIO.RISING,callback=my_callback1)

参考连接

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章