65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 .NET Micro Framework 升级您的汽车

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.99/5 (73投票s)

2013 年 9 月 22 日

LGPL3

7分钟阅读

viewsIcon

117455

downloadIcon

2661

为 .NET 开发者泄漏我们物理世界的数字信息

泄漏我们物理世界的数字信息,为 .NET 开发者 

要求:.NET MicroFramework SDK + Gadgeteer 包,请参阅 GHI 帮助页面获取链接。

介绍  

说实话……我考驾照失败了。我没有车,也不喜欢车……
但当我很久以前买的 Fez Spider 在角落里积灰时,我认识的一位 IT 奇才 Robin Martin 对用它做些有用的东西产生了兴趣。

Robin 不喜欢写代码,他是一个 100% 的 IT 人,除了他不喝咖啡只吃土豆……但他喜欢他的车,并且不介意把一些代码拼凑起来把事情做好,只要它保持简单。

他就是这么做的……50 行代码后,他自制的燃油消耗计就诞生了。

Dashboard

他拆开了汽车的仪表盘,在里面打了个洞,然后像一个粗暴的插件一样安装了他的燃油消耗计。这才是真正的黑客行为。

但话说清楚。他的黑客行为是用50 行纯粹的 C# 代码实现的,而且不需要任何电子知识

本文将首先展示如何用 LCD 显示屏实现同样的功能(10 行代码),然后紧接着展示如何改用 7 段 LED。

让我们深入了解一个鲜为人知的领域:.NET MicroFramework

.NET MicroFramework 生态系统概述

如果您对生态系统不感兴趣,只想看项目,请随意跳过这部分。

Gadgeteer

本文中的 Fez SpiderFez Cerberus 是名为 Gadgeteer 的设备系列的一部分,这是一个来自微软的开源工具包,用于构建小型电子设备。
Fez Spider 的创造者 GHI Electronics 生产各种价位的 gadgeteers
Netduino Go 也是一个功能稍弱但更便宜的选择。
如果您知道其他 gadgeteer 制造商,请在评论中提供,我会更新文章。

您可以找到大量可插入 gadgeteers 的模块……甚至还有一个打印机

Netduino

如果您喜欢在电子层面进行黑客操作,那么经典的 netduino 可能适合您。(正如您将在本文中看到的,您也可以在 Gadgeteer 上做到这一点)
对于大约 30 美元来说,它提供了无限的乐趣,您可以找到很多关于它的社区内容,因为您可以玩转与 Arduino 兼容的 shields……一个已经为爱好者熟知且流行的微控制器。

不过要小心……我因为不正确地连接东西而毁了很多 netduino……因为我从未在学校学过真正的电子学。实际上,我是在毁掉我的 netduino 的过程中学会电子学的。

空间是有限的,您的代码需要适合大约 200KB 的空间,具体取决于您选择的板。

Secret labs,netduino 的创造者及其社区非常棒,他们会在 论坛 中非常快速地回复问题,并发布很多有趣的内容。

硬件和软件要求

对于软件部分,GHI Electronics 上的帮助页面可以帮助您入门,但我还是在这里重复一下,所有东西都是免费的

  • Visual studio 2010/2012 express 或更高版本
  • .NET Microframework SDK(在 Visual Studio 中设置项目模板和 Micro framework 库)
  • Gadgeteer 包(适用于 Gadgeteers 的附加库和项目模板)

对于硬件部分,本文分为两部分:一部分使用 LCD 显示屏显示燃油消耗计,第二部分使用 7 段显示屏。

使用 LCD 显示屏

当您创建一个 Gadgeteer 项目时,它没有任何花哨的东西……只有一个普通的项目文件,没有我们习惯的那些杂乱的代码。

Project

有趣的部分是 Program.gadgeteer,它能帮助您将模块插入正确的插槽。

UnPlugged

在这里您可以看到我的 OBD II 模块只能插入插槽 4、8、9、11。
事实上,在每个插槽上您都能看到一个字母。

image

并且在每个模块上也是同样的字母。

