Holy cow. That didn't take long at all. I've been working on this for less than an hour. This little board is just awesome.
I plan on cleaning this up, and making a nice couple of objects that will let you do things in coordinates other than microseconds. Something akin to the interface I was mentioning above. Here is a quick sample of code, in case I don't have time to get back to this:
Code: Select all
import pyb
import micropython
class Ppm(object):
"""
Read pulses from a particular pin.
@note, this uses timer 2.
"""
timer = None
def __init__(self, pin, servo = None):
"""
:pin: ex pyb.Pin.board.X4, the pin the input is connected to.
:servo: ex pyb.Servo(1) a servo to control directly from the interrupt.
"""
self.pin = pin
if Ppm.timer is None:
Ppm.timer = pyb.Timer(2, prescaler=83, period=0x0fffffff)
self.interrupt = Ppm.timer.channel(4, pyb.Timer.IC, pin=pin, polarity=pyb.Timer.BOTH)
self.start = 0
self.width = 0
self.servo = servo
self.interrupt.callback(self.callback)
def callback(self, tim):
if self.pin.value():
self.start = self.interrupt.capture()
else:
self.width = self.interrupt.capture() - self.start & 0x0fffffff
if self.servo:
self.servo.pulse_width(self.width)
def demo():
# This example requires a servo on X1 and a signal (from a radio) on X4.
micropython.alloc_emergency_exception_buf(100)
in_ppm = Ppm(pyb.Pin.board.X4, pyb.Servo(1))
while True:
# wait forever
pyb.delay(200)
class Cppm(object):
"""
Read a combined PPM signal from a R/C radio.
@note, this uses timer 2.
"""
timer = None
def __init__(self, pin, numChannels = 8, servo = None):
"""
:pin: ex pyb.Pin.board.X4, the pin the input is connected to.
:servo: ex pyb.Servo(1) a servo to control directly from the interrupt.
"""
self.pin = pin
if Ppm.timer is None:
Ppm.timer = pyb.Timer(2, prescaler=83, period=0x0fffffff)
self.interrupt = Ppm.timer.channel(4, pyb.Timer.IC, pin=pin, polarity=pyb.Timer.RISING)
self.start = 0
self.width = 0
self.channel = 0
self.numChannels = numChannels
self.ch = [0]*numChannels
self.sync_width = 0
self.frame_count = 0
self.servo = servo
self.interrupt.callback(self.callback)
def callback(self, tim):
self.width = (self.interrupt.capture() - self.start) & 0x0fffffff
self.start = self.interrupt.capture()
if self.width > 4000:
self.channel = 0
self.sync_width = self.width
self.frame_count += 1
return
if self.channel == self.numChannels:
return
self.ch[self.channel] = self.width
self.channel += 1
if self.servo:
if self.channel == 1:
self.servo.pulse_width(self.width)
def demo():
# This example requires a servo on X1 and a signal (CPPM from a radio) on X4.
micropython.alloc_emergency_exception_buf(100)
in_ppm = Cppm(pyb.Pin.board.X4, 8, pyb.Servo(1))
while True:
# wait forever
pyb.delay(200)
print(in_ppm.ch, in_ppm.sync_width, in_ppm.frame_count)
That includes a PPM (the normal inverse of a servo signal) and the CPPM, and it's under 100 lines even very spread out!
Here is some example output from Cppm.demo():
Code: Select all
[1512, 1525, 1772, 1441, 1519, 1512, 0, 0] 12726 490
[1525, 1525, 1772, 1441, 1519, 1512, 0, 0] 12729 499
[1205, 1525, 1772, 1441, 1518, 1512, 0, 0] 12977 508
[1025, 1524, 1772, 1441, 1519, 1512, 0, 0] 13210 517
[986, 1525, 1772, 1441, 1518, 1512, 0, 0] 13246 527
[1051, 1525, 1772, 1441, 1518, 1512, 0, 0] 13207 536
[1371, 1524, 1772, 1441, 1518, 1512, 0, 0] 12920 545
[1756, 1524, 1772, 1441, 1519, 1512, 0, 0] 12516 554
[2038, 1525, 1772, 1440, 1519, 1512, 0, 0] 12226 563
[2025, 1525, 1772, 1441, 1518, 1512, 0, 0] 12198 572
critiques, comments, improvments (especially w.r.t. the timer code) is greatly appreciated.