Temperature Monitoring using VB.Net, Micro-framework and a Netduino

VBTeam


 

Introduction

As a bit of a geek, I like to tinker with basic gadgets. I often think of little ideas that would be great to implement but the device involves some hardware and very little software. As a software engineer I tend to think in terms of simple programs to but in order to implement something tangible would involve electronics and the interface between embedded electronics and high level languages such as VB or C# is somewhat disconnected. For a long time much of the embedded devices was coded using low level languages such as assembler and the prospect of going back to write assembler or getting into more complex electronics is something that I just don’t have the time to devote to it.

That’s when I saw this little device called the Netduino which runs something called the .NET Micro-framework. This seems just what I’ve been looking for. A microcontroller device that I can put together a few electronics items which are available off-the-shelf and write some .NET code in my language of choice (VB) to implement some basic functionality.

So the next question is what did I think would be a good first project?

My wife is studying to be a sommelier which means we have quite a few bottles of wine in the house. Sometimes we open one up an it’s developed a fault. Now there are numerous reasons for wines developing faults but incorrect storage is one possible cause. Wine is very temperamental and is best stored in a cool dark climate that doesn’t change much through the seasons which is why cellars or caves are great for storage but unfortunately in normal modern houses a cave or wine cellar is not a standard item. So we use our pantry to store our wine.

With this in mind I wanted to be able to know if the pantry conditions were really fluctuating that much. So I had my project but where to start? A simple device to monitor the wine cellar (eer pantry!!!) and provide warning indications of hi or low temperature conditions.

Well the first thing was to look around and find the parts I would need – a Netduino Plus device was chosen because it has networking capabilities built in which I would use later. A prototyping shield and a few electronic components such as temperature and humidity sensor and some LED’s to indicate status.

The Netduino hardware is a micro-controller running a very small version cut down version of the .NET framework called the Micro-Framework. This enables .NET developers to write their application code using C# and recently added VB.NET. Allowing you to write you application as high level code dealing with the problem rather than having to resort to using low level assembler to control the hardware. There are some things that a not implemented with Generics / Late Binding being the obvious two but the code is clearly VB.NET / C# and you use Visual Studio as a development tool.

The device is made in such a way that you can plug in shields. Shields are really circuit boards that conform to a specific physical layout. These shields contain all the necessary circuitry to do a specific tasks such as SD Card reader/writer, Wi-Fi networking or can be a blank one which allows you to create your own circuitry either by soldering up components or by using a prototyping breadboard.

So after a little research located the parts I need would need and the basic circuitry to do get the sensors and LED’s connected. It’s easy enough to find this information with vendors such as Sparkfun, MakerShed, Adafruit all having lots of useful information as well as the Netduino website community forums having lots of information on sensors used by people and code snippets.

With all this in hand I constructed a basic shield – very simple for anyone that has done any basic soldering. If you can’t, it’s real easy to learn. With Netduino and prototyping shield in hand I launched Visual Studio to write some code to make my monitoring device come to life.

The applicable needs to do a number of tasks

  • · Read the sensors
  • · Write the data to the SD Card
  • · Detect any temperature warning conditions.
  • · Provide visual indications of working and warning conditions
  • · Provide a reset capability

My approach was to take each task and build an evolving system. So the first thing was to wire up the sensor and the LED’s. Using a breadboard makes it real easy and is really a case of plugging wires in to make the connections.

The design looked like the following. It looks a bit crazy when prototyping but I’ll eventually clean this up before putting the item in the pantry and having a worried wife come tell me there is a mysterious device with wires coming out of it in the pantry.

 

Connections

(Some of these may be not requiring connections because they are implemented as part of the prototyping shield. Examples of this are my reset button and heartbeat and reset LED’s which only required the Dx output. The ground wires were already implemented as part of the shield.)

 

Item

Connection

TMP36 Sensor

 

3.3v and ARef (if using a RevA board)

 

A0

 

Ground

   

Hi Warning LED

 

D9

 

Ground

   

Low Warning LED

 

D11

 

Ground

   

Heartbeat LED

 

D13

 

Ground

Button

 

D8

 

Ground

Reset LED

 

D12

 

Ground

Now to make it work and write some code.

The micro framework is really a lightweight version optimized for embedded device development. VB support is a recent addition and required the 4.2 version of the micro framework to be installed along with the firmware update to the Netduino. Updating the firmware to 4.2 was a breeze.

