Jump to content
43oh

Time & Temperature on Nokia 7110


Recommended Posts

This uses code from Software RTC, Using the internal temperature sensor and Nokia 5110 template class. The code has been modified and refined a bit for this project.

 

post-2341-135135544588_thumb.jpg

 

main.cpp

#include 
#include 
#include 
#include 

#include "nokia7110tl.h"


using namespace nokia7110;

static const unsigned char ti[] = {
   48, 48 / 8,
   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
   0x00,0x00,0x00,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,
   0xFC,0xFC,0xFC,0xFC,0x00,0x00,0x00,0x00,0x00,0xF0,
   0xF0,0xF0,0xF0,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,
   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,

   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
   0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
   0xFF,0xFF,0xFF,0xFF,0xFC,0xFC,0x3C,0x80,0xFC,0xFD,
   0xFD,0xFD,0x3D,0x81,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,
   0xFC,0xFC,0xFC,0xFC,0x00,0x00,0x00,0x00,

   0x00,0x1C,0x7C,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,
   0xFC,0xFC,0xFC,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
   0xFF,0xFF,0xF7,0xF0,0xF0,0x00,0xF0,0xFF,0xFF,0xFF,
   0xFF,0x0F,0xF0,0xF0,0xF0,0xF0,0xFF,0xFF,0xFF,0xFF,
   0xFF,0xFF,0xFF,0xFF,0xF8,0xF0,0x00,0x00,

   0x00,0x00,0x00,0x00,0x01,0x03,0x07,0x3F,0x7F,0xFF,
   0xFF,0xFF,0xFF,0xFF,0x7F,0x3F,0x3F,0x7F,0xFF,0xFF,
   0xFF,0xFF,0xFF,0x1F,0x00,0x1E,0x1F,0x1F,0x1F,0x1F,
   0x01,0x1E,0x1F,0xDF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
   0xFF,0x7F,0x7F,0x3F,0x3F,0x3F,0x00,0x00,

   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
   0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x03,
   0x0F,0x3F,0xFF,0xFE,0xFE,0xFE,0xFC,0xFC,0xFC,0xFC,
   0xFC,0xFC,0xFC,0x7F,0x1F,0x07,0x03,0x03,0x01,0x00,
   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,

   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
   0x00,0x00,0x00,0x01,0x07,0x0F,0x0F,0x1F,0x1F,0x3F,
   0x3F,0x3F,0x3F,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,
   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};

/*
   P1.0    Reset
   P1.3    Temp Sensor (Not used)
   P2.0    Serial Data
   P2.1    Backlight
   P2.2    Chip Select
   P2.3    Data/Command
   P2.4    Serial Clock
   P2.5    Pushbutton
*/

// P1
static const unsigned LCD_RESET = BIT0;
static const unsigned RXD = BIT2;
static const unsigned SWITCH = BIT3;

// P2
static const unsigned LCD_DATA = BIT0;
static const unsigned LCD_BACKLIGHT = BIT1;
static const unsigned LCD_CE = BIT2;
static const unsigned LCD_DC = BIT3;
static const unsigned LCD_CLK = BIT4;
static const unsigned LCD_BTN = BIT5;


Nokia7110 lcd;


void show_time(const struct tm *t)  // Show time on LCD
{
   static const char *dow[7] = {
       "Sunday",
       "Monday",
       "Tuesday",
       "Wednesday",
       "Thursday",
       "Friday",
       "Saturday"
   };

   int x, w;
   const char *s;
   div_t d;

   if(t->tm_hour < 10) {
       x = -2;
       lcd.fill(0, 0, 9, 2, 0);
       d.rem = t->tm_hour;
   } else {
       x = 3;
       lcd.fill(0, 0, 3, 2, 0);
       d = div(t->tm_hour, 10);
       lcd.pd12(d.quot, x, 0);
   }
   lcd.pd12(d.rem, x + 11, 0);
   lcd.pd12(11, x + 22, 0);
   d = div(t->tm_min, 10);
   lcd.pd12(d.quot, x + 27, 0);
   lcd.pd12(d.rem, x + 38, 0);
   lcd.pd12(11, x + 49, 0);
   d = div(t->tm_sec, 10);
   lcd.pd12(d.quot, x + 54, 0);
   lcd.pd12(d.rem, x + 65, 0);
   lcd.fill(x + 76, 0, 7 - x, 2, 0); 

   if(t->tm_mon < 9) {
       x = -5;
       lcd.fill(0, 2, 6, 2, 0);
       d.rem = t->tm_mon + 1;
   } else {
       x = 0;
       d = div(t->tm_mon + 1, 10);
       lcd.pd12(d.quot, x, 2);
   }
   lcd.pd12(d.rem, x + 11, 2);
   lcd.pd12(13, x + 22, 2);
   d = div(t->tm_mday, 10);
   lcd.pd12(d.quot, x + 30, 2);
   lcd.pd12(d.rem, x + 41, 2);
   lcd.pd12(13, x + 52, 2);
   d = div(t->tm_year % 100, 10);
   lcd.pd12(d.quot, x + 60, 2);
   lcd.pd12(d.rem, x + 71, 2);
   if(x) lcd.fill(x + 82, 2, 1 - x, 2, 0); 

   s = dow[t->tm_wday];
   w = strlen(s) * 6;
   x = (83 - w) >> 1;
   lcd.fill(0, 4, x, 1, 0);
   lcd.print((unsigned char)x, (unsigned char)4, s);
   x += w;
   lcd.fill(x, 4, 83 - x, 1, 0);
}

