Sunday, August 28, 2011

Netduino - LCD Fixed! Refreshing...

Ok I am getting back on track with my project, the lcd display is better than ever, I have extra functionality, can clear blocks as well as clear the whole screen and most significantly....

MY SCREEN REFRESH RATE IS FIXED!!!

This is what I did, if you get the sparkfun lcd YOU WILL NEED TO DO THIS.

Here is the lcd: http://www.sparkfun.com/products/9351
Here is the new firmware: http://sourceforge.net/projects/serialglcd/files/

You will need:

AVR ISP Mk2 (or similar product): http://store.atmel.com/PartDetail.aspx?q=p:10500054
AVR Studio 5: http://www.atmel.com/microsite/avr_studio_5/default.asp?source=redirect

Simply connect up the isp to the 6 holes on the back of the serial display and power the board like this:




Then all you need to do is go in to avr sudio and go on to the programmer option, select the avrisp mk2 and the atmega168 and connect. You should have 2 green leds on the programmer, to test the connection click read on all the various values. It is also worth doing this to have a backup of the original firmware.

Next unzip the firmware, then in avr studio browse for the main.hex file in the flash memory.

Erase the device
Then program the new main.hex on

Thats it!

Thursday, July 21, 2011

Netduino - RTC

I have bought, received and implemented my real time clock. I am using a class library I found from the forums. Currently I am just printing the time and date to the LCD along with the temperature, however I have run in to my first issue. The refresh rate on the screen seems to be about half a second, so when you clear the screen and rewrite it, you get this flickering affect, making it hard to read. I will post as I solve the issue.

I have managed to get the real time clock working now, however I am still plagued by the issue of the screen refresh.


MAIN

using System;
using System.Threading;
using System.Collections;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using SecretLabs.NETMF.Hardware;
using SecretLabs.NETMF.Hardware.Netduino;
using CW.NETMF.Hardware;
using SecretLabs.NETMF.IO;
using netduino.helpers.Hardware;

namespace SerialGraphicLcd
{

    public class Program
    {

        static SGLcd disp = new SGLcd(SerialPorts.COM2);

        public static void Main()
        {
            var clock = new DS1307();
            // Set the clock to some arbitrary date / time
            clock.Set(new DateTime(2011, 7, 21, 22, 51, 20));
            clock.Halt(false);

            int maxT = 28;
            int minT = 27;
            float oldTemp = 0;
            OutputPort tled = new OutputPort(Pins.ONBOARD_LED, false);
            OutputPort rled = new OutputPort(Pins.GPIO_PIN_D7, false);
            OutputPort gled = new OutputPort(Pins.GPIO_PIN_D6, false);
            var oneWire = new OneWire(Pins.GPIO_PIN_D0); // Adjust the pin if necessary
            disp.BackLightDutyCycle(1);
            if (oneWire.Reset())
            {
                while (true)
                {
                    // DS18B20 Thermometer
                    oneWire.WriteByte(OneWire.SkipRom); // Address all devices
                    oneWire.WriteByte(DS18B20.ConvertT);
                    Thread.Sleep(750);                  // Wait Tconv (for default 12-bit resolution)

                    oneWire.Reset();
                    oneWire.WriteByte(OneWire.SkipRom);
                    oneWire.WriteByte(DS18B20.ReadScratchpad);

                    // Read just the temperature (2 bytes)
                    var tempLo = oneWire.ReadByte();
                    var tempHi = oneWire.ReadByte();
                    var temp = DS18B20.GetTemperature(tempLo, tempHi); // ((short)((tempHi << 8) | tempLo))/16F
                  
                    Debug.Print("New temp: " + temp.ToString() + " \u00b0" + "C    -    Old temp: " + oldTemp.ToString() + " \u00b0" + "C");

                    if (temp > (int)maxT | temp < (int)minT)
                    {
                        rled.Write(true);
                        gled.Write(false);
                    }
                    else
                    {
                        rled.Write(false);
                        gled.Write(true);
                    }

                        disp.ClearDisplay();
                        disp.GotoXY(2, 54);
                        disp.Write("Temp: " + temp.ToString() + " oC");  //\u00b0
                        disp.GotoXY(2, 63);
                        disp.Write(clock.Get().ToString());

                    oneWire.Reset();
                    Thread.Sleep(4250);
                    oldTemp = (float)temp;
                }
            }
        }
    }

}



RTC

using System;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;

namespace netduino.helpers.Hardware
{
    ///

