I may be reinventing the wheel, but I wrote this anyway to cut my teeth on FEZ. (FEZ ROCKS, btw, in case anyone wasn’t sure.)
So I’m working on gyro stabilization using a gyro sensor pulled from a Wii Motion. I am taking inputs from an RC receiver processing them (that’s in dev now) and outputting to the servos. I wrote a simple PWM wrapper using interrupts.
I share because I love. (not sure it’s useful to anyone but me but there you go)
class PWMInput : IDisposable
{
private long pulseTicks = 0;
private long lowHighTicks = 0;
private InterruptPort ppmInputPort;
// todo: publish event
public PWMInput(Cpu.Pin inputPin)
{
ppmInputPort = new InterruptPort(inputPin, false, Port.ResistorMode.Disabled,
Port.InterruptMode.InterruptEdgeBoth);
ppmInputPort.OnInterrupt += new NativeEventHandler(ppmInputPort_OnInterrupt);
}
void ppmInputPort_OnInterrupt(uint data1, uint data2, DateTime time)
{
if (data2 == 1) // low -> high
{
lowHighTicks = time.Ticks;
}
else // high -> low
{
pulseTicks = time.Ticks - lowHighTicks;
}
}
public int Value
{
get
{
return (int)pulseTicks / 10;
}
}
public void Dispose()
{
ppmInputPort.DisableInterrupt();
}
}
i have modified one of the ppm classes i found kicking about on this forum, below is the implementation of the class i`ll post the class next, i was going to do a wiki on this but here it is anyway, hope this helps
IMPLEMENTED CLAS
using System;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using GHIElectronics.NETMF.FEZ;
using PPM_Application.API;
namespace PPM_Application
{
public class Program
{
static RC_Input Throttle;
static RC_Input Yaw;
static RC_Input Pitch;
static RC_Input Roll;
public static void Main()
{
Throttle = new RC_Input(FEZ_Pin.Interrupt.Di7, false, 10000, 20000, -100, 100);
Yaw = new RC_Input(FEZ_Pin.Interrupt.Di6, false, 10000, 20000, -100, 100);
Pitch = new RC_Input(FEZ_Pin.Interrupt.Di5, true, 10000, 20000, -100, 100);
Roll = new RC_Input(FEZ_Pin.Interrupt.Di4, false, 10000, 20000, -100, 100);
while (true)
{
Debug.Print(" Throttle: " + Throttle.ActualPosition.ToString() + " Yaw: " + Yaw.ActualPosition.ToString() + " Pitch: " + Pitch.ActualPosition.ToString() + " Roll: " + Roll.ActualPosition.ToString());
Thread.Sleep(2000);
}
}
}
}
ACTUAL CLASS
using System;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using GHIElectronics.NETMF.FEZ;
namespace PPM_Application.API
{
class RC_Input
{
int internalRead = 0;
long ticks = 0;
int InputMin = 0;
int InputMax = 0;
int ScaledMin = 0;
int ScaledMax = 0;
bool Direction = false;
int Result = 0;
public RC_Input(FEZ_Pin.Interrupt inputPin, bool InvertPolarity, int Input_Min, int Input_Max, int Scaled_Min, int Scaled_Max)
{
InterruptPort inputHandle = new InterruptPort((Cpu.Pin)inputPin, false, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeBoth);
inputHandle.OnInterrupt += new NativeEventHandler(inputHandle_OnInterrupt);
InputMin = Input_Min;
InputMax = Input_Max;
ScaledMin = Scaled_Min;
ScaledMax = Scaled_Max;
Direction = InvertPolarity;
}
void inputHandle_OnInterrupt(uint port, uint state, DateTime time)
{
if (state == 0)
{
internalRead = (int)(time.Ticks - ticks);
}
else
ticks = time.Ticks;
}
public int ActualPosition
{
get
{
Result = (internalRead - InputMin) * (ScaledMax - ScaledMin) / (InputMax - InputMin) + ScaledMin;
if (Direction == false)
{
return Result;
}
else
return (Result * (-1));
}
}
}
}
Throttle = new RC_Input(FEZ_Pin.Interrupt.Di7, false, 10000, 20000, -100, 100);
create new instance of class, (interruptpin,invertresults ie stick upsidedown, max in , min in,scaled min output, scaled max output).
which equates to being able to set the positive direction of the rc input and scale it from 1to2millisecond input pulses to -100to100 engineering outputs