// Print integer from -999 to 9999 using 12 x 16 font
void print_int(int i, const unsigned y)
{
   if(i < -999 || i > 9999) return;
   const unsigned neg = i < 0;
   if(neg) i = -i;
   div_t d; d.quot = i;
   unsigned x = 48;
   do {
       d = div(d.quot, 10);
       lcd.pd12(d.rem, x -= 12, y);
   } while(d.quot);
   if(neg) lcd.pd12(14, x -= 12, y);
   while(x) lcd.pd12(10, x -= 12, y);
}

// Print integer from -999 to 9999 using 6 x 8 font
void print_int(int i, unsigned x, const unsigned y)
{
   if(i < -999 || i > 9999) return;
   const unsigned e = x;
   x += 24;
   const unsigned neg = i < 0;
   if(neg) i = -i;
   div_t d; d.quot = i;
   do {
       d = div(d.quot, 10);
       lcd.print(x -= 6, y, '0' + d.rem);
   } while(d.quot);
   if(neg) lcd.print(x -= 6, y, '-');
   while(x > e) lcd.print(x -= 6, y, ' ');
}

void draw_bargraph(int f)
{
   int x, y, bg;
   char c;
   unsigned char bgc[9] = { 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF, 0 };
   char *bgl[8] = { "90", "80", "70", "60", "50", "40", "30", "20" };

   x = 20;                                         //
   bg = (f - (x - 5)) * 4 / 5;                     //
   for(y = 7; y >= 0; --y) {                       //
       lcd.pos(83, y);                             //
       if(bg < 0) {
           c = bgc[8];
       } else if (bg > 7) {
           c = bgc[7];
       } else {
           c = bgc[bg];
       }
       lcd.write((unsigned char *)&c, 1, lcd_data); 
       lcd.print(bgl[y], c);
       bg -= 8;
   }                                               //

}

time_t tt;                                              // Time in seconds since epoch
unsigned adc;                                           // ADC value

#pragma vector = WDT_VECTOR                             // - Watchdog timer interrupt vector 
__interrupt void wdt_isr(void)                          // This interrupt will occur once per second
{                                                       //
   ++tt;                                               // Increment time_t
   __bic_SR_register_on_exit(LPM0_bits);               // Wakeup main code
}                                                       //
                                                       //
#pragma vector = ADC10_VECTOR                           // ADC conversion complete interrupt
__interrupt void ADC10_ISR(void)                        //
{                                                       //
   adc = ADC10MEM;                                     // Read ADC
   __bic_SR_register_on_exit(LPM0_bits);               // Wakeup main code
}                                                       //

