Untitled Sketch 2_bb.png 34.46KB 288 downloads
The 5 wires (from top of the black part) are SDA, SCL, SQW, GND, 5V. The resistors are both 1k Ohm from the SDA/SCL lines to 5V.
For the code, I started with what I found over in the NetduinoHelpers project, but I enhanced and refactored it a lot. The new code supports the 12/24 flag properly. It also will share the I2CDevice with other classes that might need to use it at the same time by locking the I2CDevice instance before interacting with it.
My version of the DS1307 class is attached below too for easy downloading.
using System; using Microsoft.SPOT; using Microsoft.SPOT.Hardware; namespace netduino.helpers.Hardware { /// <summary> /// 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 /// </summary> public class IcDS1307 : 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; public const byte DS1307_RTC_SIZE = 7; // 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 readonly bool privateClock = false; readonly I2CDevice clock; readonly I2CDevice.Configuration config = new I2CDevice.Configuration(DS1307_I2C_ADDRESS, DS1307_I2C_CLOCK_RATE_KHZ); public IcDS1307() { privateClock = true; clock = new I2CDevice(config); } public IcDS1307(I2CDevice device) { clock = device; } /// <summary> /// Gets or Sets the current date / time. /// </summary> /// <returns>A DateTime object</returns> public DateTime CurrentDateTime { get { byte[] clockData = ReadRegister(DS1307_RTC_START_ADDRESS, DS1307_RTC_SIZE); return ParseDate(clockData); } set { WriteRegister(DS1307_RTC_START_ADDRESS, EncodeDate(value, ClockHalt, TwelveHourMode)); } } private DateTime ParseDate(byte[] clockData) { int hour = 0; if ((clockData[0x02] & 0x40) == 0x40) { // 12-hour mode if ((hour & 0x20) == 0x20) hour += 12; hour += BcdToDec((byte)(clockData[0x02] & 0x1f)) + 1; } else { // 24-hour mode hour += BcdToDec((byte)(clockData[0x02] & 0x3f)); } return new DateTime( BcdToDec(clockData[0x06]) + 2000, // year BcdToDec(clockData[0x05]), // month BcdToDec(clockData[0x04]), // day hour, // hour BcdToDec(clockData[0x01]), // minutes BcdToDec((byte)(clockData[0x00] & 0x7f))); } private byte[] EncodeDate(DateTime value, bool clockHalt, bool hourMode) { byte seconds = 0x00; if (clockHalt) seconds |= 0x80; seconds |= (byte)(DecToBcd(value.Second) & 0x7f); byte hour = 0x00; if (hourMode) { // 12-hour mode hour |= 0x40; //set the 12-hour flag if (value.Hour >= 12) hour |= 0x20; hour |= DecToBcd((value.Hour % 12) + 1); } else { //24-hour mode hour |= DecToBcd(value.Hour); } return new byte[DS1307_RTC_SIZE] { seconds, DecToBcd(value.Minute), hour, DecToBcd((int)value.DayOfWeek), DecToBcd(value.Day), DecToBcd(value.Month), DecToBcd(value.Year - 2000)}; } /// <summary> /// Enables / Disables the square wave generation function of the clock. /// Requires a pull-up resistor on the clock's SQW pin. /// </summary> /// <param name="Freq">Desired frequency or disabled</param> /// <param name="OutCtrl">Logical level of output pin when the frequency is disabled (zero by default)</param> 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); } /// <summary> /// Halts / Resumes the time-keeping function on the clock. /// The value of the seconds register will be preserved. /// (True: halt, False: resume) /// </summary> public bool ClockHalt { get { var seconds = this[0x00]; return (seconds & 0x80) == 0x80; } set { lock (clock) { var seconds = this[0x00]; if (value) seconds |= 0x80; // Set bit 7 else seconds &= 0x7f; // Reset bit 7 WriteRegister(0x00, seconds); } } } /// <summary> /// Gets/Sets the Hour mode. /// The current time will be corrected. /// (True: 12-hour, False: 24-hour) /// </summary> public bool TwelveHourMode { get { var hours = this[0x02]; return (hours & 0x40) == 0x40; } set { lock (clock) { var rtcBuffer = ReadRegister(DS1307_RTC_START_ADDRESS, 7); var currentDate = ParseDate(rtcBuffer); rtcBuffer = EncodeDate(currentDate, false, value); WriteRegister(0x02, rtcBuffer[0x02]); } } } /// <summary> /// Writes to the clock's user RAM registers as a block /// </summary> /// <param name="buffer">A byte buffer of size DS1307_RAM_SIZE</param> public void SetRAM(byte[] buffer) { if (buffer.Length != DS1307_RAM_SIZE) throw new ArgumentOutOfRangeException("Invalid buffer length"); WriteRegister(DS1307_RAM_START_ADDRESS, buffer); } /// <summary> /// Reads the clock's user RAM registers as a block. /// </summary> /// <returns>A byte array of size DS1307_RAM_SIZE containing the user RAM data</returns> public byte[] GetRAM() { return ReadRegister(DS1307_RAM_START_ADDRESS, DS1307_RAM_SIZE); } public byte this[byte address] { get { return ReadRegister(address, 1)[0]; } set { WriteRegister(address, value); } } /// <summary> /// Reads an arbitrary RTC or RAM register /// </summary> /// <param name="address">Register address between 0x00 and 0x3f</param> /// <param name="length">The number of bytes to read</param> /// <returns>The value of the bytes read at the address</returns> public byte[] ReadRegister(byte address, int length = 1) { if (length < 1) throw new ArgumentOutOfRangeException("length", "Must read at least 1 byte"); if (address + length -1 > DS1307_RAM_END_ADDRESS) throw new ArgumentOutOfRangeException("Invalid register address"); var buffer = new byte[length]; lock (clock) { clock.Config = config; // Read the RAM register @ the address var transaction = new I2CDevice.I2CTransaction[] { I2CDevice.CreateWriteTransaction(new byte[] {address}), I2CDevice.CreateReadTransaction(buffer) }; if (clock.Execute(transaction, DS1307_I2C_TRANSACTION_TIMEOUT_MS) == 0) { throw new Exception("I2C transaction failed"); } } return buffer; } /// <summary> /// Writes an arbitrary RTC or RAM register /// </summary> /// <param name="address">Register address between 0x00 and 0x3f</param> /// <param name="val">The value of the byte to write at that address</param> public void WriteRegister(byte address, byte data) { WriteRegister(address, new byte[] { data }); } public void WriteRegister(byte address, byte[] data) { if (address > DS1307_RAM_END_ADDRESS) throw new ArgumentOutOfRangeException("Invalid register address"); if (address + data.Length > DS1307_RAM_END_ADDRESS) throw new ArgumentException("Buffer overrun"); byte[] txData = new byte[data.Length + 1]; txData[0] = address; data.CopyTo(txData, 1); lock (clock) { clock.Config = config; var transaction = new I2CDevice.I2CWriteTransaction[] { I2CDevice.CreateWriteTransaction(txData) }; if (clock.Execute(transaction, DS1307_I2C_TRANSACTION_TIMEOUT_MS) == 0) { throw new Exception("I2C write transaction failed"); } } } /// <summary> /// Takes a Binary-Coded-Decimal value and returns it as an integer value /// </summary> /// <param name="val">BCD encoded value</param> /// <returns>An integer value</returns> protected int BcdToDec(byte val) { int ones = (val & 0x0f); int tens = (val & 0xf0) >> 4; return (tens * 10) + ones; } /// <summary> /// Takes a Decimal value and converts it into a Binary-Coded-Decimal value /// </summary> /// <param name="val">Value to be converted</param> /// <returns>A BCD-encoded value</returns> protected byte DecToBcd(int val) { byte lowOrder = (byte)(val % 10); byte highOrder = (byte)((val / 10) << 4); return (byte)(highOrder | lowOrder); } /// <summary> /// Releases clock resources /// </summary> public void Dispose() { if(privateClock) clock.Dispose(); } } }