image

这意味着 obd II 可以插入任何带有字母 U K 的插槽……其中也包括插槽 11。
然后您可以以同样的方式插入显示屏。

Plugged

有一个用于 R、G、B 颜色的插头,最后一个是 T,用于触摸。
但我们不在此项目中使用屏幕的触摸功能,所以您不必连接它。

在代码背后,您可以发现生成的代码精确地反映了我们在设计器中的连接方式。

 

private void InitializeModules() {
    this.obd_II = new GTM.GHIElectronics.OBD_II(11);
    this.display_T35 = new GTM.GHIElectronics.Display_T35(14, 13, 12, Socket.Unused);
}

 

OBD_II 类提供了关于您汽车的信息。

image

将其连接到 LCD 显示屏就像编写 WPF 代码一样!真的,我没开玩笑。

 

void ProgramStarted()
{
    obd_II.Connect(Elm327.Core.ElmDriver.ElmObdProtocolType.Automatic, Elm327.Core.ElmDriver.ElmMeasuringUnitType.Metric);
    var panel = new Panel();
    display_T35.WPFWindow.Child = panel;
    display_T35.WPFWindow.Background = new SolidColorBrush(Colors.Black);
    var txtBlock = new Text();
    txtBlock.ForeColor = Color.White;
    txtBlock.Font = Resources.GetFont(Resources.FontResources.NinaB);
    txtBlock.HorizontalAlignment = HorizontalAlignment.Center;
    txtBlock.VerticalAlignment = VerticalAlignment.Center;
    panel.Children.Add(txtBlock);
    txtBlock.TextContent = "80.4 L/100Km";
    do
    {
        double speed = obd_II.GetVehicleSpeed();
        if(speed < 5)
        {
            txtBlock.TextContent = "Too slow to know";
            continue;
        }
        else
        {
            double distPerGallon = obd_II.elm.ObdMode01.EstimatedDistancePerGallon;
            double literPer100km = 378 / distPerGallon;
            txtBlock.TextContent = literPer100km.ToString() + " L/100km";
        }
    } while(true);
}

 

有些人制作了用于用 XAML 编写显示屏代码的工具。
无论如何,本项目不需要 Xaml,我们得到的是

image

这就是您需要了解的所有内容……现在您只需要将 OBD II 模块连接到您的汽车,然后启动。

Robin 还制作了一个真正的仪表盘,不幸的是他的代码被 CodeProject 图表标记为“有害人类”……您知道 IT 人员会写的那种样板代码……他通过使用display_T35.SimpleGraphics.SetPixel(color,x,y); 而不是 WPF 来绘制整个界面。

相信我,您不想知道它看起来是什么样子。

BadCode

尽管如此,我还是偷偷地将他的源代码附在了本文中,不要告诉 CodeProject 的管理员我污染了他们的服务器!但结果看起来很棒。

image

成本是

总计:275 美元

从 LCD 显示屏到 7 段 LED

image

事情进展顺利,但问题是 LCD 显示屏太大,无法安装到仪表盘中,而且仪表盘成本很高。

在这里,我们将替换显示模块,改用 7 段 LED,这样我们就可以使用插槽更少的 Fez Cerberus 而不是 Fez Spider,因此成本将是

总计:140 美元(比使用显示屏便宜近 2 倍)

Robin 的代码会稍微复杂一些,并且我们需要手动将 LED 连接到 MaxO 模块。

那么,一个 7 段 LED 是如何工作的呢?

image

作为开发者,您需要知道的是,我们有 7 个段 + 1 个小数点可以打开或关闭。

每个 LED 有一个引脚,还有 2 个连接到地的引脚。

我们如何将 3 个这样的 7 段 LED 连接到 gadgeteer?我们使用一个 MaxO 模块

MaxO 模块本质上是一个适配器,它将一个 gadgeteer 插槽 S 转换为 32 个开关。

image

MaxO 模块可以输出 32 个开关,这意味着您可以用 4 个字节(4 字节 = 32 位)完全描述其状态。