    /// This class implements a complete driver for the Dallas Semiconductors / Maxim DS1307 I2C real-time clock: http://pdfserv.maxim-ic.com/en/ds/DS1307.pdf
    ///

    public class DS1307 : IDisposable
    {
        [Flags]
        // Defines the frequency of the signal on the SQW interrupt pin on the clock when enabled
        public enum SQWFreq { SQW_1Hz, SQW_4kHz, SQW_8kHz, SQW_32kHz, SQW_OFF };

        [Flags]
        // Defines the logic level on the SQW pin when the frequency is disabled
        public enum SQWDisabledOutputControl { Zero, One };

        // Real time clock I2C address
        public const int DS1307_I2C_ADDRESS = 0x68;
        // I2C bus frequency for the clock
        public const int DS1307_I2C_CLOCK_RATE_KHZ = 100;

        // Allow 10ms timeouts on all I2C transactions
        public const int DS1307_I2C_TRANSACTION_TIMEOUT_MS = 10;

        // Start / End addresses of the date/time registers
        public const byte DS1307_RTC_START_ADDRESS = 0x00;
        public const byte DS1307_RTC_END_ADDRESS = 0x06;

        // Square wave frequency generator register address
        public const byte DS1307_SQUARE_WAVE_CTRL_REGISTER_ADDRESS = 0x07;

        // Start / End addresses of the user RAM registers
        public const byte DS1307_RAM_START_ADDRESS = 0x08;
        public const byte DS1307_RAM_END_ADDRESS = 0x3f;

        // Total size of the user RAM block
        public const byte DS1307_RAM_SIZE = 56;

        // Instance of the I2C clock
        I2CDevice clock;

        public DS1307()
        {
            clock = new I2CDevice(new I2CDevice.Configuration(DS1307_I2C_ADDRESS, DS1307_I2C_CLOCK_RATE_KHZ));
        }

        ///
        /// Gets the date / time in 24 hour format.
        ///

        /// A DateTime object
        public DateTime Get()
        {
            byte[] clockData = new byte[7];

            // Read time registers (7 bytes from DS1307_RTC_START_ADDRESS)
            var transaction = new I2CDevice.I2CTransaction[] {
                I2CDevice.CreateWriteTransaction(new byte[] {DS1307_RTC_START_ADDRESS}),
                I2CDevice.CreateReadTransaction(clockData)
            };

            if (clock.Execute(transaction, DS1307_I2C_TRANSACTION_TIMEOUT_MS) == 0)
            {
                throw new Exception("I2C transaction failed");
            }

            return new DateTime(
                BcdToDec(clockData[6]) + 2000, // year
                BcdToDec(clockData[5]), // month
                BcdToDec(clockData[4]), // day
                BcdToDec(clockData[2] & 0x3f), // hours over 24 hours
                BcdToDec(clockData[1]), // minutes
                BcdToDec(clockData[0] & 0x7f) // seconds
                );
        }

        ///
        /// Sets the time on the clock using the datetime object. Milliseconds are not used.
        ///

        /// A DateTime object used to set the clock
        public void Set(DateTime dt)
        {
            var transaction = new I2CDevice.I2CWriteTransaction[] {
                I2CDevice.CreateWriteTransaction(new byte[] {
                                  DS1307_RTC_START_ADDRESS,
                                  DecToBcd(dt.Second),
                                  DecToBcd(dt.Minute),
                                  DecToBcd(dt.Hour),
                                  DecToBcd((int)dt.DayOfWeek),
                                  DecToBcd(dt.Day),
                                  DecToBcd(dt.Month),
                                  DecToBcd(dt.Year - 2000)} )
            };

            if (clock.Execute(transaction, DS1307_I2C_TRANSACTION_TIMEOUT_MS) == 0)
            {
                throw new Exception("I2C write transaction failed");
            }
        }

        ///
        /// Enables / Disables the square wave generation function of the clock.
        /// Requires a pull-up resistor on the clock's SQW pin.
        ///

        /// Desired frequency or disabled
        /// Logical level of output pin when the frequency is disabled (zero by default)
        public void SetSquareWave(SQWFreq Freq, SQWDisabledOutputControl OutCtrl = SQWDisabledOutputControl.Zero)
        {
            byte SqwCtrlReg = (byte)OutCtrl;

            SqwCtrlReg <<= 3;   // bit 7 defines the square wave output level when disabled
            // bit 6 & 5 are unused

            if (Freq != SQWFreq.SQW_OFF)
            {
                SqwCtrlReg |= 1;
            }

            SqwCtrlReg <<= 4; // bit 4 defines if the oscillator generating the square wave frequency is on or off.
            // bit 3 & 2 are unused

            SqwCtrlReg |= (byte)Freq; // bit 1 & 0 define the frequency of the square wave

            WriteRegister(DS1307_SQUARE_WAVE_CTRL_REGISTER_ADDRESS, SqwCtrlReg);
        }

