Developing for the .NET Micro Framework
An SDK that you can install on top of Visual Studio has been provided. You can use Visual Studio 2005 or later to develop for the .NET Micro Framework. The SDK includes project templates using Visual C# that you can begin using immediately. In fact, if you use one of the built-in project types, you quickly can build and deploy a sample embedded application. An emulator is provided, so you don't even need a physical device to try it. You can download the SDK.
Once installed, you'll be able to begin developing applications that target ARM-based processors and devices. The best way to see what the SDK does is to jump into a sample application. You can immediately start building an application targeting the included emulator.
Building a .NET Micro Framework Application
After installing the .NET Micro Framework, you will find a new Project Type listed under Visual C#. This is the Micro Framework type shown in Figure 3. You'll see several new templates added within this project type should you select it.
[Framework3.JPG]
Figure 3: New Visual Studio Project types.
To create a sample application, select the Console Application project template within the Micro Framework project types. You then can provide a project Name in the same manner that you do for any other C# project. For my sample code, I use MF_App1. Select OK to create the project in Visual Studio.
If you then open the Program.cs file that was created, you'll see the code in Listing 1 in the editor:
Listing 1: Default Embedded Application
using System;
using Microsoft.SPOT;
namespace MF_App1
{
public class Program
{
public static void Main()
{
Debug.Print(
Resources.GetString(Resources.StringResources.String1));
}
}
}
If you click build and run the application (or simply press F5), you should have a successful build, the emulator as shown in Figure 4 should be displayed, and then the program will end. Because your program doesn't do anything more than display a debug message, the program quickly ends and the emulator shuts down. If you want to see the emulator, you can put a break point on the debug line and run the program again.
[Framework4.JPG]
Figure 4: The emulator for a program that does nothing.
A program that does nothing is really not a good illustration. To build a more robust application, you are likely to want to use some of the libraries available. Right-click on your project's name in the Solution Explorer and select the Add References option. Make sure the following libraries are included:
- Microsoft.SPOT.graphics
- Microsoft.SPOT.Hardware
- Microsoft.SPOT.Native
- Microsoft.SPOT.Net
- Microsoft.SPOT.TinyCore
- mscorlib
- System
Once these references are included, you can begin to build an application that does more.
First, you will want to modify the main() routine that you have in Listing 1. You'll drop the Debug.Print() line and instead do the following:
ButtonWatcher watcher = new ButtonWatcher();
watcher.Run();
Of course, if you are going to call the ButtonWatcher class, you need to add it. You can do this by adding a new class called ButtonWatcher to the project (select Project --> Add New Item --> Class) and then modifying its code to what is in Listing 2.
Listing 2: An Application using buttons on an Embedded Device.
using System;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
namespace MF_App1
{
enum Button
{
None = -1,
Left = Cpu.Pin.GPIO_Pin0,
Right = Cpu.Pin.GPIO_Pin1,
Up = Cpu.Pin.GPIO_Pin2,
Select = Cpu.Pin.GPIO_Pin3,
Down = Cpu.Pin.GPIO_Pin4
}
class ButtonWatcher
{
public void Run()
{
InputPort up = new InputPort((Cpu.Pin)Button.Up,
false, Port.ResistorMode.PullUp);
InputPort down = new InputPort((Cpu.Pin)Button.Down,
false, Port.ResistorMode.PullUp);
InputPort left = new InputPort((Cpu.Pin)Button.Left,
false, Port.ResistorMode.PullUp);
InputPort right = new InputPort((Cpu.Pin)Button.Right,
false, Port.ResistorMode.PullUp);
InputPort select = new InputPort((Cpu.Pin)Button.Select,
false, Port.ResistorMode.PullUp);
Button lastButton = Button.None;
Button currentButton = Button.None;
while (true)
{
if (!up.Read())
currentButton = Button.Up;
else if (!down.Read())
currentButton = Button.Down;
else if (!left.Read())
currentButton = Button.Left;
else if (!right.Read())
currentButton = Button.Right;
else if (!select.Read())
currentButton = Button.Select;
else
currentButton = Button.None;
if (lastButton != currentButton )
{
switch (currentButton)
{
case Button.Left:
Debug.Print("Left");
break;
case Button.Right:
Debug.Print("Right");
break;
case Button.Up:
Debug.Print("Up");
break;
case Button.Down:
Debug.Print("Down");
break;
case Button.Select:
Debug.Print("Select");
break;
}
lastButton = currentButton;
}
System.Threading.Thread.Sleep(15);
}
}
}
}
This focus of the ButtonWatcher class is to watch the buttons on the embedded device. In Figure 4, you saw that the emulator had five buttons. These can be set up as directional buttons (right, left, up, and down) and a selection button in the center.
In Listing 2, you see that these buttons can be queried by using pin numbers. Rather than using cryptic calls such as Cpu.Pin.GPIO_Pin0 for the buttons, an enumerator called Button is created and the values from the pins are assigned to more intuitive names such as left, right, up, down, and select. This lets you use Button.Left instead of Cpu.Pin.GPIO_Pin0. Of course, you don't have to do this; however, if you do, the rest of your code will be much easier to read!
When the ButtonWatcher's Run method is executed, a number of variables are created; they can be used to watch the buttons. Each is created as an InputPort that is assigned to a given button. These assignments then will let the program do a simple Read() to see whether the button has been clicked. In fact, after setting up the InputPorts and a couple of tracking variables, the program is put into an infinite loop that simply checks each of the InputPort variables to see whether the corresponding button has been clicked. If so, the current button is set to the button that is read. As long as the button is held down, the value of currentButton will be the same as lastButton. Once the button is unselected, all of the reads will be false and therefore the currentButton will be set to None, thus allowing a button to be clicked again or a new button to be selected.
The main purpose of the program is to print out debug messages based on the button that is pressed. If the last button read is not the same as the current one, a debugging message is displayed in Visual Studio's Output window as shown in Figure 5. Instead of doing the debugging message, you could have created programming logic that performed an action when these buttons were pressed.
[Framework5.JPG]
Figure 5: The ButtonWatcher program in action.
It is important to point out that the reason you set the lastButton to the currentButton is to prevent a slew of debug messages to be printed. If you didn't do this, you would get multiple debug messages if you were to hold the button down longer than the Thread sleep value. Granted, the program does a Thread.Sleep() call to slow things down.
You might also be thinking that putting a program into an infinite loop is bad programming practice. If you are creating an embedded application, chances are the program you are creating is all that the device does. As such, when the device is on, the program should be running. A person wouldn't necessarily 'exit' an embedded application.
Comments
There are no comments yet. Be the first to comment!