image

您可以将 MaxO 模块串联起来,在一个 Socket S 上实现 128 个开关。
在我们的例子中,我们只需要一个 MaxO,因为每个 7 段 LED 需要 8 个开关,即 3 个 7 段 LED 需要 24 个开关(引脚)。

imageimage

一旦理解了这一点,代码就变得直观了,条件块根据消耗水平将小数点放在正确的位置。(例如,“02.5”表示低于 10 L/100km,“12.5”表示高于 10 且低于 100,“123”表示高于 100)

 

void ProgramStarted()
{
    Debug.Print("Program Started");
    maxO.NumBoards = 1;
    maxO.EnableOutputs();
    byte[] nodata = { 255, Digitcode((char)'-'), Digitcode((char)'-'), Digitcode((char)'-') };
    maxO.WriteArray(nodata);
    obd_II.Connect(Elm327.Core.ElmDriver.ElmObdProtocolType.Automatic, Elm327.Core.ElmDriver.ElmMeasuringUnitType.Metric);
    do
    {
        double speed = obd_II.GetVehicleSpeed();
        if(speed > 5)
        {
            byte[] switches = { 255, 255, 255, 255 };
            double distPerGallon = obd_II.elm.ObdMode01.EstimatedDistancePerGallon;
            double literPer100km = 378 / distPerGallon;
            char[] digits = literPer100km.ToString().ToCharArray();
            if(literPer100km >= 100)
            {
                //Over 100, no digital point
                switches[1] = Digitcode(digits[0]);
                switches[2] = Digitcode(digits[1]);
                switches[3] = Digitcode(digits[2]);
            }
            else if(literPer100km >= 10)
            {
                //From 10 to 100, add a digital point eg : "80.4"
                switches[1] = Digitcode(digits[0]);
                switches[2] = PointCode(Digitcode(digits[1]));
                switches[3] = Digitcode(digits[3]);
            }
            else
            {
                //Under 10, dot after the second digit eg : "02.4"
                switches[1] = Digitcode((char)'0');
                switches[2] = PointCode(Digitcode(digits[0]));
                switches[3] = Digitcode(digits[2]);
            }
            maxO.WriteArray(switches);
        }
        else
        {
            maxO.WriteArray(nodata);
        }
    } while(true);
}

 

这是将数字转换为其 7 段 LED 正确字节值的映射。

 

byte PointCode(byte code)
{
    return (byte)(code - 128);
}
byte Digitcode(char digit)
{
    switch(digit)
    {
        case (char)'0':
            return 132;
        case (char)'1':
            return 159;
        case (char)'2':
            return 194;
        case (char)'3':
            return 138;
        case (char)'4':
            return 153;
        case (char)'5':
            return 168;
        case (char)'6':
            return 160;
        case (char)'7':
            return 158;
        case (char)'8':
            return 128;
        case (char)'9':
            return 136;
    }
    //Else, show "-" 
    return 251;
}

 

关于这段代码就说到这里。

Robin 利用了廉价电话线中的 8 根线,将一个 7 段 LED 连接到 MaxO 模块。

image

结论

感谢 Robin Martin 发送他的项目给我,让我的 fez spider 重获新生。
感谢 MicrosoftSecret LabsGHI Electronics 赋予我的力量,以及
SparkFunMakerShedAdafruit 这些优秀的 Arduino/netduino/gadgeteer/电子元件经销商。

我希望您能一窥 .NET MF 作为一名普通开发者所拥有的强大功能。
如果您一直犹豫 gadgeteer 或 netduino 是否值得您的金钱和时间,我希望我已经说服了您。是的,它值得您的时间,社区很棒,工具很棒,模块很多,供应商和制造商配合得很好。.NET MF 是一个成功。

定价范围取决于您的需求(cerberus 30 美元,Fez Spider 120 美元),并且,正如您所见,gadgeteer 允许您在确实需要时连接到普通的电子设备。

.NET MF 即将推出一款智能手表,我迫不及待了。 笑脸

© . All rights reserved.