So let’s break development into a few simple tasks one at a time. Each task I’ll show code snippets but the entire finished source is available to download.

 

Reading the sensor

The code for this application is a simple Console application which is running indefinitely. As I’m powering the final device by means of a 9v battery I want to do enough to get the job done but want to make sure that I have sufficient battery life. So I will be taking a reading every 10 minutes which means that most of the time the device is really asleep.

There are both analogue and digital temperature sensors. Mine original sensor is a simple thermistor (Temperature dependent resistor) which means that the resistance varies with temperature changes. Using the Analogue input ports on the Netduino in conjunction with this allows me to determine a temperature. There are two revisions of the Netduino (Rev A and Rev B). The significant difference between the two is related to Analogue references and the need to provide an extra link between the 3.3v pin and the Aref0 pin – without this the values read on the Analogue port will be inconsistent. Luckily almost all boards out there are Rev B boards with this already internally connected on the board preventing you from having to remember this.

The formula for calculating a temperature is as follows….

This code will create a timer which raises an event every x seconds and takes a temperature reading. As there are some minor variations in reading a single instantaneous value, my approach was to take a number of readings over a short period of time and average them out. This should flatten any rogue values that occurred. When debugging this I set a shorter period to ensure that I could see this process working.

I’d also included debug values to be able to monitor the temperature value it was reading. These can be conditional compiled out in final release version. The values seemed a little high on this sensor so I located a second sensor and installed this and measured the temperature reading on this and was able to adjust the first. This may have been possible by adding a resistor in the circuit for the original sensor but I was able to experiment using and offset value in code to calibrate this and it seemed accurate enough.

Imports Microsoft.SPOT
Imports Microsoft.SPOT.Hardware
Imports SecretLabs.NETMF.Hardware
Imports SecretLabs.NETMF.Hardware.Netduino
Public Module Module1
    Dim PollingDelay As Integer = 2
    Dim tempSensor As New AnalogInput(Pins.GPIO_PIN_A5)
    Dim CurrentTemperature As Double = 0
    Public Sub Main()
        Dim Temperature As Double = 0
        '//Setup Event Handlers
        PollingTemperatureMethod()
        '//Get the initial temperature
        CurrentTemperature = GetAverageTemperatureReading()
        While True
            Thread.Sleep(Timeout.Infinite)
        End While
    End Sub
   Function GetCurrentTemperature() As Double
        ''Read the raw sensor value
        Return tempSensor.Read()
    End Function
    'Get the average temperature of 101 readings over a second
    Function GetAverageTemperatureReading() As Double
        Dim totalTemp As Double
        Dim averagetemp As Double = 0
        For i = 0 To 99
            totalTemp += GetCurrentTemperature()
            Thread.Sleep(10)
        Next
        averagetemp = totalTemp / 100
        Dim Kelvin As Double = (((averagetemp / 1023) * 3.3) * 100)
        Dim Celsius As Double = (Kelvin - 273) - 17.8
        Dim Fahrenheit = (Celsius) * (9 / 5) + 32
        Debug.Print(WarningStatus.ToString & " " & averagetemp.ToString() & " " & Fahrenheit.ToString & " / " & Celsius.ToString & " ")
        Return Celsius
    End Function
    Private PollingTimer As Timer
    Private Sub PollingTemperatureMethod()
        Dim PollingDelegate As New TimerCallback(AddressOf PollForTemperature)
        PollingTimer = New Timer(PollingDelegate, Nothing, 1000, PollingDelay * 1000)
    End Sub
    Public Sub PollForTemperature(stateInfo As Object)
        Module1.CurrentTemperature = GetAverageTemperatureReading()
    End Sub
End Module

Writing the SD Card

There are a few differences between the Netduino and the Netduino Plus. I’d chosen the Plus version because it comes with a micro SD card slot on the board – so no new hardware are required to log these values for reviewing later. Searching in the Netduino forums reveals many examples of code available to write to SD Cards. The micro-framework includes some IO file support but is not the file support that you might expect from the full desktop .NET Framework. The task I want to achieve is to append the new sensor readings to the end of a file containing the existing readings and using the full framework I’d simply be using the System.IO.File class but this doesn’t exist on Micro-framework and so I had to create my own helper function which uses a Streamwriter, I guess once I’ve done this once I can reuse it over again.