int main(void)
{
   int x, y;
   char c;
   struct tm ts;
   int dc, dk, df;                                     // Temperature in degrees C, K, and F

   WDTCTL = WDTPW | WDTHOLD;

   P1REN = RXD | SWITCH;
   P1DIR = LCD_RESET; 
   P1OUT = RXD | SWITCH | LCD_RESET;

   P2DIR = LCD_DC | LCD_CE | LCD_CLK | LCD_BACKLIGHT | LCD_DATA;
   P2REN = LCD_BTN;
   P2OUT = LCD_CLK | LCD_DC | LCD_CE | LCD_BACKLIGHT | LCD_BTN;

   ADC10CTL0 = 0;                                      // Configure ADC
   ADC10CTL1 = INCH_10 | ADC10DIV_3;                   //
   ADC10CTL0 = SREF_1 | ADC10SHT_3 | REFON | ADC10ON | ADC10IE;
   ADC10CTL0 |= ADC10IE;                               // Enable ADC conversion complete interrupt
                                                       //
                                                       // 32 kHz xtal loading
   //BCSCTL3 = XCAP_1;                                 // 6 pF (default)
   BCSCTL3 = XCAP_2;                                   // 10 pF
   //BCSCTL3 = XCAP_3;                                 // 12.5 pF
                                                       //
   WDTCTL = WDTPW | WDTTMSEL | WDTCNTCL | WDTSSEL;     // Use WDT as interval timer
   IE1 |= WDTIE;                                       // Enable WDT interrupt
   _EINT();                                            // Enable interrupts
                                                       //
                                                       // Set initial time - there is no UI for this
   ts.tm_hour = 13;                                    // Hour
   ts.tm_min = 37;                                     // Minute
   ts.tm_sec = 42;                                     // Second
   ts.tm_mon = 3;                                      // Month (0 based!)
   ts.tm_mday = 20;                                    // Day of Month
   ts.tm_year = 2012 - 1900;                           // Year
   ts.tm_wday = 5;                                     // Day of Week - Not used by mktime()
   ts.tm_yday = 0;                                     // Not used by mktime()
   ts.tm_isdst = 0;                                    // DST flag - Not used by rtc_tick()
                                                       //
   tt = mktime(&ts);                                   // Convert tm struct to time_t
                                                       //
   lcd.reset();
   lcd.init();
   lcd.clear();

   lcd.print(30, 6, "MSP430");
   lcd.print(18, 7, "Nokia 7110");
   for(x = -47; x < 24; ++x) {
       lcd.bitmap(ti, x, 0);
       __delay_cycles(20000);
   }
   __delay_cycles(2000000);
   for(; x < 96; ++x) {
       lcd.bitmap(ti, x, 0);
       __delay_cycles(20000);
   }

   lcd.clear();
   lcd.print(9, 7, "Character Set");
   x = y = 0;
   lcd.pos(x, y);
   for(c = 32; c < 128; ++c) {
       lcd.print(c);
       if(++x >= 16) x = 0, lcd.pos(x, ++y);
   }
   __delay_cycles(3000000);

   lcd.clear();    
   ts.tm_hour = ts.tm_min = ts.tm_sec = 88;
   ts.tm_mon = 87;
   ts.tm_mday = ts.tm_year = 88;
   ts.tm_wday = 5;
   show_time(&ts);
   lcd.pd12(15, 48, 5); lcd.pd12(17, 59, 5);
   lcd.print(24, 7, "\x7F""C"); lcd.print(66, 7, "\x7F""K");
   print_int(8888, 5); print_int(8888, 0, 7);  print_int(8888, 42, 7);
   for(x = 15; x < 96; ++x) draw_bargraph(x);
   __delay_cycles(3000000);

   lcd.clear();                                        //
   lcd.pd12(15, 48, 5);                                // Degrees
   lcd.pd12(17, 59, 5);                                // F
   lcd.print(24, 7, "\x7F""C");                        // C
   lcd.print(66, 7, "\x7F""K");                        // K
                                                       //
   for(; {                                           // for-ever
       show_time(localtime(&tt));                      // Convert time_t to tm struct and show on LCD
       __bis_SR_register(LPM0_bits + GIE);             // Sleep until WDT interrupt

       ADC10CTL0 |= (ENC | ADC10SC);                   // Begin ADC conversion
       __bis_SR_register(LPM0_bits + GIE);             // Sleep until conversion complete
                                                       //
                                                       // Convert to temperature
       dc = ((27069L * adc) - 18169625L) >> 16;        // Vref = 1.5V
       dk = ((27069L * adc) - 268467L) >> 16;          // Vref = 1.5V
       df = ((48724L * adc) - 30634388L) >> 16;        // Vref = 1.5V
                                                       //
                                                       // Display on LCD
       print_int(df, 5);                               // Degrees F
       print_int(dc, 0, 7);                            // Degrees C
       print_int(dk, 42, 7);                           // Degrees K
       draw_bargraph(df);                              // Deg F Bargraph
   }                                                   //

   return 0;
}

 

nokia7110tl.h - C++ template class for Nokia 7110 (SED1565)

namespace nokia7110 {

unsigned char PNONE;

typedef enum {
   lcd_command = 0,        // Array of one or more commands
   lcd_data = 1,           // Array of one or more bytes of data
   lcd_data_repeat = 2     // One byte of data repeated
} lcd_cmd_type;

template  volatile unsigned char &_EP, unsigned char _CE, volatile unsigned char &_RP, unsigned char _RST, unsigned _RD>
struct Nokia7110
{
   void write(const unsigned char *cmd, unsigned len, const lcd_cmd_type type = lcd_data);
   void reset(void);
   void init(void);
   void home(void);
   void pos(unsigned char x, unsigned char y);
   void clear(unsigned char x = 0);
   void fill(unsigned x, unsigned y, unsigned w, unsigned h, unsigned char z);
   void bitmap(const unsigned char *bmp, signed char x, signed char y, unsigned char w, unsigned char h);
   inline void bitmap(const unsigned char *bmp, signed char x, signed char y) { bitmap(bmp + 2, x, y, bmp[0], bmp[1]); };
   void print(char c);
   inline void print(unsigned char x, unsigned char y, char c) { pos(x, y); print(c); };
   void print(const char *s);
   inline void print(unsigned char x, unsigned char y, const char *s) { pos(x, y); print(s); };
   void print(const char *s, unsigned char m);
   void printv(unsigned char x, unsigned char y, char *s);
   void pd12(unsigned n, unsigned x, unsigned y);
};

template  volatile unsigned char &_EP, unsigned char _CE, volatile unsigned char &_RP, unsigned char _RST, unsigned _RD>
void Nokia7110<_SP, _CLK, _DATA, _CP, _DC, _EP, _CE, _RP, _RST, _RD>::write(const unsigned char *cmd, unsigned len, const lcd_cmd_type type)
{
   register unsigned mask;

   if(&_EP != &PNONE) _EP &= ~_CE;
   do {
       mask = 0x0080;
       do {
           if(*cmd & mask) {
               _SP |= _DATA;
               _SP &= ~_CLK;
           } else {
               _SP &= ~(_CLK | _DATA);
           }
           _SP |= _CLK;
           mask >>= 1;
       } while(!(mask & 1));
       if(&_CP == &PNONE) {
           __delay_cycles(_DC);
       } else {
           if(!type) _CP &= ~_DC;
       }
       if(*cmd & mask) {
           _SP |= _DATA;
           _SP &= ~_CLK;
       } else {
           _SP &= ~(_CLK | _DATA);
       }
       _SP |= _CLK;
       if(&_CP != &PNONE) _CP |= _DC;
       if(!(type & 2)) ++cmd;
   } while(--len);
   if(&_EP != &PNONE) _EP |= _CE;
}

template  volatile unsigned char &_EP, unsigned char _CE, volatile unsigned char &_RP, unsigned char _RST, unsigned _RD>
void Nokia7110<_SP, _CLK, _DATA, _CP, _DC, _EP, _CE, _RP, _RST, _RD>::reset(void)
{
   if(&_RP == &PNONE) {
                                       // --- Set initial state of CLK, DC and CE as needed
                                       // * = output used for reset
       if(&_CP == &PNONE) {
           if(&_EP != &PNONE) {        // CLK*, DATA, CE
               _EP |= _CE;
           } // else                   // CLK*, DATA
       } else {
           if(&_EP != &PNONE) {        // CLK, DATA, DC*, CE
               if(&_SP == &_EP) {
                   _SP |= (_CLK | _CE);
               } else {
                   _SP |= _CLK;
                   _EP |= _CE;
               }
           } else {                    // CLK, DATA, DC*
               _SP |= _CLK;
           }
       }
                                       // --- Reset pulse on CLK or DC as needed
       if(&_CP == &PNONE) {            // No DC port, use CLK to reset
           _SP &= ~_CLK;
           __delay_cycles(_RD);
           _SP |= _CLK;
       } else {                        // Use DC to reset
           _CP &= ~_DC;
           __delay_cycles(_RD);
           _CP |= _DC;
       }
   } else {
       _RP &= ~_RST;
       if(&_EP != &PNONE) {
           if(&_SP == &_EP) {
               _SP |= (_CLK | _CE);
           } else {
               _SP |= _CLK;
               _EP |= _CE;
           }
       } else {
           _SP |= _CLK;
       }
       __delay_cycles(_RD);
       _RP |= _RST;
   }
   __delay_cycles(_RD);
}

template  volatile unsigned char &_EP, unsigned char _CE, volatile unsigned char &_RP, unsigned char _RST, unsigned _RD>
void Nokia7110<_SP, _CLK, _DATA, _CP, _DC, _EP, _CE, _RP, _RST, _RD>::init(void)
{
   static const unsigned char init[] = {
       0xA6, //Display: Normal
       0xA3, //LCD Bias Settings: 1/7
       0xA1, //ADC Selection: Reverse
       0xC0, //Common Output: Normal Direction
       //0xC8, //Common Output: Upside Down
       0x22, //Set the V5 output Voltage
       0x81, //Set Electronic Volume Register
       0x2E, //Power Controller Set
               // Booster circuit: ON
               // Voltage regulator circuit: ON
               // Voltage follower circuit: OFF
       0x2F, //Power Controller Set
               // Voltage follower circuit: ON
       0xE3, //Non-OPeration Command
       0x40, //Set the start line
       0xAF, //LCD On
       //0xA5, //Display All Points: ON
       0xA4, //Display All Points: NORMAL
   };

   write(init, sizeof(init), lcd_command);
}

template  volatile unsigned char &_EP, unsigned char _CE, volatile unsigned char &_RP, unsigned char _RST, unsigned _RD>
void Nokia7110<_SP, _CLK, _DATA, _CP, _DC, _EP, _CE, _RP, _RST, _RD>::home(void)
{
   static const unsigned char home[] = { 0xB0, 0x11, 0x02 };
   write(home, sizeof(home), lcd_command);
}

template  volatile unsigned char &_EP, unsigned char _CE, volatile unsigned char &_RP, unsigned char _RST, unsigned _RD>
void Nokia7110<_SP, _CLK, _DATA, _CP, _DC, _EP, _CE, _RP, _RST, _RD>::pos(unsigned char x, unsigned char y)
{
   unsigned char c[3];
   x += 18;
   c[0] = 0xB0 | y;
   c[1] = 0x10 | (x >> 4);
   c[2] = x & 0x0F;
   write(c, sizeof(c), lcd_command);
}

template  volatile unsigned char &_EP, unsigned char _CE, volatile unsigned char &_RP, unsigned char _RST, unsigned _RD>
void Nokia7110<_SP, _CLK, _DATA, _CP, _DC, _EP, _CE, _RP, _RST, _RD>::clear(unsigned char x)
{
   for(unsigned y = 0; y < 9; ++y) {
       pos(0, y);
       write(&x, 96, lcd_data_repeat);
   }
}

template  volatile unsigned char &_EP, unsigned char _CE, volatile unsigned char &_RP, unsigned char _RST, unsigned _RD>
void Nokia7110<_SP, _CLK, _DATA, _CP, _DC, _EP, _CE, _RP, _RST, _RD>::fill(unsigned x, unsigned y, unsigned w, unsigned h, unsigned char z)
{
   unsigned yy = y + h;
   unsigned char c[3];
   x += 18;
   c[1] = 0x10 | (x >> 4);
   c[2] = (x & 0x0F);
   for(;y < yy; ++y) {
       c[0] = 0xB0 | y;
       write(c, sizeof(c), lcd_command);
       write(&z, w, lcd_data_repeat);
   }
}

template  volatile unsigned char &_EP, unsigned char _CE, volatile unsigned char &_RP, unsigned char _RST, unsigned _RD>
void Nokia7110<_SP, _CLK, _DATA, _CP, _DC, _EP, _CE, _RP, _RST, _RD>::bitmap(const unsigned char *bmp, signed char x, signed char y, unsigned char w, unsigned char h)
{
   unsigned char c[3];
   unsigned char ww;
   if(x < 0) {
       ww = w + x;
       bmp -= x;
       x = 0;
   } else if(x + w >= 96) {
       ww = (96 - x);
   } else {
       ww = w;
   }
   x += 18;
   c[0] = 0xB0 | y;
   c[1] = 0x10 | (x >> 4);
   c[2] = x & 0x0F;
   while(h--) {
       write(c, sizeof(c), lcd_command);
       write(bmp, ww);
       bmp += w;
       ++c[0];
   }
}

static const unsigned char font[96][5] = {
   0x00, 0x00, 0x00, 0x00, 0x00, //
   0x00, 0x00, 0x5F, 0x00, 0x00, // !
   0x00, 0x07, 0x00, 0x07, 0x00, // "
   0x14, 0x7F, 0x14, 0x7F, 0x14, // #
   0x24, 0x2A, 0x7F, 0x2A, 0x12, // $
   0x23, 0x13, 0x08, 0x64, 0x62, // %
   0x36, 0x49, 0x56, 0x20, 0x50, // &
   0x00, 0x08, 0x07, 0x03, 0x00, // '
   0x00, 0x1C, 0x22, 0x41, 0x00, // (
   0x00, 0x41, 0x22, 0x1C, 0x00, // )
   0x2A, 0x1C, 0x7F, 0x1C, 0x2A, // *
   0x08, 0x08, 0x3E, 0x08, 0x08, // +
   0x00, 0x40, 0x38, 0x18, 0x00, // ,
   0x08, 0x08, 0x08, 0x08, 0x08, // -
   0x00, 0x00, 0x60, 0x60, 0x00, // .
   0x20, 0x10, 0x08, 0x04, 0x02, // /
   0x3E, 0x51, 0x49, 0x45, 0x3E, // 0
   0x00, 0x42, 0x7F, 0x40, 0x00, // 1
   0x42, 0x61, 0x51, 0x49, 0x46, // 2
   0x21, 0x41, 0x49, 0x4D, 0x33, // 3
   0x18, 0x14, 0x12, 0x7F, 0x10, // 4
   0x27, 0x45, 0x45, 0x45, 0x39, // 5
   0x3C, 0x4A, 0x49, 0x49, 0x30, // 6
   0x41, 0x21, 0x11, 0x09, 0x07, // 7
   0x36, 0x49, 0x49, 0x49, 0x36, // 8
   0x06, 0x49, 0x49, 0x29, 0x1E, // 9
   0x00, 0x00, 0x14, 0x00, 0x00, // :
   0x00, 0x00, 0x40, 0x34, 0x00, // ;
   0x00, 0x08, 0x14, 0x22, 0x41, // <
   0x14, 0x14, 0x14, 0x14, 0x14, // =
   0x00, 0x41, 0x22, 0x14, 0x08, // >
   0x02, 0x01, 0x51, 0x09, 0x06, // ?
   0x3E, 0x41, 0x5D, 0x59, 0x4E, // @
   0x7C, 0x12, 0x11, 0x12, 0x7C, // A
   0x7F, 0x49, 0x49, 0x49, 0x36, // B
   0x3E, 0x41, 0x41, 0x41, 0x22, // C
   0x7F, 0x41, 0x41, 0x41, 0x3E, // D
   0x7F, 0x49, 0x49, 0x49, 0x41, // E
   0x7F, 0x09, 0x09, 0x09, 0x01, // F
   0x3E, 0x41, 0x49, 0x49, 0x7A, // G
   0x7F, 0x08, 0x08, 0x08, 0x7F, // H
   0x00, 0x41, 0x7F, 0x41, 0x00, // I
   0x20, 0x40, 0x41, 0x3F, 0x01, // J
   0x7F, 0x08, 0x14, 0x22, 0x41, // K
   0x7F, 0x40, 0x40, 0x40, 0x40, // L
   0x7F, 0x02, 0x1C, 0x02, 0x7F, // M
   0x7F, 0x04, 0x08, 0x10, 0x7F, // N
   0x3E, 0x41, 0x41, 0x41, 0x3E, // O
   0x7F, 0x09, 0x09, 0x09, 0x06, // P
   0x3E, 0x41, 0x51, 0x21, 0x5E, // Q
   0x7F, 0x09, 0x19, 0x29, 0x46, // R
   0x26, 0x49, 0x49, 0x49, 0x32, // S
   0x01, 0x01, 0x7F, 0x01, 0x01, // T
   0x3F, 0x40, 0x40, 0x40, 0x3F, // U
   0x1F, 0x20, 0x40, 0x20, 0x1F, // V
   0x3F, 0x40, 0x38, 0x40, 0x3F, // W
   0x63, 0x14, 0x08, 0x14, 0x63, // X
   0x03, 0x04, 0x78, 0x04, 0x03, // Y
   0x61, 0x51, 0x49, 0x45, 0x43, // Z
   0x00, 0x7F, 0x41, 0x41, 0x41, // [
   0x02, 0x04, 0x08, 0x10, 0x20, // '\'
   0x00, 0x41, 0x41, 0x41, 0x7F, // ]
   0x04, 0x02, 0x01, 0x02, 0x04, // ^
   0x80, 0x80, 0x80, 0x80, 0x80, // _
   0x00, 0x03, 0x07, 0x08, 0x00, // '
   0x20, 0x54, 0x54, 0x54, 0x78, // a
   0x7F, 0x28, 0x44, 0x44, 0x38, // b
   0x38, 0x44, 0x44, 0x44, 0x28, // c
   0x38, 0x44, 0x44, 0x28, 0x7F, // d
   0x38, 0x54, 0x54, 0x54, 0x18, // e
   0x00, 0x08, 0x7E, 0x09, 0x02, // f
   0x18, 0xA4, 0xA4, 0xA4, 0x7C, // g
   0x7F, 0x08, 0x04, 0x04, 0x78, // h
   0x00, 0x44, 0x7D, 0x40, 0x00, // i
   0x00, 0x20, 0x40, 0x40, 0x3D, // j
   0x00, 0x7F, 0x10, 0x28, 0x44, // k
   0x00, 0x41, 0x7F, 0x40, 0x00, // l
   0x7C, 0x04, 0x78, 0x04, 0x78, // m
   0x7C, 0x08, 0x04, 0x04, 0x78, // n
   0x38, 0x44, 0x44, 0x44, 0x38, // o
   0xFC, 0x18, 0x24, 0x24, 0x18, // p
   0x18, 0x24, 0x24, 0x18, 0xFC, // q
   0x7C, 0x08, 0x04, 0x04, 0x08, // r
   0x48, 0x54, 0x54, 0x54, 0x24, // s
   0x04, 0x04, 0x3F, 0x44, 0x24, // t
   0x3C, 0x40, 0x40, 0x20, 0x7C, // u
   0x1C, 0x20, 0x40, 0x20, 0x1C, // v
   0x3C, 0x40, 0x30, 0x40, 0x3C, // w
   0x44, 0x28, 0x10, 0x28, 0x44, // x
   0x4C, 0x90, 0x90, 0x90, 0x7C, // y
   0x44, 0x64, 0x54, 0x4C, 0x44, // z
   0x00, 0x08, 0x36, 0x41, 0x00, // {
   0x00, 0x00, 0x77, 0x00, 0x00, // |
   0x00, 0x41, 0x36, 0x08, 0x00, // }
   0x02, 0x01, 0x02, 0x04, 0x02, // ~
   0x00, 0x06, 0x09, 0x09, 0x06, // degrees
};

template  volatile unsigned char &_EP, unsigned char _CE, volatile unsigned char &_RP, unsigned char _RST, unsigned _RD>
void Nokia7110<_SP, _CLK, _DATA, _CP, _DC, _EP, _CE, _RP, _RST, _RD>::print(char c)
{
   write(&font[c - 32][0], 5);
   write(&font[0][0], 1);
}

template  volatile unsigned char &_EP, unsigned char _CE, volatile unsigned char &_RP, unsigned char _RST, unsigned _RD>
void Nokia7110<_SP, _CLK, _DATA, _CP, _DC, _EP, _CE, _RP, _RST, _RD>::print(const char *s)
{
   while(*s) {
       write(&font[*s - 32][0], 5);
       write(&font[0][0], 1);
       ++s;
   }
}

template  volatile unsigned char &_EP, unsigned char _CE, volatile unsigned char &_RP, unsigned char _RST, unsigned _RD>
void Nokia7110<_SP, _CLK, _DATA, _CP, _DC, _EP, _CE, _RP, _RST, _RD>::print(const char *s, unsigned char m)
{
   unsigned char c;
   while(*s) {
       c = font[*s - 32][0] ^ m; write(&c, 1);
       c = font[*s - 32][1] ^ m; write(&c, 1);
       c = font[*s - 32][2] ^ m; write(&c, 1);
       c = font[*s - 32][3] ^ m; write(&c, 1);
       c = font[*s - 32][4] ^ m; write(&c, 1);
       write(&m, 1);
       ++s;
   }
}

template  volatile unsigned char &_EP, unsigned char _CE, volatile unsigned char &_RP, unsigned char _RST, unsigned _RD>
void Nokia7110<_SP, _CLK, _DATA, _CP, _DC, _EP, _CE, _RP, _RST, _RD>::printv(unsigned char x, unsigned char y, char *s)
{
   while(*s) {
       pos(x, y);
       ++y;
       write(&font[*s - 32][0], 5);
       write(&font[0][0], 1);
       ++s;
   }
}

static const unsigned char num11x16[19][11 * 2] = {
   0x00,0xF0,0xFC,0xFE,0x06,0x02,0x06,0xFE,0xFC,0xF0,0x00, // 0
   0x00,0x07,0x1F,0x3F,0x30,0x20,0x30,0x3F,0x1F,0x07,0x00,
   0x00,0x00,0x08,0x0C,0xFC,0xFE,0xFE,0x00,0x00,0x00,0x00, // 1
   0x00,0x20,0x20,0x20,0x3F,0x3F,0x3F,0x20,0x20,0x20,0x00,
   0x00,0x0C,0x0E,0x06,0x02,0x02,0x86,0xFE,0x7C,0x38,0x00, // 2
   0x00,0x30,0x38,0x3C,0x36,0x33,0x31,0x30,0x30,0x38,0x00,
   0x00,0x0C,0x0E,0x86,0x82,0x82,0xC6,0xFE,0x7C,0x38,0x00, // 3
   0x00,0x18,0x38,0x30,0x20,0x20,0x31,0x3F,0x1F,0x0E,0x00,
   0x00,0x00,0xC0,0x20,0x18,0x04,0xFE,0xFE,0xFE,0x00,0x00, // 4
   0x00,0x03,0x02,0x02,0x02,0x22,0x3F,0x3F,0x3F,0x22,0x02,
   0x00,0x00,0x7E,0x7E,0x46,0x46,0xC6,0xC6,0x86,0x00,0x00, // 5
   0x00,0x18,0x38,0x30,0x20,0x20,0x30,0x3F,0x1F,0x0F,0x00,
   0x00,0xC0,0xF0,0xF8,0xFC,0x4C,0xC6,0xC2,0x82,0x00,0x00, // 6
   0x00,0x0F,0x1F,0x3F,0x30,0x20,0x30,0x3F,0x1F,0x0F,0x00,
   0x00,0x06,0x06,0x06,0x06,0x06,0xC6,0xF6,0x3E,0x0E,0x00, // 7
   0x00,0x00,0x00,0x30,0x3C,0x0F,0x03,0x00,0x00,0x00,0x00,
   0x00,0x38,0x7C,0xFE,0xC6,0x82,0xC6,0xFE,0x7C,0x38,0x00, // 8
   0x00,0x0E,0x1F,0x3F,0x31,0x20,0x31,0x3F,0x1F,0x0E,0x00,
   0x00,0x78,0xFC,0xFE,0x86,0x02,0x86,0xFE,0xFC,0xF8,0x00, // 9
   0x00,0x00,0x00,0x21,0x21,0x31,0x1D,0x1F,0x0F,0x03,0x00,
   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 
   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
   0x00,0x70,0x70,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // :
   0x00,0x0E,0x0E,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // .
   0x00,0x38,0x38,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
   0x00,0x00,0x00,0x00,0xC0,0x30,0x0C,0x00,0x00,0x00,0x00, // /
   0x00,0x30,0x0C,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
   0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, // -
   0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
   0x00,0x18,0x3C,0x66,0x66,0x3C,0x18,0x00,0x00,0x00,0x00, // 
   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
   0xF0,0xF8,0x0C,0x06,0x02,0x02,0x02,0x02,0x0E,0x0C,0x00, // C
   0x03,0x07,0x0C,0x18,0x10,0x10,0x10,0x10,0x1C,0x0C,0x00,
   0xFE,0xFE,0x42,0x42,0x42,0x42,0x42,0x42,0x00,0x00,0x00, // F
   0x1F,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
   0xFE,0xFE,0x40,0xE0,0xB0,0x18,0x0C,0x06,0x02,0x00,0x00, // K
   0x1F,0x1F,0x00,0x00,0x01,0x03,0x06,0x0C,0x18,0x10,0x00
};

template  volatile unsigned char &_EP, unsigned char _CE, volatile unsigned char &_RP, unsigned char _RST, unsigned _RD>
void Nokia7110<_SP, _CLK, _DATA, _CP, _DC, _EP, _CE, _RP, _RST, _RD>::pd12(unsigned n, unsigned x, unsigned y)
{
   pos(x, y);   write(num11x16[n], 11, lcd_data);
   pos(x, ++y); write(num11x16[n] + 11, 11, lcd_data);
}

} // namespace

Link to post
Share on other sites
  • 2 weeks later...

Very nice. Thanks for the code. I just got my SugarAddict board and dropped this code in. Works right out of the box.

 

I did find an issue with the 7110 init code. The array init[] has a missing value for the contrast setting. After the 0x81 line, I added an 0x33 for optimum contrast on my display.

 

    static const unsigned char init[] = {
       0xA6, //Display: Normal
       0xA3, //LCD Bias Settings: 1/7
       0xA1, //ADC Selection: Reverse
       0xC0, //Common Output: Normal Direction
       //0xC8, //Common Output: Upside Down
       0x22, //Set the V5 output Voltage
       0x81, //Set Electronic Volume Register
       0x33, //Contrast setting <-- ADD THIS
       0x2E, //Power Controller Set
               // Booster circuit: ON
               // Voltage regulator circuit: ON
               // Voltage follower circuit: OFF
       0x2F, //Power Controller Set
               // Voltage follower circuit: ON
       0xE3, //Non-OPeration Command
       0x40, //Set the start line
       0xAF, //LCD On
       //0xA5, //Display All Points: ON
       0xA4, //Display All Points: NORMAL
   };

 

Randy

Link to post
Share on other sites

Looks like I jumped the gun. :oops: I thought the 0x2E value was "Power control set", like the comments say. It is not, it is the contrast setting. As it turns out, that setting is too low on my hardware. So, don't add the extra line. :)

Very nice. Thanks for the code. I just got my SugarAddict board and dropped this code in. Works right out of the box.

 

I did find an issue with the 7110 init code. The array init[] has a missing value for the contrast setting. After the 0x81 line, I added an 0x33 for optimum contrast on my display.

 

    static const unsigned char init[] = {
       0xA6, //Display: Normal
       0xA3, //LCD Bias Settings: 1/7
       0xA1, //ADC Selection: Reverse
       0xC0, //Common Output: Normal Direction
       //0xC8, //Common Output: Upside Down
       0x22, //Set the V5 output Voltage
       0x81, //Set Electronic Volume Register
       0x33, //Contrast setting <-- ADD THIS
       0x2E, //Power Controller Set
               // Booster circuit: ON
               // Voltage regulator circuit: ON
               // Voltage follower circuit: OFF
       0x2F, //Power Controller Set
               // Voltage follower circuit: ON
       0xE3, //Non-OPeration Command
       0x40, //Set the start line
       0xAF, //LCD On
       //0xA5, //Display All Points: ON
       0xA4, //Display All Points: NORMAL
   };

 

Randy

Link to post
Share on other sites

Some notes on compiling this with msp430-gcc.

 

1) To handle C++ templates in nokia7110tl.h, you need to a version of msp430-gcc with C++ support. If building from sources, configure with --enable_languages=c,c++. The packaged msp430-gcc in recent versions of Ubuntu should already be C++ enabled.

 

