Leaking the digital on our physical world, for .NET developers
Requirement : .NET MicroFramework SDK + Gadgeteer Package see
GHI help page for links.
Introduction
Truth to be told… I failed my driver license. I don’t own a car, and I don’t like cars…
But while the Fez Spider I bought for a project long time ago were gathering dust, Robin Martin, an IT wizard I knew from my old days at school was interested to make something useful.
Robin does not like coding he is a real 100% IT guy except he does not drink coffee and eats only potatoes… but he likes his car, and doesn’t mind hacking some lines of code together to get things done as long as it stays simple.
That’s what he did… 50 lines of code later his home made Fuel Consumption Meter was born.
He took out the dashboard of his cars, made a hole inside and added his Fuel Consumption Meter like a vulgar plugin. That’s what I call hacking.
But let’s be clear. His hack works with 50 lines of plain old C# code, and no electronic knowledge is required.
This article will show how to do the same thing with an LCD display first (10 lines of code), then we will how to use 7-Segments leds instead right after.
Let’s dive in a field that few developers knows : .NET MicroFramework.
An overview of the .NET MicroFramework ecosystem
If you are not interested about the ecosystem, but only the project, be free to skip this part.
Gadgeteer
The Fez Spider and Fez Cerberus from this article are part of a family of device called Gadgeteer, an open source toolkit from Microsoft for building small electronics device.
The creator of Fez Spider, GHI Electronics create lots of gadgeteers at all price.
Netduino Go is also a less powerfull but cheaper alternative.
If you know other gadgeteer makers, put them in comments, I’ll update the article.
And you can find tons of modules pluggable to your gadgeteers… even a printer !
Netduino
If you like hacking at the electronic level, then, classical netduino might be for you. (You can also do that on Gadgeteer, as you will see in this article)
Unlimited fun for something like 30$, you can find lots of community stuff about it since you can play with arduino compatible shields… an already well know microcontroller for hobbyists.
Be careful though… I killed many netduino by plugging things incorrectly… because I never learned real electronics at school. Actually I learn electronic by killing my netduinos.
Space is limited, your code need to fit into something like 200ko depending on the board you choose.
Secret labs, the creator of netduino and its community is awesome, they reply to questions in the forum very quickly, and post lots of interesting stuff.
Material and software requirements
For the software part, the help page on GHI Electronics get you started, but I’ll repeat it here, all is free:
- Visual studio 2010/2012 express or better
- .NET Microframework SDK (set project templates in Visual Studio and Micro framework libraries)
- Gadgeteer package (Additional libraries and project templates specific to Gadgeteers)
For the hardware part, this article is divided into two parts, one part is using LCD display to show the fuel consumption meter, the second part use 7-Segment display:
Using LCD display
When you create a Gadgeteer project, you have nothing fancy… just a plain old project file without the mess we’re accustomed to.
The interesting part is the Program.gadgeteer that help you to plug your modules in the right slot.
Here you can see that my OBD II module can only plug in slot 4,8,9,11.
In fact on each slot you can see a letter.
And on each module the same letters.
This means that obd II can plug on any slot which holds the letter U or K… which include slot 11.
Then you can plug the display the same way.
There is one plug for R, one for G and one for B colors, the last one is T, for Touch.
But we don’t use the Touch feature of the screen for this project so you don’t have to plug it.
In the code behind, you can see that the generated code reflects exactly how we plugged things in the designer.
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);
}
The OBD_II class comes with information about your car.
Plugging it to your LCD display is about coding in WPF ! Really, not kidding.
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);
}
Some people made tools for coding your display in XAML.
Anyway, we don’t need Xaml for this project, here is what we get :
This is all there is to know… now you just have to plug the OBD II module to your car, and drive.
Robin also made a real dash meter, unfortunately his code is censured by the CodeProject chart as “Harmful to the humanity”… you know the kind of boilerplate code an IT guy can make… he drew the whole interface by using display_T35.SimpleGraphics.SetPixel(color,x,y); instead of WPF.
Believe me, you don’t want to know how it looks like.
Nevertheless I secretly attached his source to this article, don’t tell to CodeProject admins I polluted their servers ! But the result looked great.
The cost is :
Total : 275$
From LCD display to 7-Segment Leds
Things worked well, but the problem is that the LCD display is too big to be plugged into the dashboard, and that the meter cost is high.
Here, we will replace the Display module to use 7-segments leds instead, by doing that we can use a Fez Cerberus -less slots- instead of Fez Spider, so the cost will be :
Total : 140$ (or almost 2 times less than with the display)
Robin’s code will be a little more complicated, and we will need to plug the leds to the MaxO module manually.
So first how does one 7-Segment works ?
As a developer, the only thing you need to know is that we have 7 segments + 1 digital point to switch on or switch off.
There is one pin per led and 2 pins to connect to the ground.
How do we connect 3 of these 7-segments leds to the gadgeteer ? We use a MaxO module.
The MaxO module is nothing more than an adapter which convert a gadgeteer slot S into 32 switches.
MaxO module can output 32 switches, this mean that you can completely describe its state with 4 bytes. (4 bytes = 32 binary digit)
You can chain MaxO modules to reach 128 switches on one Socket S.
In our case, we need only one MaxO because each 7-Segment led requires 8 switches, that is 24 switches (pins) for the 3 7-Segments.
Once understood, the code is straightforward, the conditional blocks put the decimal separator at the right place depending on the consumption level. (eg : “02.5” for less than 10 L/100km, “12.5” for more than 10 and “123” for more than 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)
{
switches[1] = Digitcode(digits[0]);
switches[2] = Digitcode(digits[1]);
switches[3] = Digitcode(digits[2]);
}
else if(literPer100km >= 10)
{
switches[1] = Digitcode(digits[0]);
switches[2] = PointCode(Digitcode(digits[1]));
switches[3] = Digitcode(digits[3]);
}
else
{
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);
}
And here is the mapping for converting a digit to the correct byte value of its 7-Segment 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;
}
return 251;
}
That’s all there is to say about this code.
Robin took advantage of the 8 wires there is inside a cheap phone cable to connect a 7-Segment to the MaxO module.
Conclusion
Thanks to Robin Martin for sending me his project, and giving a second life to my fez spider.
Thanks to Microsoft, Secret Labs, and GHI Electronics for giving me power and to
SparkFun, MakerShed and Adafruit excellent distributors of arduino/netduino/gadgeteer/electronic components.
I hope you got a glimpse of the power .NET MF give you, as a modest developer.
If you always asked if a gadgeteer or netduino were worth your money and time, I hope I convinced you. YES it is worth your time, the community is great, the tool are great, modules are plentiful, vendors and makers align well together. .NET MF is a success.
The pricing range depends on your need (30$ for cerberus, 120$ for Fez Spider), and, as you have seen, gadgeteer allows you to plug to normal electronic devices if you really need to.
.NET MF is also moving to a smart watch soon, can’t wait for that.