.NET Micro Framework:細說軟件人的硬件
毫無疑問,我是一個軟件人。在學校,我學習了電氣工程專業的相關課程,然后我學習了LED課程,再然后,像其他人一樣,我學習了小型計算機,我知道了大多數零件的“伏特”和“安培”,但是,我的硬件知識也就到此為止了。我的硬件技能的上限也就是在某處添加一個LED和一些電阻來關閉USB適配器。
我對像Clint Rutkas那樣的硬件愛好者心生敬畏,我的意思是他只是基于個人的興趣,就從零開始制作了一個T-shirt炮,真的很令人吃驚。今天,Clint郵寄給我一塊“Netduino”板(具體可以參考:http://netduino.com/)。除了使用.NET Micro Framework以外,它幾乎和“Arduino”板一樣。你說“Micro”嗎?它是“tiny ass(Analog imulation System:模擬仿真系統) framework”的技術術語。
2004年我制作了一份SPOT表。它使用的是Smart Personal Objects Technology,這是“tiny ass(Analog imulation System:模擬仿真系統) framework”的營銷術語。這個表已經使用6年了(它一直運行的很好,實際上,現在它正放在我的書桌上),它使用的是.NET。
讓我們回到現在,我發現我自己正在把這塊“Netduino ”板插到我的計算機上,通過Pete的Hello World教程(關于這個教程,具體可以參考如下頁面:http://10rem.net/blog/2010/09/02/first-experiences-with-netduino-and-the-net-micro-framework),我看到了這些命名空間:
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
一切又回來了!
OK,把它們一起放到上下文環境中。“Netduino”是一塊基本上和“Arduino”兼容的板,而且,它還提供了一張電路圖(“Netduino”電路圖的PDF版本,可以參考如下頁面:http://www.netduino.com/netduino/schematic.pdf),所以,如果你有興趣的話,也可以自己制作一個這樣的板。.NET Micro Framework(一些人也叫他TinyCLR)只是字面上的叫法而已——實際上它是運行.NET字節碼的一個微型的CLR(Common Language Runtime:公共語言運行時)。你可以編寫C#代碼,然后使用很小的內存(比如64K)在微型的CPU上運行這些代碼。它已經存在相當長的一段時間了,圍繞它已經建立起了一個強大的社區。
.NET Micro Framework 4.1的源代碼可以從如下頁面下載:http://www.microsoft.com/downloads/en/details.aspx?FamilyID=CCDD5EAC-04B1-4ECB-BAD9-3AC78FB0452B&displaylang=en,它是開源的(開源許可證是:Apache 2.0 License)。(新的微軟簡直令我激動萬分,居然有這么多的代碼悄悄地通過開源許可證來公開。)詳細情況可以參考Pete的blog(關于Pete的Blog,具體可以參考如下頁面:http://10rem.net/blog/2010/09/02/first-experiences-with-netduino-and-the-net-micro-framework)。
這是“Netduino”板的外觀:
我正在思考一些硬件方面的創意——我可以用它來制作些什么呢?我獲得了更多的功能和傳說中的Tahoe II(帶有觸摸屏,加速計,按鈕等等)(關于Tahoe II,具體可以參考:http://devicesolutions.net/Products/TahoeII.aspx)。如果你對快速構建原型或使用現成的板構建一個完整的系統感興趣,請不要錯過它!這是Tahoe II的外觀。記住,所有這些板都是使用C#和.NET的。使用我過去熟悉的語言和框架來為硬件編寫程序是多么令人嘆為觀止啊!毫不夸張地說,在學習曲線方面,它讓我節省了80%的時間和精力。
這是GHI Electronics EMX Development system,我們可以有很多的選擇。
要使用這些板(和其他類似的板),你只需要Micro Framework 4.1和針對特定的板的SDK就可以了。它已經集成到了Visual Studio 2010中。如果你想對這個產品做出改進,他們正在.NETMF論壇中征集各種建議:http://www.netmf.com/Discussion/Forums/SingleForum.aspx?mode=singleForum&forum=5d5ba383-e09d-470c-af8b-988cbf828630。
入門:
你需要的東西:
Netduino板(Scott:或其他.NET Micro Framework板)
USB線(早期的Netduino單元帶有USB線)(Scott:通常是一個微型的或模擬的USB)
Visual Studio 2010和.NET Micro Framework 4.1 SDK(可以從如下頁面下載:http://blogs.msdn.com/b/netmfteam/archive/2010/07/19/netmf-versions-4-1-released-to-web.aspx)(如果你沒有Visual Studio,你可以使用C# Express 2010)
32位的Netduino SDK或64位的Netduino SDK,這主要取決于你的主機操作系統是32位的還是64位的。
可選:在netduino版上,shields和starter kits(具體可以參考如下頁面:http://www.makershed.com/SearchResults.asp?Cat=43)可以做很多很“酷”的事情。它和現有的Arduino shields是兼容的。一個shield只是一個附加的“卡”,它和板上的引腳是匹配的。
為了和Netduino進行交互,這個SDK會安裝一個設備驅動。你一定要選擇和你的主機操作系統相匹配的位數(64位/32位),并且你一定要在Netduino連接到PC以前安裝它。在安裝這個SDK以前,我已經安裝了Visual Studio 2010,但是這并不是很重要。
如果你使用USB線插入了Netduino,你應該可以看到這個設備的驅動已經安裝好了,同時,這個板上的電源指示燈也應該被點亮了。
使用Morse Code的Hello World
現在,我只有一塊Netduino板,我并沒有得到其他的任何附件。如果我是一個硬件愛好者,我相信我會嘗試著拆開一個烤面包機,來實現遠程控制,并且我會清楚這樣一些事情(比如:在引腳輸出***的情況下,這個烤面包機只需要1歐姆的電阻,所以我可以反轉電壓,然后我就可以通過藍牙來烤面包了),但是,我不知道這些事情。我能用Netduino做的所有事情就是讓它的LED燈不停地閃爍,就像Pete指出的那樣:
public static void Main()
{
OutputPort onboardLed = new OutputPort(Pins.ONBOARD_LED, false);
while (true)
{
onboardLed.Write(true);
Thread.Sleep(500);
onboardLed.Write(false);
Thread.Sleep(500);
}
}
讓我們把它變得更新奇一點。使用Morse Code來輸出字符串怎么樣?維基上說一個點是100ms長,一個短劃線是300ms長。這很難做到嗎?
我參考了StackOverflow站點上的實現,因為他們進行了一項比賽,比賽的內容是看看誰能編寫出體積最小的程序,程序的功能很簡單,就是獲取一個字符串,然后輸出Morse Code。他們有一個極端優化的解決方案(相對于代碼行數而言)。我也可以使用了一個Hashtable,但是兩個平行的數組會更好一些。.NET Micro Framework,是“微型”的,所以它并沒有提供完整的框架所提供的所有功能。但是它是開源的,它已經采用了一些社區的貢獻,4.1版本已經包含了一個Hashtable的實現。我甚至可以直接調試連接的那塊板!
這是我那“可悲的”小程序(它十分簡單!)
using System;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using SecretLabs.NETMF.Hardware;
using SecretLabs.NETMF.Hardware.Netduino;
using System.Text;
using System.Collections;
namespace NetduinoApplication1
{
public class Program
{
public static void Main()
{
OutputPort onboardLed = new OutputPort(Pins.ONBOARD_LED, false);
while (true)
{
onboardLed.Write(false);
foreach (char c in " hello scott hanselman ")
{
string morse = ConvertTextToMorse(c);
Debug.Print(c + " = " + morse);
TransmitDotOrDash(onboardLed, morse);
}
}
}
private static Char[] Letters = new Char[] {'a', 'b', 'c', 'd', 'e', 'f', 'g',
'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u',
'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8',
'9', ' '};
private static String[] MorseCode = new String[] {".-", "-...", "-.-.",
"-..", ".", "..-.", "--.", "....", "..", ".---", "-.-", ".-..",
"--", "-.", "---", ".--.", "--.-", ".-.", "...", "-", "..-",
"...-", ".--", "-..-", "-.--", "--..", "-----", ".----", "..---",
"...--", "....-", ".....", "-....", "--...", "---..", "----.", " "};
public static String ConvertTextToMorse(char c)
{
int index = -1;
index = Array.IndexOf(Letters, c);
if (index != -1)
return MorseCode[index];
return string.Empty;
}
public static void TransmitDotOrDash(OutputPort port, string dotordash)
{
foreach (char c in dotordash)
{
TransmitDotOrDash(port, c);
}
Thread.Sleep(300); //gap between letters
}
public static void TransmitDotOrDash(OutputPort port, char dotordash)
{
if (dotordash == ' ')
{
port.Write(false);
Thread.Sleep(700); //gap between words
}
else //it's something
{
port.Write(true);
if (dotordash == '.')
Thread.Sleep(100); //dot
else
Thread.Sleep(300); //dash
port.Write(false);
}
}
}
}
當我在這塊板上閃爍“hello scott hanselman”時候,這是調試輸出:
沒有什么比這更容易的了。下次,我將會在Tahoe II上做一些工作,也許我會給男孩子們制作一個游戲。也許我會連接一個揚聲器和一個近距離的傳感器,然后看看它們是否可以在上面工作。