Dennis Smith / Mbed 2 deprecated NixieClock800Max

Dependencies:   PCF8583_rtc mbed

Files at this revision

API Documentation at this revision

Comitter:
dennyem
Date:
Sun Feb 09 00:25:21 2014 +0000
Child:
1:a8b9fb95696b
Commit message:
First C++ revision for the LPC812

Changed in this revision

PCF8583_rtc.cpp Show annotated file Show diff for this revision Revisions of this file
PCF8583_rtc.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PCF8583_rtc.cpp	Sun Feb 09 00:25:21 2014 +0000
@@ -0,0 +1,403 @@
+/*********************************************************************************
+ * An mbed class to control the PCF8583 Real time Clock/Calender
+ * Copyright (c) 2014 Dennis (Denny) Smith - dennyem
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * 13.01.14    initial design for PIC devices using PICC compiler
+ * 21.01.14    ported to mBed LPC1768 in 'C'
+ * 09.02.14    converted to C++ and ported to mBed LPC812
+ *
+ * TODO
+ *       write function is still to be tested
+ *       WriteNVram function is still to be tested
+ *       ReadNVram function is still to be tested
+ *       FormatDateTime needs am/pm, 12/24 hour parsing
+ *       Alarm functions not yet implemented
+*/
+
+#include <mbed.h>
+#include <PCF8583_rtc.h>
+
+//-----------------------------------------------------------------------------
+// constructor -- accepts an I2c object to use for connection with the rtc
+PCF8583rtc::PCF8583rtc(I2C *i2c)
+{
+   _i2c = i2c;
+      
+  ShortDateFormat = "d,m,yy";
+  LongDateFormat  = "dddd dd mmmm yyyy";
+  ShortTimeFormat = "d:m:yy";
+  LongTimeFormat  = "dd:nn:yyyy";
+
+  DateSeparator   = '/';
+  TimeSeparator   = ':';
+
+  ShortDayNames[0] = "Mon";
+  ShortDayNames[1] = "Tue";
+  ShortDayNames[2] = "Wed";
+  ShortDayNames[3] = "Thu";
+  ShortDayNames[4] = "Fri";
+  ShortDayNames[5] = "Sat";
+  ShortDayNames[6] = "Sun";
+
+  LongDayNames[0]  = "Monday";
+  LongDayNames[1]  = "Tuesday";
+  LongDayNames[2]  = "Wednesday";
+  LongDayNames[3]  = "Thursday";
+  LongDayNames[4]  = "Friday";
+  LongDayNames[5]  = "Saturday";
+  LongDayNames[6]  = "Sunday";
+
+  ShortMonthNames[0] = "Jan";
+  ShortMonthNames[1] = "Feb";
+  ShortMonthNames[2] = "Mar";
+  ShortMonthNames[3] = "Apr";
+  ShortMonthNames[4] = "May";
+  ShortMonthNames[5] = "Jun";
+  ShortMonthNames[6] = "Jul";
+  ShortMonthNames[7] = "Aug";
+  ShortMonthNames[8] = "Sep";
+  ShortMonthNames[9] = "Oct";
+  ShortMonthNames[10] = "Nov";
+  ShortMonthNames[11] = "Dec";
+
+  LongMonthNames[0]  = "January";
+  LongMonthNames[1]  = "February";
+  LongMonthNames[2]  = "March";
+  LongMonthNames[3]  = "April";
+  LongMonthNames[4]  = "May";
+  LongMonthNames[5]  = "June";
+  LongMonthNames[6]  = "July";
+  LongMonthNames[7]  = "August";
+  LongMonthNames[8]  = "September";
+  LongMonthNames[9]  = "October";
+  LongMonthNames[10]  = "November";
+  LongMonthNames[11]  = "December";
+};
+
+void PCF8583rtc::write(const char address)
+{
+    pauseCounting();    //Must stop counting before initialising Date/time
+
+    _i2c->start();                                                 // Issue start signal
+    _i2c->write(Write_addr);                                       // Address PCF8583, see PCF8583 datasheet
+    _i2c->write(address);                                          // Address is 1 for Time or 10 for Alarm
+    _i2c->write(dt.time.hundreds);                                 // Hundredths of a second
+    _i2c->write(dt.time.seconds);                                  // Seconds
+    _i2c->write(dt.time.minutes);                                  // Minutes
+    _i2c->write(dt.time.hours);                                    // Hours
+    _i2c->write(dt.date.day & 0x3F);                               // Always set the 3 year bits to 0
+
+    if(address == TIME)
+        _i2c->write(((dt.date.weekday & 7) << 5 )| dt.date.month); // Weekday/month
+    else
+        _i2c->write(dt.date.month & 0x1f);                         // No Weekday for alarm
+
+    _i2c->stop();                                                  // Issue stop signal
+
+    if(address == TIME) {
+        writeByte(CENTURY_REG, dt.date.century);                 // Store the full 4 digit year in NV Ram
+        writeByte(YEAR_REG, dt.date.year);
+    };
+
+    enableCounting();
+};
+
+//--------------------- Reads time and date information from RTC (PCF8583)
+void PCF8583rtc::read(const char address)
+{
+    char tmp[8];
+    char year_bits = 0;                // To test for year change
+
+    tmp[0] = address;
+    _i2c->write(PCF8583_addr, tmp, 1); // Address PCF8583, see PCF8583 datasheet
+    _i2c->read(PCF8583_addr, tmp, 6);  // Address PCF8583 for reading R/W=1
+    
+    dt.time.hundreds   = ((tmp[0] & 0xF0) >> 4) * 10 + (tmp[0] & 0x0F);   // Transform hundredths of seconds
+    dt.time.seconds    = ((tmp[1] & 0xF0) >> 4) * 10 + (tmp[1] & 0x0F);   // Transform seconds
+    dt.time.minutes    = ((tmp[2] & 0xF0) >> 4) * 10 + (tmp[2] & 0x0F);   // Transform minutes
+    dt.time.hours      = ((tmp[3] & 0x30) >> 4) * 10 + (tmp[3] & 0x0F);   // Transform hours
+    dt.time.fmt_hours  =  (tmp[3] & 0x80);                                // 12/24 hour format
+    dt.time.am_pm_flag =  (tmp[3] & 0x40);                                // Am/Pm flag
+    dt.date.day        = ((tmp[4] & 0x30) >> 4) * 10  + (tmp[4] & 0x0F);  // Transform day
+
+    if(address == TIME)
+        year_bits = (tmp[4] & 0xC0) >> 6;
+    else
+        dt.date.year = 0;                                              // No year for alarm
+
+    dt.date.month   = ((tmp[5] & 0x10)  >> 4) * 10 + (tmp[5] & 0x0F);  // Transform month
+
+    if(address == TIME)
+        dt.date.weekday =  tmp[5] >> 5;
+    else
+        dt.date.weekday =  0;                                          // No weekday for alarm
+
+    if(address == TIME) {
+        tmp[0] = readByte(CENTURY_REG);
+        dt.date.century  = ((tmp[0] & 0xF0) >> 4) * 10 + (tmp[0] & 0x0F);
+        tmp[0] = readByte(YEAR_REG);
+        dt.date.year  = ((tmp[0] & 0xF0)  >> 4) * 10 + (tmp[0] & 0x0F);
+
+        if(year_bits > 0) {                                            // Midnight on new years eve?
+            dt.date.year += 1;                                         // Increment the year
+            writeByte(YEAR_REG, dt.date.year);                         // Save the new year value to NV Ram
+            writeByte(5, dt.date.day & 0x3F);                          // Clear the year bits but preserve the date
+        }
+    }
+};
+
+struct DateTime_t PCF8583rtc::GetDateTime(void)
+{
+  return dt;    
+}
+ 
+struct DateTime_t PCF8583rtc::GetDateTimeBCD(void)
+{
+    struct DateTime_t dtb;
+    
+    dtb = dt;
+    dtb.time.hours    = bin2bcd(dt.time.hours);
+    dtb.time.minutes  = bin2bcd(dt.time.minutes);
+    dtb.time.seconds  = bin2bcd(dt.time.seconds);
+    dtb.time.hundreds = bin2bcd(dt.time.hundreds);
+
+    dtb.date.day      = bin2bcd(dt.date.day);
+    dtb.date.month    = bin2bcd(dt.date.month);
+    dtb.date.year     = bin2bcd(dt.date.year);
+    dtb.date.century  = bin2bcd(dt.date.century);
+  
+    return dtb;
+}
+
+void PCF8583rtc::FormatDateTime(char *dest, char *f)
+{
+    if(f != 0 && *f != 0) {   //If the format param is empty then do a default 'c'
+        while(*f != 0) {        //expect null terminated string (we hope)
+            switch(*f) {
+                case 'c':
+                    break;
+                case 'd':
+                    if(*(f+1) != 'd') {            //'d' - Day with no leading zero
+                        dest += Bcd2Char(dest, dt.date.day, FALSE);
+                    } else {
+                        f++;
+                        if(*(f+1) != 'd')            //'dd' - Day with leading zero
+                            dest += Bcd2Char(dest, dt.date.day, TRUE);
+                        else {
+                            f++;
+                            if(*(f+1) != 'd') {        //'ddd' - Short day name
+//                                i = 0;
+//                                while(ShortDayNames[dt.date.weekday][i] != 0)
+//                                    *dest++ = ShortDayNames[dt.date.weekday][i++];
+                            } else {
+                                f++;
+//                                i = 0;
+//                                while(LongDayNames[dt.date.weekday][i] != 0)
+//                                    *dest++ = LongDayNames[dt.date.weekday][i++];
+                            }
+                        }
+                    }
+                    break;
+                case 'm':
+                    if(*(f+1) != 'm') {            //'m' - Month with no leading zero
+                        dest += Bcd2Char(dest, dt.date.month, FALSE);
+                    } else {
+                        f++;
+                        if(*(f+1) != 'm')            //'mm' - Month with leading zero
+                            dest += Bcd2Char(dest, dt.date.month, TRUE);
+                        else {
+                            f++;
+                            if(*(f+1) != 'm') {        //'mmm' - Short month name
+//                                i = 0;
+//                                while(ShortMonthNames[dt.date.month - 1][i] != 0)
+//                                    *dest++ = ShortMonthNames[dt.date.month - 1][i++];
+                            } else {
+                                f++;
+//                                i = 0;
+//                                while(LongMonthNames[dt.date.month - 1][i] != 0)
+//                                    *dest++ = LongMonthNames[dt.date.month - 1][i++];
+                            }
+                        }
+                    }
+                    break;
+                case 'y':
+                    if(*(f+1) == 'y') {
+                        f++;                                 //We have at least a 'yy'
+                        if(*(f+1) == 'y' && *(f+2) == 'y') { //'yyyy' - 4 digit year
+                            dest += Bcd2Char(dest, dt.date.century, TRUE);
+                            f += 2;
+                        }
+                        dest += Bcd2Char(dest, dt.date.year, TRUE);
+                    }
+                    break;
+                case 'h':
+                    if(*(f+1) != 'h') {            //'h' - Hour with no leading zero
+                        dest += Bcd2Char(dest, dt.time.hours, FALSE);
+                    } else {
+                        f++;
+                        dest += Bcd2Char(dest, dt.time.hours, TRUE);
+                    }
+                    break;
+                case 'n':
+                    if(*(f+1) != 'n') {            //'m' - Minutes with no leading zero
+                        dest += Bcd2Char(dest, dt.time.minutes, FALSE);
+                    } else {
+                        f++;
+                        dest += Bcd2Char(dest, dt.time.minutes, TRUE);
+                    }
+                    break;
+                case 's':
+                    if(*(f+1) != 's') {            //'s' - Seconds with no leading zero
+                        dest += Bcd2Char(dest, dt.time.seconds, FALSE);
+                    } else {
+                        f++;
+                        dest += Bcd2Char(dest, dt.time.seconds, TRUE);
+                    }
+                    break;
+                case 'z':
+                    if(*(f+1) != 'z') {            //'z' - Hundredths with no leading zero
+                        dest += Bcd2Char(dest, dt.time.hundreds, FALSE);
+                    } else {
+                        f++;
+                        dest += Bcd2Char(dest, dt.time.hundreds, TRUE);
+                    }
+                    break;
+                case '/':
+                    *dest++ = DateSeparator;
+                    break;
+                case ':':
+                    *dest++ = TimeSeparator;
+                    break;
+                case 39 :
+                    while(*++f != 0 && *f != 39) *dest++ = *f;
+                    break;  //Ignore the first '
+                default:
+                    *dest++ = *f;
+                    break;            //Anything we don't recognise, return it
+            }
+            f++;
+        }
+    }
+    *dest = 0;    //Null terminate
+};
+
+bool PCF8583rtc::WriteNVram(char address, char *value, char num)
+{
+    if((address < USER_REG) || (num == 0))       // dont allow overwriting first 2 user bytes
+        return false;
+    
+    _i2c->write(PCF8583_addr, &address, 1); // set the rom address
+    return _i2c->write(PCF8583_addr, value, num);  // write the data
+};
+
+bool PCF8583rtc::ReadNVram(char address, char * dest, char num)
+{
+    if((address < USER_REG) || (num == 0))       // dont allow overwriting first 2 user bytes
+        return false;
+    
+    _i2c->write(PCF8583_addr, &address, 1); // set the rom address
+    _i2c->read(PCF8583_addr, dest, num);    // read the data
+    
+    return true;
+};
+
+/*****************************************************************************/
+/************************** Private Functions ********************************/
+/*****************************************************************************/
+
+char PCF8583rtc::Bcd2Char(char *d, char val, char WantLeadZero)
+{
+    char  n = 0;
+
+    if(WantLeadZero == TRUE || (val / 10) != 0) {
+        *d++ = (val / 10) + 48;
+        n++;
+    }
+    *d = (val % 10) + 48;
+    return(n + 1);
+}
+
+//----------------------------------------------
+// This function converts an 8 bit binary value to a 2 byte BCD value.
+// The input range must be from 0 to 99.
+int PCF8583rtc::bin2bcd(char value)
+{
+    int tmp = 0;
+
+    while(1) {
+        // Get the tens digit by doing multiple subtraction
+        // of 10 from the binary value.
+        if(value >= 10) {
+            value -= 10;
+            tmp += 0x10;
+        } else {  // Get the ones digit by adding the remainder.
+            tmp += value;
+            break;
+        }
+    }
+    return tmp;
+}
+
+void PCF8583rtc::writeByte(char address, char d)
+{
+    _i2c->start();
+    _i2c->write(Write_addr);
+    _i2c->write(address);
+    _i2c->write(d);
+    _i2c->stop();
+}
+
+void PCF8583rtc::configureControlReg(char control)
+{
+    _i2c->start();
+    _i2c->write(Write_addr);
+    _i2c->write(0x00);
+    _i2c->write(control);
+    _i2c->stop();
+}
+
+void PCF8583rtc::configureAlarmReg(char alarm)
+{
+    _i2c->start();
+    _i2c->write(Write_addr);
+    _i2c->write(0x08);
+    _i2c->write(alarm);
+    _i2c->stop();
+}
+
+char PCF8583rtc::readByte(char address)
+{
+    char var;
+    _i2c->start();
+    _i2c->write(Write_addr);
+    _i2c->write(address);
+    _i2c->start();
+    _i2c->write(Read_addr);
+    var = _i2c->read(0) ;
+    _i2c->stop();
+    return var;
+}
+
+void PCF8583rtc::pauseCounting()
+{
+    char tmp;
+    tmp = readByte(0x00);
+    tmp = tmp | 0x80;
+    writeByte(0x00, tmp);
+}
+
+void PCF8583rtc::enableCounting()
+{
+    char tmp;
+    tmp = readByte(0x00);
+    tmp = tmp ^ 0x80;
+    writeByte(0x00, tmp);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PCF8583_rtc.h	Sun Feb 09 00:25:21 2014 +0000
@@ -0,0 +1,165 @@
+#include <mbed.h>
+
+#ifndef rtc_included
+#define rtc_included
+
+#define PCF8583_addr        0xA2     // PCF8583 Write address,
+#define Write_addr          0xA2     // PCF8583 Write address,
+#define Read_addr           0xA3     // PCF8583 Read address
+#define SET_DATE_TIME       0x01
+#define GET_DATE_TIME       0x02
+#define SET_ALARM           0x09
+#define GET_ALARM           0x0A
+#define ON                  1
+#define OFF                 0
+
+#ifndef TRUE
+#define TRUE  1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+//Configuration Alarm Control Register
+#define alarm_enable_bit    0x04
+#define alarm_flag          0x02;
+#define timer_hundsek       0x01
+#define timer_seconds       0x02
+#define timer_minutes       0x03
+#define timer_hours         0x04
+#define timer_days          0x05
+#define timer_int_enable    0x08
+#define daily_alarm         0x10
+#define weekday_alarm       0x20
+#define dated_alarm         0x30
+#define timer_alarm_enable  0x40
+#define alarm_int_enable    0x80
+#define timer_alarm_enable  0x40
+#define alarm_int_enable    0x80
+
+// Use the first 2 NVRAM addresses for the century and year bytes.
+#define CENTURY_REG         0x10
+#define YEAR_REG            0x11
+#define USER_REG            0x12
+
+#define TIME                1
+#define ALARM               9
+
+struct Time_t {
+  char fmt_hours;
+  char am_pm_flag;
+  char hours;
+  char minutes;
+  char seconds;
+  char hundreds;
+};
+
+struct Date_t {
+  char day;
+  char month;
+  char year;
+  char century;
+  char weekday;
+};
+
+struct DateTime_t {
+  struct Date_t date;
+  struct Time_t time;
+};
+
+class PCF8583rtc {
+  I2C *_i2c;
+  
+public:
+  //Set these public variables according to your locale, default is Australia English
+  char *ShortDateFormat;
+  char *LongDateFormat;
+  char *ShortTimeFormat;
+  char *LongTimeFormat;
+
+  char DateSeparator;
+  char TimeSeparator;
+
+  char *ShortDayNames[7];
+  char *LongDayNames[7];
+  char *ShortMonthNames[12];
+  char *LongMonthNames[12];
+    
+  PCF8583rtc(I2C *i2c);
+
+  int  bin2bcd(char value);
+  void read(const char address);
+  void write(const char address);
+  void FormatDateTime(char *dest, char *format);
+  bool WriteNVram(char address, char * value, char num);
+  bool ReadNVram(char address, char * dest, char num);
+  struct DateTime_t GetDateTime(void); 
+  struct DateTime_t GetDateTimeBCD(void); 
+private:
+  struct DateTime_t dt;
+
+  char Bcd2Char(char *d, char val, char WantLeadZero);
+  void enableCounting(void);
+  void pauseCounting(void);
+  char readByte(char address);
+  void writeByte(char address, char d);
+  void configureAlarmReg(char alarm);
+  void configureControlReg(char control);
+};
+
+/** PCF8583_rtc class.
+ *
+ * Example:
+ * @code
+ * #include <mbed.h>
+ * #include <PCF8583_rtc.h>
+ *
+ * I2C i2c(P0_10, P0_11);       // sda, scl
+ * PCF8583rtc rtc(&i2c);
+ *
+ * int main() { 
+ *  
+ * rtc.read(TIME);
+ * i2c.write(ADDR_8574_1, &rtc.HoursBCD, 1);   //write hours to display
+ * i2c.write(ADDR_8574_2, &rtc.MinsBCD, 1);    //write minutes to display
+ * }
+ * @endcode
+ */
+ 
+/** Create a PCF8583rtc object using a pointer to the given I2C object.
+ *
+ * @param i2c pointer to an I2C object to which the PCF8583 device is connected.
+ */
+//PCF8583rtc(I2C *i2c);
+
+/** the Read_DateTime function.
+ *
+ * @param address  Determines whether to read the date/time or alarm registers
+ *                 Values are retrieved from the internal datetime structure
+ */
+//void read(const char address);
+
+/** the Write_DateTime function.
+ *
+ * @param address  Determines whether to set the date/time or alarm registers
+ *                 Values are first set into the internal datetime structure prior to calling
+ */
+//void write(const char address);
+ 
+/** the FormatDateTime function.
+ *
+ * @param dest   a pointer to a char array where formatted values are to be placed
+ * @param format a pointer to a string describing how to format the values 
+ */
+//void FormatDateTime(char *dest, char *format);
+
+/** the WriteNVram function.
+ *
+ * @param address  address where value is to be placed
+ * @param value    pointer to char array containing the value(s) to be stored
+ * @param num      the number bytes to store
+ */
+//void WriteNVram(char address, char *value, char num);
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Sun Feb 09 00:25:21 2014 +0000
@@ -0,0 +1,82 @@
+#include "mbed.h"
+#include "PCF8583_rtc.h"
+
+void NixieDisplay(void);
+//void ChangeTime(void);
+
+DigitalOut Red(P0_7);
+DigitalOut Green(P0_17);
+DigitalOut Blue(P0_16);
+
+I2C i2c(P0_10, P0_11);       // sda, scl
+Serial pc(USBTX, USBRX);     // tx, rx
+Ticker TickerFunc;
+PCF8583rtc rtc(&i2c);
+
+// i2c addresses
+const int ADDR_8574_1 = 0x70;
+const int ADDR_8574_2 = 0x72;
+
+int    alarm    = OFF;
+int    setTimer = OFF;
+
+int main()
+{
+    struct DateTime_t dtBCD;
+
+    Red = Green = Blue = 1;
+//    TickerFunc.attach(&NixieDisplay, 1.0);    // The address of the function to be attached and the interval (1 seconds)
+
+    i2c.frequency(400000);
+    
+    while(1) {
+        rtc.read(TIME);
+        dtBCD = rtc.GetDateTimeBCD();      //get the date and time in BCD form
+        i2c.write(ADDR_8574_1, &dtBCD.time.hours, 1);
+        i2c.write(ADDR_8574_2, &dtBCD.time.minutes, 1);
+       
+        Blue = !Blue;
+        wait(.5);
+//      if(!sw3.read()) {                      // Change Time
+//          ChangeTime();
+//      }
+
+//      pc.printf("Magnet = %d\n", magnet.read());
+    }
+}
+
+void NixieDisplay()
+{
+//    i2c.write(ADDR_8574_1, &HoursBCD, 1);
+//    i2c.write(ADDR_8574_2, &MinsBCD, 1);
+
+    Red = !Red;
+//    time_t seconds = time(NULL);
+//    struct tm *t = localtime(&seconds);
+//
+//    data =  bin2bcd(t.tm_hour);
+//    i2c.writeite(ADDR_8574_1, &data, 1);
+//
+//    data =  bin2bcd(t.tm_min);
+//    i2c.writeite(ADDR_8574_2, &data, 1);
+}
+
+//void ChangeTime() {
+//    time_t seconds = time(NULL);
+//    wait(0.1);
+//    struct tm *t = localtime(&seconds);
+//
+//    while(!sw3.read()) {
+//        if(!sw2.read()) {      //Change Hour
+//          t.tm_hour += 1;
+//        } else {
+//            if(!sw1.read()) {  //Change Minute
+//                t.tm_min += 1;
+//            }
+//        }
+//
+//        set_time(mktime(t));
+//        wait(0.2);
+//    }
+//}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Sun Feb 09 00:25:21 2014 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/a9913a65894f
\ No newline at end of file