使用树莓派作为智能小车主控制器时,需要对轮子进行测速,采用的是马达+霍尔传感器的形式,小车运动时霍尔传感器会输出连续脉冲信号,通过转换就可以得到小车的速度,前行的距离等等。本博文用于流量传感器检测连续脉冲场景,通过转换可以得到流量大小。
使用到了树莓派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)
可在某一时刻获取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状态,可用到以下两个函数:
用于在检测到边缘之前阻止程序的运行。换句话说,上面的示例中,等待按钮被按下的语句可以改写为:
GPIO.wait_for_edge(channel, GPIO.RISING)
设计用于循环中有其它东西时使用,但不同于轮询的是,它不会错过当 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)
【注意】在该示例中,回调函数为顺序运行而不是同时运行。这是因为当前只有一个进程供回调使用,而回调的运行顺序是依据它们被定义的顺序。
按键按下时,回调操作调用不止一次,这种现象称为“开关抖动”,有两种方式可以解决:
软件去抖可以在回调函数中添加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)
#霍尔脉冲读取函数
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)
参考连接
树莓派中用python检测连续脉冲
使用 RPi.GPIO 模块的输入(Input)功能