        ///
        /// Halts / Resumes the time-keeping function on the clock.
        /// Calling this function preserves the value of the seconds register.
        ///

        /// True: halt, False: resume
        public void Halt(bool halt)
        {
            var seconds = this[DS1307_RTC_START_ADDRESS];

            if (halt)
            {
                seconds |= 0x80; // Set bit 7
            }
            else
            {
                seconds &= 0x7f; // Reset bit 7
            }

            WriteRegister(DS1307_RTC_START_ADDRESS, seconds);
        }

        ///
        /// Writes to the clock's user RAM registers as a block
        ///

        /// A byte buffer of size DS1307_RAM_SIZE
        public void SetRAM(byte[] buffer)
        {
            if (buffer.Length != DS1307_RAM_SIZE)
            {
                throw new ArgumentOutOfRangeException("Invalid buffer length");
            }

            // Allocate a new buffer large enough to include the RAM start address byte and the payload
            var TrxBuffer = new byte[sizeof(byte) /*Address byte*/ + DS1307_RAM_SIZE];

            // Set the RAM start address
            TrxBuffer[0] = DS1307_RAM_START_ADDRESS;

            // Copy the user buffer after the address
            buffer.CopyTo(TrxBuffer, 1);

            // Write to the clock's RAM
            var transaction = new I2CDevice.I2CWriteTransaction[] { I2CDevice.CreateWriteTransaction(TrxBuffer) };

            if (clock.Execute(transaction, DS1307_I2C_TRANSACTION_TIMEOUT_MS) == 0)
            {
                throw new Exception("I2C write transaction failed");
            }
        }

        ///
        /// Reads the clock's user RAM registers as a block.
        ///

        /// A byte array of size DS1307_RAM_SIZE containing the user RAM data
        public byte[] GetRAM()
        {
            var ram = new byte[DS1307_RAM_SIZE];

            var transaction = new I2CDevice.I2CTransaction[] {
                    I2CDevice.CreateWriteTransaction(new byte[] {DS1307_RAM_START_ADDRESS}),
                    I2CDevice.CreateReadTransaction(ram)
                    };

            if (clock.Execute(transaction, DS1307_I2C_TRANSACTION_TIMEOUT_MS) == 0)
            {
                throw new Exception("I2C transaction failed");
            }

            return ram;
        }

        ///
        /// Reads an arbitrary RTC or RAM register
        ///

        /// Register address between 0x00 and 0x3f
        /// The value of the byte read at the address
        public byte this[byte address]
        {
            get
            {
                if (address > DS1307_RAM_END_ADDRESS)
                {
                    throw new ArgumentOutOfRangeException("Invalid register address");
                }

                var value = new byte[1];

                // Read the RAM register @ the address
                var transaction = new I2CDevice.I2CTransaction[] {
                    I2CDevice.CreateWriteTransaction(new byte[] {address}),
                    I2CDevice.CreateReadTransaction(value)
                    };

                if (clock.Execute(transaction, DS1307_I2C_TRANSACTION_TIMEOUT_MS) == 0)
                {
                    throw new Exception("I2C transaction failed");
                }

                return value[0];
            }
        }

        ///
        /// Writes an arbitrary RTC or RAM register
        ///

        /// Register address between 0x00 and 0x3f
        /// The value of the byte to write at that address
        public void WriteRegister(byte address, byte val)
        {
            if (address > DS1307_RAM_END_ADDRESS)
            {
                throw new ArgumentOutOfRangeException("Invalid register address");
            }

            var transaction = new I2CDevice.I2CWriteTransaction[] {
                I2CDevice.CreateWriteTransaction(new byte[] {address, (byte) val})
            };

            if (clock.Execute(transaction, DS1307_I2C_TRANSACTION_TIMEOUT_MS) == 0)
            {
                throw new Exception("I2C write transaction failed");
            }
        }

        ///
        /// Takes a Binary-Coded-Decimal value and returns it as an integer value
        ///

        /// BCD encoded value
        /// An integer value
        protected int BcdToDec(int val)
        {
            return ((val / 16 * 10) + (val % 16));
        }

        ///
        /// Takes a Decimal value and converts it into a Binary-Coded-Decimal value
        ///