Added to PollForTemperature Method

 

        Dim Str As String = "SensorData: 1," & Module1.CurrentTemperature.ToString & "2," & Module1.CurrentTemperature2.ToString
        AppendToFile("\SD\Temperature.dat", Str)
#Region "Writing Data to SD Card"
    Private Function VolumeExist() As Boolean
        Dim volumes As VolumeInfo() = VolumeInfo.GetVolumes()
        For Each volumeInfo__1 As VolumeInfo In volumes
            If volumeInfo__1.Name.Equals("SD") Then
                Return True
            End If
        Next
        Return False
    End Function
    ' Append to a file / Create the file if it doesn't exist
    Private Sub AppendToFile(filename As String, string1 As String)
        If Not VolumeExist() Then
            Return
        End If
        Try
            Dim fs As FileStream = If(File.Exists(filename), New FileStream(filename, FileMode.Append), New FileStream(filename, FileMode.Create))
            Dim streamWriter As New StreamWriter(fs)
            streamWriter.WriteLine(string1.ToString)
            streamWriter.Flush()
            streamWriter.Close()
            fs.Close()
        Catch generatedExceptionName As Exception
        End Try
    End Sub
#End Region

Detecting Warning Conditions

I wanted my code to be able to detect hot and cold warning conditions as both of these can cause problems with wine storage. During development I wanted a much narrower temperature range allowing me to trigger it easily but chose to read these settings into the application from a file on the SD Card to make it flexible. Allowing me modify the settings without having to redeploy the application. Once I have these Maximum and Minimum values I can then use these to determine if the sensor reading is a Warning Condition and if this has occurred turn on one of the two warning LED to provide a clear indication that we have had an temperature event occur.

Dim HiWarningLED As New OutputPort(Pins.GPIO_PIN_D9, False)
Dim LowWarningLED As New OutputPort(Pins.GPIO_PIN_D11, False)
Public Enum LevelCheck
    LowTemp
    HiTemp
End Enum
    Dim LowWarningStatus As Boolean = False
    Dim WarningStatus As Boolean = False
    Dim MinTemp As Single = 20
    Dim MaxTemp As Single = 26
    Function CheckTemperatureForWarning(Temp As Double, Optional Level As LevelCheck = LevelCheck.HiTemp) As Boolean
        Dim WarnStateOccured As Boolean = False
        If Level = LevelCheck.LowTemp Then
            'Is Temperature Exceeding MaxTemp
            If Temp <= MinTemp Then
                Debug.Print("Low Warning Triggered")
                Debug.Print("Temp: " & Temp.ToString)
                Debug.Print("maxTemp: " & MaxTemp.ToString)
                Debug.Print("minTemp: " & MinTemp.ToString)
                WarnStateOccured = True
            End If
        ElseIf Level = LevelCheck.HiTemp Then
            'Is Temperature Exceeding MaxTemp
            If Temp >= MaxTemp Then
                Debug.Print("Hi Warning Triggered")
                Debug.Print("Temp: " & Temp.ToString)
                Debug.Print("maxTemp: " & MaxTemp.ToString)
                Debug.Print("minTemp: " & MinTemp.ToString)
                WarnStateOccured = True
            End If
        End If
        Return WarnStateOccured
    End Function
    Sub WarningStatusLight(State As Boolean, Optional Level As LevelCheck = LevelCheck.HiTemp)
        'Code to turn on/off LED
        If Level = LevelCheck.LowTemp Then LowWarningLED.Write(State)
        If Level = LevelCheck.HiTemp Then HiWarningLED.Write(State)
    End Sub
Public Sub PollForTemperature(stateInfo As Object)
        Module1.CurrentTemperature = GetAverageTemperatureReading()
        'If the warning status light is off and a warning temperature occurs then 
        'set Warning Light State to True and don't bother checking any more as the 
        'alarm condition has been met
        If LowWarningStatus = False AndAlso CheckTemperatureForWarning(CurrentTemperature, LevelCheck.LowTemp) = True Then
            LowWarningStatus = True
            WarningStatusLight(LowWarningStatus, LevelCheck.LowTemp)
        End If
        If WarningStatus = False AndAlso CheckTemperatureForWarning(CurrentTemperature, LevelCheck.HiTemp) = True Then
            WarningStatus = True
            WarningStatusLight(WarningStatus, LevelCheck.HiTemp)
        End If
End Sub

 

Reset Button

