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);
        }
    }
}

1 comment:

  1. HI

    I'm Korean student and I'm very Impressed from your
    gorgeous project.

    And I want to make it too but I have one problem.

    Can you send me a OneWire Library version netduino plus?

    I can't register in netduino forum and I can't get it.

    I beg you to send me that library.

    Thanks you

    My Mail : urmall1108@naver.com

    link : http://forums.netduino.com/index.php?/topic/230-onewire-alpha/

    ReplyDelete