        /// Value to be converted
        /// A BCD-encoded value
        protected byte DecToBcd(int val)
        {
            return (byte)((val / 10 * 16) + (val % 10));
        }

        ///
        /// Releases clock resources
        ///

        public void Dispose()
        {
            clock.Dispose();
        }
    }
}



LCD

using System;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using SecretLabs.NETMF.Hardware;
using SecretLabs.NETMF.Hardware.Netduino;
using System.IO.Ports;

namespace SerialGraphicLcd
{
    public sealed class SGLcd
    {

        public enum DisplayType { H12864, H240320 }

        public enum Status { On, Off }


        private readonly SerialPort _serialPort;

        private readonly DisplayType _displayType;


        public SGLcd(string portName)
            : this(portName, DisplayType.H12864)
        { }

        public SGLcd(string portName, DisplayType displayType)
        {
            // Defaults for SerialPort are the same as the settings for the LCD, but I'll set them explicitly
            _serialPort = new SerialPort(portName, 115200, Parity.None, 8, StopBits.One);

            _displayType = displayType;
        }

        public void DemoDisplay()
        {
            Write(new byte[] { 0x7C, 0x04 });
        }

        public void ClearDisplay()
        {
            Write(new byte[] { 0x7C, 0x00 });
        }

        // Reverse Mode
        public void Reverse()
        {
            Write(new byte[] { 0x7C, 0x12 });
        }

        //Splash Screen
        public void SplashScreen()
        {
            Write(new byte[] { 0x7C, 0x13 });
        }

        //Set Backlight Duty Cycle
        public void BackLightDutyCycle(byte dutycycle)
        {
            byte[] buffer = new byte[3];
            buffer[0] = 0x7c;
            buffer[1] = 0x02;
            buffer[2] = dutycycle;

            Write(buffer);
        }
        //Change Baud Rate
        /*
        “1” = 4800bps
        “2” = 9600bps
        “3” = 19,200bps
        “4” = 38,400bps
        “5” = 57,600bps
        “6” = 115,200bps
        */
        public void NewBaudRate(string baud)
        {
            byte[] temp = new byte[3];
            temp[0] = 0x7c;
            temp[1] = 0x07;
            temp[2] = (byte)baud[0];
            Write(temp);
        }


        //Set X or Y Coordinates
        public void GotoXY(byte x, byte y)
        {
            //set x first
            byte[] temp = new byte[3];
            temp[0] = 0x7c;
            temp[1] = 0x18;
            temp[2] = x;
            Write(temp);
            //set y
            temp[0] = 0x7c;
            temp[1] = 0x19;
            temp[2] = y;
            Write(temp);
        }

        //Set/Reset Pixel - x =0 to xmax, y = 0 to ymax, state = 0 or 1
        public void SetPixel(byte x, byte y, byte state)
        {
            byte[] temp = new byte[5];
            temp[0] = 0x7c;
            temp[1] = 0x10;
            temp[2] = x;
            temp[3] = y;
            temp[4] = state;
            Write(temp);
        }


        //Draw Line x1 y1 first coords, x2 y2 second coords, state 0 = erase 1 = draw
        public void DrawLine(byte x1, byte y1, byte x2, byte y2, byte state)
        {
            byte[] temp = new byte[7];
            temp[0] = 0x7c;
            temp[1] = 0x0c;
            temp[2] = x1;
            temp[3] = y1;
            temp[4] = x2;
            temp[5] = y2;
            temp[6] = state;
            Write(temp);
        }


        //Draw Circle
        public void DrawCircle(byte x, byte y, byte r, byte state)
        {
            byte[] temp = new byte[6];
            temp[0] = 0x7c;
            temp[1] = 0x03;
            temp[2] = x;
            temp[3] = y;
            temp[4] = r;
            temp[5] = state;
            Write(temp);
        }

        //Draw Box
        public void DrawBox(byte x1, byte y1, byte x2, byte y2, byte state)
        {
            byte[] temp = new byte[7];
            temp[0] = 0x7c;
            temp[1] = 0x0f;
            temp[2] = x1;
            temp[3] = y1;
            temp[4] = x2;
            temp[5] = y2;
            temp[6] = state;
            Write(temp);
        }

        //Erase Block
        public void EraseBlock(byte x1, byte y1, byte x2, byte y2)
        {
            byte[] temp = new byte[6];
            temp[0] = 0x7c;
            temp[1] = 0x05;
            temp[2] = x1;
            temp[3] = y1;
            temp[4] = x2;
            temp[5] = y2;

            Write(temp);

        }