When a temperature event has occurred I can retrieve the SD Card and determine how high and for how long this event occurred. But I would like a simple way to reset the LED. I could just repower the device which would restart everything back to its original state or a more elegant way is simply to have a Reset Button to turn the LED off – so I’d implemented a solution which would reset the warning indicator LED and provide feedback with a little flashing sequence. One important thing to note is that when the button pressed interrupt occurs it is necessary to re-enable the interrupt. This is something that you don’t normally have to do with other button click events.

 

    Dim button As New InterruptPort(Pins.GPIO_PIN_D8, False, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeBoth)
    Dim ResetLED As New OutputPort(Pins.GPIO_PIN_D12, False)
    Sub SetupResetButtonHandler()
        AddHandler button.OnInterrupt, AddressOf ResetStatusLight
        button.EnableInterrupt()
    End Sub
    Sub ResetStatusLight(ByVal data1 As UInteger, ByVal data2 As UInteger, ByVal time As Date)
        Debug.Print("Reset Warning Light")
        If data2 = 0 Then
            ResetLED.Write(True)
            Dim LEDFlashState As Boolean = False
            For i = 0 To 8
                ResetLED.Write(LEDFlashState)
                Thread.Sleep(100)
                LEDFlashState = Not LEDFlashState
            Next
            ResetLED.Write(False)
        End If
        button.EnableInterrupt()
    End Sub

 

Heartbeat Indicator

When testing the functionality I realized this device could be sitting in my pantry working away and the temperature could be just fine OR the battery could be flat and I would have no obvious signs to differentiate the two. The location of the shield on top of the device hides a little LED on the main Netduino board. So, I decided that a heartbeat LED flashing every minute would be a good idea on providing visual indication the sensor was alive and working.

Dim HeartBeatLED As New OutputPort(Pins.GPIO_PIN_D13, False)
    Private watchdogTimer As Timer
    Private HeartBeatThread As Thread = Nothing
    Private Sub HeartBeatThreadMethod()
        Dim HeartBeatDelegate As New TimerCallback(AddressOf PulseLED)
        watchdogTimer = New Timer(HeartBeatDelegate, Nothing, 1000, HeartBeatDelay * 1000)
    End Sub
    Public Sub PulseLED(stateInfo As Object)
        Debug.Print("HeartBeat...")
        HeartBeatLED.Write(True)
        Thread.Sleep(250)
        HeartBeatLED.Write(False)
        Thread.Sleep(250)
        HeartBeatLED.Write(True)
        Thread.Sleep(250)
        HeartBeatLED.Write(False)
    End Sub

Debug

With this code in place I can now debug the application. Simply pressing F5 will compile and debug the application. As the device doesn’t have a UI as such, we can use Visual Studio when debugging on a device to monitor values of variables etc. just as we would on a desktop application. This enables me to code step code to trace through the code and find logic issues as well as write additional debug output to the Output window.

The experience is very similar to the desktop – although no edit and continue is permitted. This is ok as the applications as small and you are essentially deploying them completely to the device each time you are debugging your application. The deployment is very quick as the applications are measured in kilobytes. The important thing to check is that you are deploying to the device – Project Properties > .NET Micro-framework Tab -> USB -> Netduino_Plus is selected.

Deploy

Deploying your application is automatically accomplished by debugging your application. The process involves a couple of additional steps in translating your IL into code which will run on the specific micro-framework device but these details are more to do with the hardware platform vendors SDK hooking into Visual Studio. Although .NET Micro-framework supports hardware emulators for testing – it is simple to debug on the device itself – albeit it takes a few seconds longer to deploy the application to the physical device.

 

Summary

I now have a basic functioning sensor that I can used to retrieve sensor readings from my Wine Cellar which will give me a visual indication of spoilage temperature conditions. I’ve managed to read a build a circuit, read a sensor, use timers to poll for reading, turn on/off LED’s for Visual Indication, Interact with device via a button input and write data to a Micro SD Card. These are basic functions which can be used over and over again in many different applications.

Next:

We’ll take this one step further and enable the Wifi support to allow remote reading of the device.

 

Spotty

 

Additional Info

Netduino micro-controller

www.Netduino.com

Electronic Components Suppliers

www.AdaFruit.com

www.Makershed.com

www.Sparkfun.com

Download Locations

Micro-framework 4.2 Beta

http://netmf.codeplex.com/

Netduino Firmware

http://forums.netduino.com/index.php?/topic/1958-netduino-firmware-v420-beta-1/

0 comments

Leave a comment

Feedback usabilla icon