Inputs with Events


The preceding program will work well, but it is an example of polling. To monitor the state of the button, the switch continuously reads the value from the input port, meaning that the program is running at all times. This uses considerable processor time and may result in the flashlight battery draining before it has even been switched on.

A much better way to manage inputs of this kind is to use interrupts. An interrupt is initiated by a change in the state of a port. Special circuitry that generates a signal that causes the processor to pause the currently executing program and run code in an interrupt handler detects this change. Once the interrupt has been dealt with, the program will resume execution.

In conventional embedded programming, the use of interrupts can be quite tricky. The programmer has to create the interrupt handler, bind that to the required interrupt, and then enable the interrupt signal hardware. Using the .NET Micro Framework, things are a lot easier. Rather than create an InputPort instance, you need to create an InterruptPort.

 InterruptPort switchInterrupt = new InterruptPort(switchPin, // desired pin    false, // no glitch filter    Port.ResistorMode.PullDown, // pull the input down    Port.InterruptMode.InterruptEdgeBoth); // trigger on both edges 

The InterruptPort is created very similarly to our previous input port, except for an additional parameter at the end that selects the signal conditions that will cause the interrupt to be produced. If you think about it, you realize that a signal can do two things: it can move from low to high, or from high to low. With some devices, you might be interested only in transitions from low to high-for example, an analogue-to-digital converter may signal completion of a conversion by raising a signal line. If you care only about transitions in one direction, you can create an interrupt port that only detects such transitions.

At the moment, we have only the interrupt port. Next, we have to connect our interrupt handler to the port itself. To understand how to make this work, we must understand delegates.

Methods and Delegates

We have already seen that an instance of a class can contain data properties and executable methods. The properties hold the information and the methods give the instance its behaviors. To make our interrupt useful, we need a way to connect a particular method in an instance to the event that is triggered when the interrupt occurs. To achieve this, the C# language provides a mechanism called a delegate. A delegate is a reference to a method in an instance of a class. We create a delegate to refer to a method. We can then add this delegate instance to a list maintained by the event so that the delegate knows to call the method when the event occurs.

If you are a C programmer, you will be familiar with the idea of pointers to functions. You will also be accustomed to the experience of your program failing when you call the wrong type of function using a pointer. C# delegates are like pointers to functions, but are vastly more useful because they are type safe. Type safe means that there is no question of incorrectly calling the method referred to by a delegate, because the runtime system will make sure that all calls of the delegate are consistent with its declaration.

An Interrupt-Handler Method

Before we can create the delegate, we need to have a method that it can refer to. The method must have a particular construction because it is going to bind into part of the .NET Micro Framework system.

 static void switchInterrupt_OnInterrupt(Cpu.Pin port,  // the pin causing the interrupt      bool state,    // the state of the pin      TimeSpan time) // the time of the interrupt {      lampOutput.Write(state); } 

This is the method that we want to connect to the interrupt. This method has a specific signature, that is, a set of parameters, which are how the .NET Micro Framework delivers information to it. From the parameters, we can determine which port caused the interrupt, the state that it is now in, and the time at which the event was detected. This method ignores the port and time information and just uses the state value to control the output. Whenever the state of the input changes, the light will change to match it.

As far as the rest of the system is concerned, once our lamp and switch are tied together like this, there is no need for our program to do anything to keep track of the switch; whenever the input changes, our code is alerted and can behave appropriately. This behavior is directly analogous to the way in which a Windows Forms application is made to respond to user events such as button presses. When the user clicks a button on the screen, the window manager creates a thread that calls the event handler. Exactly the same thing happens in the .NET Micro Framework, making hardware components as easy to interact with as software components.

Note 

The .NET Micro Framework has quite a bit of work to do to create a thread and then invoke the interrupt handler does mean that there will be a time lag between the interrupt occurring and your code getting control. In most situations, this is not a problem, but it does mean that hard real-time applications (those applications that require a deterministic response time) may not be suitable for this Framework.

Connecting an Interrupt Handler to an Event

Now that we have our InterruptPort instance and our handler method, we need to connect them together. An interrupt port instance contains an interrupt handler that maintains a list of delegates that have bound to its event. To get things to work, we just have to add our delegate to this handler. To make our lives easier, the creators of the .NET Micro Framework Library have overloaded the += operator.

 switchInterrupt.OnInterrupt +=      new GPIOInterruptEventHandler(switchInterrupt_OnInterrupt); 

OnInterrupt is the event handler for our interrupt port. This code makes a new instance of a GPIOInterruptEventHandler and then adds to the event handler a reference to this object. The constructor for GPIOInterruptEventHandler is passed the method that contains the code to be executed when the event occurs.

It is perfectly permissible to bind a single event-handler method to a number of different event generators. This is analogous to binding a single method to a button event, a menu event, and a keyboard shortcut event in Microsoft Windows Forms. Because the handler is told which CPU pin has caused the event, it is possible for the handler to respond appropriately.

It is also permissible to bind multiple event handlers to a single event source. If you do this, the handler methods are called in sequence, in the order in which they were bound to the event. Note that this means the first handler must complete before the second can be called, and so on down the chain.

Finally, the handler supports a -= operator that can be used to remove delegates from the event.




Embedded Programming with the Microsoft .Net Micro Framework
Embedded Programming with the Microsoft .NET Micro Framework
ISBN: 0735623651
EAN: 2147483647
Year: 2007
Pages: 118

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net