        public void Open()
        {
            if (!_serialPort.IsOpen)
                _serialPort.Open();
        }



        public void Write(byte buffer)
        {
            Write(new[] { buffer });
        }

        public void Write(byte[] buffer)
        {
            Open();

            _serialPort.Write(buffer, 0, buffer.Length);
        }

        public void Write(char character)
        {
            Write((byte)character);
        }

        public void Write(string text)
        {
            byte[] buffer = new byte[text.Length];

            for (int i = 0; i < text.Length; i++)
            {
                buffer[i] = (byte)text[i];
            }

            Write(buffer);
        }
    }
}

Sunday, July 17, 2011

Netduino - Getting somewhere...

Since my last post I haven't had much time to do anything with my project, but yesterday I had a fantastically productive day. I decided to bypass the 6-7 volt requirement of the 5v regulator on the serial backpack for my LCD and to power the 5v pin directly from my netduino. This meant I could instantly start playing around with my LCD. I found I really useful class on the netduino forums: http://forums.netduino.com/index.php?/topic/687-driver-class-for-sparkfun-lcd-graphic-backpack/ and quickly managed to get temperatures on the screen.

Currently my project is reading temperatures, determining if it is with a range, then if it is in range a green led is on and when it goes out of range a red led comes on. Also the temperature is then printed to the display, see my code so far below:


using System;
using System.Threading;
using System.Collections;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using SecretLabs.NETMF.Hardware;
using SecretLabs.NETMF.Hardware.Netduino;
using CW.NETMF.Hardware;
using SecretLabs.NETMF.IO;


namespace SerialGraphicLcd
{

    public class Program
    {

        static SGLcd disp = new SGLcd(SerialPorts.COM2);

        public static void Main()
        {
            int maxT = 28;
            int minT = 27;
            float oldTemp = 0;
            OutputPort tled = new OutputPort(Pins.ONBOARD_LED, false);
            OutputPort rled = new OutputPort(Pins.GPIO_PIN_D7, false);
            OutputPort gled = new OutputPort(Pins.GPIO_PIN_D6, false);
            var oneWire = new OneWire(Pins.GPIO_PIN_D0); // Adjust the pin if necessary
            disp.BackLightDutyCycle(1);
            if (oneWire.Reset())
            {
                while (true)
                {
                    // DS18B20 Thermometer
                    oneWire.WriteByte(OneWire.SkipRom); // Address all devices
                    oneWire.WriteByte(DS18B20.ConvertT);
                    Thread.Sleep(750);                  // Wait Tconv (for default 12-bit resolution)

                    oneWire.Reset();
                    oneWire.WriteByte(OneWire.SkipRom);
                    oneWire.WriteByte(DS18B20.ReadScratchpad);

                    // Read just the temperature (2 bytes)
                    var tempLo = oneWire.ReadByte();
                    var tempHi = oneWire.ReadByte();
                    var temp = DS18B20.GetTemperature(tempLo, tempHi); // ((short)((tempHi << 8) | tempLo))/16F
                   
                    Debug.Print("New temp: " + temp.ToString() + " \u00b0" + "C    -    Old temp: " + oldTemp.ToString() + " \u00b0" + "C");

                    if (temp > (int)maxT | temp < (int)minT)
                    {
                        rled.Write(true);
                        gled.Write(false);
                    }
                    else
                    {
                        rled.Write(false);
                        gled.Write(true);
                    }
                    if (oldTemp != (float)temp)
                    {
                        disp.ClearDisplay();
                        disp.GotoXY(2, 63);
                        disp.Write(temp.ToString() + " oC");  //\u00b0
                    }
                    oneWire.Reset();
                    Thread.Sleep(5000);
                    oldTemp = (float)temp;
                }
            }
        }
    }

}


My next aim is to get the data logged on to the Micro SD, in a format that can be used by the netduino and could also be used to plug in to a computer. The end idea for the SD is to give me more space for my code and also to store data, for example if the internet went down or the server that I will log my data on in the future, the netduino would have a backup on the SD. As each entry will be time stamped it can find the last entry and then reconcile the missing times. This data will then be graphically display in graphs etc to allow me to monitor fluctuations in parameters of the tank over time.

Update to my shopping list....