To compile C++ code, use msp430-g++ instead of msp430-gcc. You will likely get the error

 

ld: cannot find -lstdc++

 

This is because msp430-g++ links against the C++ standard library by default, which is not included with msp430-gcc. To work around, run msp430-g++ as follows:

 

msp430-g++ -mmcu=msp430g2452 -o time.elf main.cpp -nodefaultlibs -fno-rtti -fno-exceptions -lc -lgcc

 

This tells msp430-g++ not to use default libraries. You then need to explicitly list the default libraries that you need (-lc and -lgcc). -fno-rtti -fno-exceptions eliminates some C++ bloat and reduces code size.

 

2) time.h is not included with msp430-gcc. I used this version which I found somewhere on the internet:

 

typedef	long	time_t;		/* for representing times in seconds 
*/
struct tm {
int	tm_sec;
int	tm_min;
int	tm_hour;
int	tm_mday;
int	tm_mon;
int	tm_year;
int	tm_wday;
int	tm_yday;
int	tm_isdst;
};

const unsigned char	moninit[] = {31, 28, 31, 30, 31, 30, 31, 31, 
30, 31, 30, 31};

static unsigned
dylen(unsigned yr)
{
if(yr%4 || (yr % 100) == 0 && ((yr+300)%400) != 0)
	return(365);
return(366);
}

struct tm *
gmtime(time_t * tp)
{
time_t		t;
static struct tm	tim;

t = *tp;
tim.tm_sec = t % 60L;
t /= 60L;
tim.tm_min = t % 60L;
t /= 60L;
tim.tm_hour = t % 24L;
tim.tm_mday = t / 24L;
tim.tm_wday = (tim.tm_mday + 4) % 7;
tim.tm_year = 70;
while(tim.tm_mday >= dylen(tim.tm_year)) {
	tim.tm_mday -= dylen(tim.tm_year);
	tim.tm_year++;
}
tim.tm_yday = tim.tm_mday;
if(tim.tm_mday >= 59 && dylen(tim.tm_year) == 366)
	tim.tm_mday--;
tim.tm_mon = 0;
while(tim.tm_mday >= moninit[tim.tm_mon]) {
	tim.tm_mday -= moninit[tim.tm_mon];
	tim.tm_mon++;
}
tim.tm_mday++;
return &tim;
}

struct tm *
localtime(time_t * tp)
{
time_t	t;

t = *tp - 7 * 3600L;
return gmtime(&t);
}

 

Notice that there is no mktime function here. Instead, in main.cpp, I set tt to the current unix timestamp (obtained with "date +%s" in Linux). Also, the localtime function here hardcodes my timezone. Change accordingly.

 

3) This original code causes the LCD to go berserk when compiled under msp430-gcc:

 

for(c = 32; c < 128; ++c) {
       lcd.print(c);
       if(++x >= 16) x = 0, lcd.pos(x, ++y);
}

 

That's because c is a signed byte value, and the compiler treats 128 as -1, causing an infinite loop. What you want instead is

 

for(c = 32; c < 128U; ++c) {
       lcd.print(c);
       if(++x >= 16) x = 0, lcd.pos(x, ++y);
}

 

Hope this will be useful to somebody.

Link to post
Share on other sites
  • 4 weeks later...

I may be missing something, but it looks like you copied oPossum's code verbatim and then added the following header to his code:

 

// Project Nokia7110_430b

// Created by Rei VILO on 26/05/12

// Copyright © 2012 http://embeddedcomputing.weebly.com

 

https://github.com/energia/Energia/blob ... _library.h

 

Please give proper attribution to oPossum in all source files that use his code.

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...