I have just order a real time clock board which has a DS1307 rtc IC on it, and 6 relays from Hong Kong. The relays are solid state and operate on a 3-32 volt switching current and can take up to 15amps @ 480v. I am going to build a board, perhaps using some diodes to isolate the relays completely and some transistors to switch them, with LEDs to let me know which relays are on. The great thing with the SSRs is I can do PWM on lights, essentially allowing me to dim any light, although I am eventually going to use LED lighting in all my tanks. The primary reason for the SSRs was just because they require a low voltage so I can power them directly from the netduino and they isolate the high current inside them. I will need to look at using a shift register to operate the relays as I don't want to use to many pins from the netduino. I have already had a little play with shift registers to control LEDs but only managed to daisy chain 2, the third seemed to operate inversely to other 2.

Thursday, July 7, 2011

Netduino - dimmer update

I have done a slight update to my dimmer code as I noticed that there was a little noise at the bottom end which led to the led flickering slightly rather than being completely off. I corrected this with a simple if less than or equal to 3% then set to 0%. I also looked at inverse usage of the pots reading, this is done by taking the pot value away from 100, as the range of the pot was set to 0 - 100.


using System;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using SecretLabs.NETMF.Hardware;
using SecretLabs.NETMF.Hardware.Netduino;

namespace CIRC_08
{
    public class Program
    {

        static PWM pwm2 = new PWM(Pins.GPIO_PIN_D10);
        static AnalogInput potentiometer = new AnalogInput(Pins.GPIO_PIN_A0);
        static PWM pwm = new PWM(Pins.GPIO_PIN_D5);

        public static void Main()
        {
            int sensorValue = 0;
            potentiometer.SetRange(0, 100);

            while (true)
            {
                sensorValue = potentiometer.Read();
                if (sensorValue <= 3)
                {
                    sensorValue = 0;
                }
                Debug.Print("pot value = " + sensorValue.ToString());
                pwm.SetDutyCycle((uint)sensorValue);
                pwm2.SetDutyCycle(100-(uint)sensorValue);
            }
        }

    }
}

Wednesday, July 6, 2011

Netduino - project update

Since my last post I have been quite busy following basic tutorials (losely) and trying to achieve a few simple projects that may become part of my final project. This has been great for me to get to grips with c# and the .net framework and I am already starting to see similarities in between asp.net and the micro framework.

I have sucessfully managed to create a dimmer, initially this was a button triggered dimmer that turned a light on and off in a fading action. This has been refined with a more personal approach and I have managed to take reading from a pot and use this to affect the pwm port in order to dim the light. It's basic but it proves a point.


using System;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using SecretLabs.NETMF.Hardware;
using SecretLabs.NETMF.Hardware.Netduino;

namespace CIRC_08
{
    public class Program
    {

        static OutputPort led = new OutputPort(Pins.GPIO_PIN_D13, false);
        static AnalogInput potentiometer = new AnalogInput(Pins.GPIO_PIN_A0);
        static PWM pwm = new PWM(Pins.GPIO_PIN_D5);
      
        public static void Main()
        {
            int sensorValue = 0;
            potentiometer.SetRange(0, 100);
                      
            while (true)
            {
                sensorValue = potentiometer.Read();
                Debug.Print("pot value = " + sensorValue.ToString());
                pwm.SetDutyCycle((uint)sensorValue);
            }
        }

    }
}


Finally I have also ordered some extra bits and pieces, I have 10 shift registers, a real time clock, a new temperature probe and a few other bits on their way. I am currently trying to figure out if I can bypass the 6-7 v vcc on the lcd display I have in order to run it straight off the netduino. The idea being I will play around with the screen a little and then see if I can print my various reading to it. After that it will be logging data to the sd card!

Sunday, June 26, 2011

Netduino - Temperature probe adapter

Here is my temperature probe adapter, I am using a 1% 4k7 resistor between pins 2 and 3 of the probe. This will allow me to plug my pre made probe straight in and then a 3pin header cable will go to the bread board to got in to the netduino.

Saturday, June 25, 2011

Netduino - Project update inc Temperature

I have been playing with my netduino for a few days and have done a fair bit of reading which has led to a couple of changes....

A lack of reading in the first place unfortunately led to me making a few ordering errors. I now know that the xbee wireless module is not wireless in the way I was expecting, it communicates on 2.4GHz, BUT it is 802.15 and not 802.11 making it incompatible with wifi internet devices. I also discovered I would have saved a fair bit of cash and required fewer addons if I had known about the netduino plus. The netduino plus has ethernet on the board, its not wireless but it allows for a web connection out of the box. Also it has an micro SD slot on the board, meaning I wouldn't have needed the SD shield.

Since these belated discoveries I have returned the xbee module and adapter shield. My original plan was for wireless and I have looked at this briefly, however initial reading shows that this is somewhat problematic with the netduino. The wifly has a lot of issues and has no official drivers, it also requires external power to the netduino and a bit of pin rerouting. At this time, this doesn't sound like a practical option, so I am going to leave it until I have the board sensing and controlling. One possible option is to get the netduino plus, but for now I will still with the netduino until I have learnt a little more.

So I am getting to grips with C# slowly, managed to edit a little code and made my first break through and fatality at the same time. I found some code for one wire support http://forums.netduino.com/index.php?/topic/230-onewire-alpha/page__p__1505__hl__ds18b20__fromsearch__1#entry1505, again a feature not currently officially supported, and I managed to get a temperature reading eventually. I am using a DS18B20 and re-flashed the netduino with v4.1.1 beta with one wire. This was an experience and an encouraging learning curve in its self. I have now used SAMBA and MFDEPLOY which I have a feeling will become more and more necessary. This went well and I got my LED blink test running with a little help. The beta firmware can also be found on the link above.

I used the example program.cs code of the afore mentioned thread as well as the DS18B20.cs class from the example project. I need to reference the LE OneWire.dll from the zip and also the System.Threading reference to allow for degree characters.

This is my working code:
Program.cs

using System;
using System.Threading;
using System.Collections;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using SecretLabs.NETMF.Hardware;
using SecretLabs.NETMF.Hardware.Netduino;
using CW.NETMF.Hardware;

namespace NetduinoApplication1
{
    public class Program
    {
        public static void Main()
        {
            var oneWire = new OneWire(Pins.GPIO_PIN_D0); // Adjust the pin if necessary
            if (oneWire.Reset())
            {
                // DS18B20 Thermometer
                oneWire.WriteByte(OneWire.SkipRom); // Address all devices
                oneWire.WriteByte(DS18B20.ConvertT);
                Thread.Sleep(750);                  // Wait Tconv (for default 12-bit resolution)

                oneWire.Reset();
                oneWire.WriteByte(OneWire.SkipRom);
                oneWire.WriteByte(DS18B20.ReadScratchpad);

                // Read just the temperature (2 bytes)
                var tempLo = oneWire.ReadByte();
                var tempHi = oneWire.ReadByte();
                var temp = DS18B20.GetTemperature(tempLo, tempHi); // ((short)((tempHi << 8) | tempLo))/16F
                Debug.Print(temp.ToString() + " \u00b0" + "C");
            }
            Thread.Sleep(Timeout.Infinite);



        }

    }
}

 DS18B20.cs

 //---------------------------------------------------------------------------
//
//
// Copyright 2010 Stanislav "CW" Simicek
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//

//---------------------------------------------------------------------------
namespace CW.NETMF.Hardware
{
    ///

    /// DS18B20 Programmable Resolution 1-Wire Digital Thermometer
    ///

    public static class DS18B20
    {
        public const byte FamilyCode = 0x28;

        // Commands
        public const byte ConvertT = 0x44;
        public const byte CopyScratchpad = 0x48;
        public const byte WriteScratchpad = 0x4E;
        public const byte ReadPowerSupply = 0xB4;
        public const byte RecallE2 = 0xB8;
        public const byte ReadScratchpad = 0xBE;

        // Helpers
        public static float GetTemperature(byte tempLo, byte tempHi)
        {
            return ((short)((tempHi << 8) | tempLo)) / 16F;
        }
    }
}


This gave me single temperature read outs that seemed very accurate from my testing with a digital thermometer. What I did next was the fatality......

Eager to get this in the fish tank I went about making my submersible temperature probe as per: http://www.practicalmaker.com/sensor/diy-waterproof-ds18b20-temperature-sensor. However I managed to snap a leg off the DS18B20. Since then I have decided to order a pre-made probe, I'm all for DIY but these look really good and safe for in the tank: http://www.earthshineelectronics.com/components/18-ds18b20-digital-temperature-probe.html

I have built a little connection device on some protoboard, essentially just some angled headers, a resistor and some normal headers, allowing me to connect the probe to the netduino easily with a resistor. I will upload a picture soon.

My next plan is to have another go at personalising the code so that I can get a reading once every 5 seconds and then will be to get this logged some how. I will also have a go at getting temperature reading to display on the the LCD.

Wednesday, June 15, 2011

Netduino shopping list

Here is a the spec of my aquarium controller and the parts I have ordered...

It will provide 3 main functions via 3 levels of control, the controller will log sensor readings, will control the parameters of the fish tank, will alert when the monitored variables go outside the 'normal' parameters.

The controller will measure temperature, PH and light initially, latter on I may measure additional environmental factors such as flow, ORP, conductivity, water level and dissolved oxygen (DO).

From the initial measurements it will control, monitor, log and report on the temperature and control the heater accordingly. Initially PH will be measure but as a means of warning only, eventually this may expand to control CO2 dosers. Light will be used to sense the ambient light and could for example turn the fish tank lights off earlier if the light level in the house is below a certain level, or turn them up if light is at a low level. Alternatively this could be used to control the intensity of the lights in the tank to follow the climate locally. Eventually dissolved oxygen reading will control the air pump and the flow meter can report on significant losses of pump power, either from air lock after feeding pump stops or blockages and control the heater and air pump accordingly.

Other features will include, 5 minute or adjustable pump and heater pauses for feeding cycles and control of an automated feeder. Control of the pump for cleaning, feeding and water changes. Control of the air pump, for cleaning, noise reduction and night time. Control of lights which will be replaced with high power RGB LEDs, these will follow lunar and solar patterns based on data from the web and can be manually controlled for ambiance. Also they will be programmed to simulate cloud cover and lightening.

Future feature possibilities, water level and auto top control. Also the ability to auto water change, pumping water out and simultaneously heating and filtering and pumping water back in (possibly using a temperature controlled sump and/or top tank and mains attached RO unit.

Control is a key aspect of the project, the device itself must be able to independently monitor and control parameters automatically, but also make it possible to manually control and interface with the device. This manual control and monitoring will be both remote, via a web interface and local using an LCD graphics display and keypad. Reading will be stored on a web server and also backed up locally on an SD card. If there are any network issues the device will revert to local backup only until a connection is re-established and at which point, the web data loss will be restored from the SD card. Via the web all aspect will be graphically viewable and can be controlled, there will also be an IP web cam for monitoring the tank (possibly pan tilt controlled). Via both the keypad and the web settings can be programmed and changed and will be stored both locally and on the web, should a problem occur with the devices memory.

Currently my shopping list comprises of the following, there are sill a few things I need.

Atlas scientific - pH-Stamp: AVR, PIC, Arduino, Parallax NEW V2.0  $20.00 + $10 postage. 

3p-3p 12X Arduino 20cm Jumper Cable Shield EQUIV SENSOR (160575951979) $1.96 + $2.43

3mm Heat Shrink 2:1 - 5 meters £0.99
13MM HIGH QUALITY BLACK HEATSHRINK / heat shrink  £1.00 + £0.79 postage
Product Model Quantity Unit Price Total
Netduino board NETDUINO 1 £25.95 £25.95
XBee Shield - Sparkfun WRL-09976 1 £16.95 £16.95
Arduino Stackable Header Kit PRT-10007 2 £1.25 £2.50
830 point Breadboard 352 1 £3.99 £3.99
140 piece Jumper Wire Kit 312 1 £4.25 £4.25
Stripboard 95 x 127mm STRIPBRD95127 1 £1.75 £1.75
Light Dependent Resistor LDR 1 £0.60 £0.60
One Wire Digital Temperature Sensor - DS18B20 SEN-00245 1 £3.25 £3.25
XBee 2mW Chip Antenna - Series 2 (ZB) XBEE2MWS2CA 1 £22.95 £22.95
Serial Graphic LCD 128x64 with Backlight LCD-09351 1 £26.00 £26.00

Arduino MicroSD Shield DEV-09802 1 £11.95 £11.95











Netduino Aquarium controller

This is my first post about my latest project, a netduino Aquarium controller.

The purpose of this project is to help me learn C# within asp.net using visual studio and to also technologicalise my fish tank up to the 21st century.

At this point I have spent a ridiculous amount of time deciding how to achieve my goal of learning a new language in a useful manner and producing a new cool toy that will help me automate my aquarium. This research has took me to phidgets, arduino, many other arm processor based solutions and finally to netduino. The hardest decision at first was on a processing power level, microcontroller or single board computer (sbc).

Finally after many rambling in various forums and a lot of Google searches, I came to the conclusion of a microcontroller to meet my requirements. There was one main sacrifice that the Phidget sbc offered that Arduino doesn't and this is the ability to plug in usb peripherals, notably a web cam. The work around for this loss will be an IP cam, but I will get to that later. After this massive dilemma, if you've seen the film, this one was much bigger, I settled on the Arduino, only after placing my order, to change my mind and go with the Netduino.

The reason behind this choice moved from wanting the most I/O to wanting to use visual studio and a language which is much more useful to work and play.

My order is in the post and arrives tomorrow, I will give a run though of what I have ordered and how I envisage it to work together tomorrow evening.