// File Name : lcd.c
//=================================================================================
// LCD
// PortA is output for data, and PortD is output for control
// PortA: PA
// PD7 PD6 PD5 PD4 PD3 PD2 PD1 PD0
// - - Cnt RS R/W E - -
// PA7 PA6 PA5 PA4 PA3 PA2 PA1 PA0
// D7 D6 D5 D4 D3 D2 D1 D0
//
// Reference at
// http://www.stanford.edu/class/ee281/projects/aut2001/remotecontrol/code.htm
//
// By: Gang Xie
// Courtesy of Pascal Stang: some segments/functions are directly from Pascal.
//=================================================================================
#ifndef WIN32
#include
#include
#include
#include
#endif
#include "lcd.h"
#include "timer.h"
// custom LCD characters
static unsigned char __attribute__ ((progmem)) LcdCustomChar[] =
{
0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, // 0. 0/5 full progress block
0x00, 0x1F, 0x10, 0x10, 0x10, 0x10, 0x1F, 0x00, // 1. 1/5 full progress block
0x00, 0x1F, 0x18, 0x18, 0x18, 0x18, 0x1F, 0x00, // 2. 2/5 full progress block
0x00, 0x1F, 0x1C, 0x1C, 0x1C, 0x1C, 0x1F, 0x00, // 3. 3/5 full progress block
0x00, 0x1F, 0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x00, // 4. 4/5 full progress block
0x00, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x00, // 5. 5/5 full progress block
0x03, 0x07, 0x0F, 0x1F, 0x0F, 0x07, 0x03, 0x00, // 6. rewind arrow
0x00, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x00, // 7. stop block
0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x00, // 8. pause bars
0x18, 0x1C, 0x1E, 0x1F, 0x1E, 0x1C, 0x18, 0x00, // 9. fast-forward arrow
0x00, 0x04, 0x04, 0x0E, 0x0E, 0x1F, 0x1F, 0x00, // 10. scroll up arrow
0x00, 0x1F, 0x1F, 0x0E, 0x0E, 0x04, 0x04, 0x00, // 11. scroll down arrow
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 12. blank character
0x00, 0x0E, 0x19, 0x15, 0x13, 0x0E, 0x00, 0x00, // 13. animated play icon frame 0
0x00, 0x0E, 0x15, 0x15, 0x15, 0x0E, 0x00, 0x00, // 14. animated play icon frame 1
0x00, 0x0E, 0x13, 0x15, 0x19, 0x0E, 0x00, 0x00, // 15. animated play icon frame 2
0x00, 0x0E, 0x11, 0x1F, 0x11, 0x0E, 0x00, 0x00, // 16. animated play icon frame 3
};
#define LCD_DELAY asm volatile ("nop"); asm volatile ("nop")
extern RtcTimeType gRtcTime;
extern PumpInfoType gPumpInfo;
extern SysStateType gSysState;
extern RtcTimeType gAlarmTime;
//---------------------------------------------------------------------------------
//---------------------------------------------------------------------------------
void lcdInitHW(void)
{
// initialize I/O portss
// initialize LCD control lines
cbi(LCD_CTRL_PORT, LCD_CTRL_RS);
cbi(LCD_CTRL_PORT, LCD_CTRL_RW);
cbi(LCD_CTRL_PORT, LCD_CTRL_E);
//This line is necessary in my LCD. Maybe some bits should be initialized.
outb(LCD_CTRL_DDR, 0xFF);
// initialize LCD control lines to output
sbi(LCD_CTRL_DDR, LCD_CTRL_RS);
sbi(LCD_CTRL_DDR, LCD_CTRL_RW);
sbi(LCD_CTRL_DDR, LCD_CTRL_E);
// initialize LCD data port to input
// initialize LCD data lines to pull-up
outb(LCD_DATA_DDR, 0x00); // set data I/O lines to input (8bit)
outb(LCD_DATA_POUT, 0xFF); // set pull-ups to on (8bit)
}
//---------------------------------------------------------------------------------
//---------------------------------------------------------------------------------
void lcdBusyWait(void)
{
// wait until LCD busy bit goes to zero
// do a read from control register
cbi(LCD_CTRL_PORT, LCD_CTRL_RS); // set RS to "control"
outb(LCD_DATA_DDR, 0x00); // set data I/O lines to input (8bit)
outb(LCD_DATA_POUT, 0xFF); // set pull-ups to on (8bit)
sbi(LCD_CTRL_PORT, LCD_CTRL_RW); // set R/W to "read"
sbi(LCD_CTRL_PORT, LCD_CTRL_E); // set "E" line
LCD_DELAY; // wait
while(inp(LCD_DATA_PIN) & 1<=0
// y >=0
//---------------------------------------------------------------------------------
void lcdGotoXY(u08 x, u08 y)
{
register u08 DDRAMAddr;
// remap lines into proper order
switch(y)
{
case 0: DDRAMAddr = LCD_LINE0_DDRAMADDR+x; break;
case 1: DDRAMAddr = LCD_LINE1_DDRAMADDR+x; break;
case 2: DDRAMAddr = LCD_LINE2_DDRAMADDR+x; break;
case 3: DDRAMAddr = LCD_LINE3_DDRAMADDR+x; break;
default: DDRAMAddr = LCD_LINE0_DDRAMADDR+x;
}
// set data address
lcdControlWrite(1< pixelprogress )
{
// this is a partial or empty block
if( ((i*PROGRESSPIXELS_PER_CHAR)) > pixelprogress )
{
// this is an empty block
// use space character?
c = 0;
}
else
{
// this is a partial block
c = pixelprogress % PROGRESSPIXELS_PER_CHAR;
}
}
else
{
// this is a full block
c = 5;
}
// write character to display
lcdDataWrite(c);
}
}
//---------------------------------------------------------------------------------
//---------------------------------------------------------------------------------
void lcdInitDisp(void)
{
//012345678901234567890123
//??/??/????-??? ??:??:??
lcdDispTwoDgtls(0, 0, gRtcTime.month);
lcdDispChar(2, 0, 0x2F); ///
lcdDispTwoDgtls(3, 0, gRtcTime.day);
lcdDispChar(5, 0, 0x2F); ///
lcdDispFourDgtls(6, 0, gRtcTime.year);
lcdDispChar(10, 0, 0x2D); //-
lcdDispDay(11, 0, gRtcTime.sunsat);
lcdDispTwoDgtls(16, 0, gRtcTime.hour);
lcdDispChar(18, 0, 0x3A); //:
lcdDispTwoDgtls(19, 0, gRtcTime.minute);
lcdDispChar(21, 0, 0x3A); //:
lcdDispTwoDgtls(22, 0, gRtcTime.second);
lcdDispPumpInfo();
}
//---------------------------------------------------------------------------------
//---------------------------------------------------------------------------------
void lcdUpdateDisp(void)
{
u08 x, y;
u08 all = 0;
//whether to redraw a whole screen
if (gSysState.displayPage != gSysState.displayPrevPage)
{
all = 1;
lcdClear();
gSysState.displayPrevPage = gSysState.displayPage;
}
//display on LCD
if (gSysState.displayPage == kPage0_Norm)
{
//if previously another page was showed
if (all)
lcdInitDisp();
else
{
// first line
//012345678901234567890123
//mm/dd/yyyy-sun hh:mm:ss
if (gSysState.update_rtc_month)
{
lcdDispTwoDgtls(0, 0, gRtcTime.month);
gSysState.update_rtc_month = 0;
}
if (gSysState.update_rtc_day)
{
lcdDispTwoDgtls(3, 0, gRtcTime.day);
lcdDispDay(11, 0, gRtcTime.sunsat);
gSysState.update_rtc_day = 0;
}
if (gSysState.update_rtc_year)
{
lcdDispFourDgtls(6, 0, gRtcTime.year);
gSysState.update_rtc_year = 0;
}
if (gSysState.update_rtc_sunsat)
{
lcdDispDay(11, 0, gRtcTime.sunsat);
gSysState.update_rtc_sunsat = 0;
}
if (gSysState.update_rtc_hour)
{
lcdDispTwoDgtls(16, 0, gRtcTime.hour);
gSysState.update_rtc_hour = 0;
}
if (gSysState.update_rtc_minute)
{
lcdDispTwoDgtls(19, 0, gRtcTime.minute);
gSysState.update_rtc_minute = 0;
}
if (gSysState.update_rtc_second)
{
lcdDispTwoDgtls(22, 0, gRtcTime.second);
gSysState.update_rtc_second = 0;
}
if (gSysState.update_info)
{
lcdDispPumpInfo();
gSysState.update_info = 0;
}
}
}
else
{
switch (gSysState.displayPage)
{
case kPage1_Alarm: lcdDispAlarm(all); break;
case kPage2_PumpActive: lcdDispPumpActive(all); break;
case kPage3_PumpDuration: lcdDispPumpDuration(all); break;
case kPage4_PumpFreq: lcdDispPumpFrequency(all); break;
case kPage5_PumpNext: lcdDispPumpNext(all); break;
}
}
//blink the cursor
if (gSysState.displayState == kState_Edit)
{
switch (gSysState.displayPage)
{
case kPage0_Norm:
//012345678901234567890123
//mm/dd/yyyy-sun hh:mm:ss
y = 0;
switch (gSysState.fieldAdjusted)
{
case 0: x = 1; break;
case 1: x = 4; break;
case 2: x = 9; break;
case 3: x = 13; break;
case 4: x = 17; break;
case 5: x = 20; break;
default:x = 23; break;
}
break;
case kPage1_Alarm:
//012345678901234567890123
//Alarm at: ??:??:??
//Sound: o?? *----
switch (gSysState.fieldAdjusted)
{
case 0: x = 11; y = 0; break;
case 1: x = 14; y = 0; break;
case 2: x = 17; y = 0; break;
default:x = 7; y = 1; break;
}
break;
case kPage2_PumpActive:
//012345678901234567890123
//Pump: active/inactive
//Sound: o?? -*---
switch (gSysState.fieldAdjusted)
{
case 0: x = 6; y = 0; break;
default:x = 7; y = 1; break;
}
break;
case kPage3_PumpDuration:
//012345678901234567890123
//Pump for ?? minutes and
//?? seconds --*--
switch (gSysState.fieldAdjusted)
{
case 0: x = 10; y = 0; break;
default:x = 1; y = 1; break;
}
break;
case kPage4_PumpFreq:
//012345678901234567890123
//every ?? days ?? hours
//and ?? minutes ---*-
switch (gSysState.fieldAdjusted)
{
case 0: x = 7; y = 0; break;
case 1: x = 15; y = 0; break;
default:x = 5; y = 1; break;
}
break;
default: // kPage5_PumpNext:
switch (gSysState.fieldAdjusted)
{
case 0: x = 17; y = 0; break;
case 1: x = 20; y = 0; break;
case 2: x = 23; y = 0; break;
case 3: x = 4; y = 1; break;
case 4: x = 7; y = 1; break;
default:x = 12; y = 1; break;
}
break;
}
lcdGotoXY(x, y);
lcdBlinkCursor();
}
}
//---------------------------------------------------------------------------------
//---------------------------------------------------------------------------------
void lcdDispDay(u08 x, u08 y, u08 sunsat)
{
switch (sunsat)
{
case 0: lcdDispStr(x, y, "Sun"); break;
case 1: lcdDispStr(x, y, "Mon"); break;
case 2: lcdDispStr(x, y, "Tue"); break;
case 3: lcdDispStr(x, y, "Wed"); break;
case 4: lcdDispStr(x, y, "Thu"); break;
case 5: lcdDispStr(x, y, "Fri"); break;
default: lcdDispStr(x, y, "Sat"); break;
}
}
//---------------------------------------------------------------------------------
//---------------------------------------------------------------------------------
void lcdDispPumpInfo(void)
{
u16 tmp;
if ((gSysState.pumpActivated == 1) && (gPumpInfo.duration.year > 0))
{
tmp = gPumpInfo.totDurInSeconds - gPumpInfo.duration.year;
lcdGotoXY(0,1);
lcdProgressBar(tmp, gPumpInfo.totDurInSeconds, 24);
return;
}
//012345678901234567890123
switch (gSysState.update_info_num)
{
case 0: lcdDispStr(0, 1, " Welcome !"); break;
case 1: lcdDispStr(0, 1, " Welcome ! "); break;
case 2: lcdDispStr(0, 1, " Welcome ! "); break;
case 3: lcdDispStr(0, 1, " Welcome ! "); break;
case 4: lcdDispStr(0, 1, " Welcome ! "); break;
case 5: lcdDispStr(0, 1, " Welcome ! "); break;
case 6: lcdDispStr(0, 1, " Welcome ! "); break;
case 7: lcdDispStr(0, 1, " Welcome ! "); break;
case 8: lcdDispStr(0, 1, " Welcome ! "); break;
case 9: lcdDispStr(0, 1, " Welcome ! "); break;
case 10: lcdDispStr(0, 1, " Welcome ! "); break;
case 11: lcdDispStr(0, 1, " Welcome ! "); break;
case 12: lcdDispStr(0, 1, " Welcome ! "); break;
case 13: lcdDispStr(0, 1, " Welcome ! "); break;
case 14: lcdDispStr(0, 1, " Welcome ! "); break;
case 15: lcdDispStr(0, 1, "Welcome ! "); break;
case 16:
case 17:
case 18:
if (gSysState.pumpActivated)
{
//012345678901234567890123
//Next pump on mm/dd hh:mm
lcdDispStr(0, 1, "Next pump on / : ");
lcdDispTwoDgtls(13, 1, gPumpInfo.next.month);
lcdDispTwoDgtls(16, 1, gPumpInfo.next.day);
lcdDispTwoDgtls(19, 1, gPumpInfo.next.hour);
lcdDispTwoDgtls(22, 1, gPumpInfo.next.minute);
}
else
lcdDispStr(0, 1, "The pump is inactive. ");
break;
case 19:
case 20:
case 21:
//012345678901234567890123
//lcdDispStr(0, 1, " Stanford EE281 Project ");
lcdDispStr(0, 1, " Gang loves Yue . ");
break;
}
}
//---------------------------------------------------------------------------------
//---------------------------------------------------------------------------------
void lcdDispAlarm(u08 all)
{
// first line
//012345678901234567890123
//Alarm at: ??:??:??
if (all)
lcdDispStr(0, 0, "Alarm at:");
if (all || gSysState.update_alm_hour)
{
gSysState.update_alm_hour = 0;
lcdDispTwoDgtls(10, 0, gAlarmTime.hour);
}
if (all)
lcdDispChar(12, 0, 0x3A); //:
if (all || gSysState.update_alm_minute)
{
gSysState.update_alm_minute = 0;
lcdDispTwoDgtls(13, 0, gAlarmTime.minute);
}
if (all)
lcdDispChar(15, 0, 0x3A); //:
if (all || gSysState.update_alm_second)
{
gSysState.update_alm_second = 0;
lcdDispTwoDgtls(16, 0, gAlarmTime.second);
}
// second line
//012345678901234567890123
//Sound: o?? *----
if (all)
lcdDispStr(0, 1, "Sound:");
if (all || gSysState.update_alm_sound)
{
gSysState.update_alm_sound = 0;
if (gSysState.alarmOn)
lcdDispStr(7, 1, "on ");
else
lcdDispStr(7, 1, "off");
}
if (all)
lcdDispStr(19, 1, "*----");
all = 0;
}
//---------------------------------------------------------------------------------
//---------------------------------------------------------------------------------
void lcdDispPumpActive(u08 all)
{
// first line
//012345678901234567890123
//Pump: active/inactive
if (all)
lcdDispStr(0, 0, "Pump:");
if (all || gSysState.update_pa_active)
{
gSysState.update_pa_active = 0;
if (gSysState.pumpActivated)
lcdDispStr(6, 0, "active ");
else
lcdDispStr(6, 0, "inactive");
}
// second line
//012345678901234567890123
//Sound: o?? -*---
if (all)
lcdDispStr(0, 1, "Sound:");
if (all || gSysState.update_pa_sound)
{
gSysState.update_pa_sound = 0;
if (gSysState.pumpSoundOn)
lcdDispStr(7, 1, "on ");
else
lcdDispStr(7, 1, "off");
}
if (all)
lcdDispStr(19, 1, "-*---");
all = 0;
}
//---------------------------------------------------------------------------------
//---------------------------------------------------------------------------------
void lcdDispPumpDuration(u08 all)
{
// first line
//012345678901234567890123
//Pump for ?? minutes and
if (all)
lcdDispStr(0, 0, "Pump for");
if (all || gSysState.update_pd_minute)
{
gSysState.update_pd_minute = 0;
lcdDispTwoDgtls(9, 0, gPumpInfo.duration.minute);
}
if (all)
lcdDispStr(12, 0, "minutes and");
//012345678901234567890123
//?? seconds --*--
if (all || gSysState.update_pd_second)
{
gSysState.update_pd_second = 0;
lcdDispTwoDgtls(0, 1, gPumpInfo.duration.second);
}
if (all)
lcdDispStr(3, 1, "seconds");
if (all)
lcdDispStr(19, 1, "--*--");
}
//---------------------------------------------------------------------------------
//---------------------------------------------------------------------------------
void lcdDispPumpFrequency(u08 all)
{
// first line
//012345678901234567890123
//every ?? days ?? hours
if (all)
lcdDispStr(0, 0, "every");
if (all || gSysState.update_pf_day)
{
gSysState.update_pf_day = 0;
lcdDispTwoDgtls(6, 0, gPumpInfo.frequency.day);
}
if (all)
lcdDispStr(9, 0, "days");
if (all || gSysState.update_pf_hour)
{
gSysState.update_pf_hour = 0;
lcdDispTwoDgtls(14, 0, gPumpInfo.frequency.hour);
}
if (all)
lcdDispStr(17, 0, "hours");
//012345678901234567890123
//and ?? minutes. ---*-
if (all)
lcdDispStr(0, 1, "and");
if (all || gSysState.update_pf_minute)
{
gSysState.update_pf_minute = 0;
lcdDispTwoDgtls(4, 1, gPumpInfo.frequency.minute);
}
if (all)
lcdDispStr(7, 1, "minutes.");
if (all)
lcdDispStr(19, 1, "---*-");
}
//---------------------------------------------------------------------------------
//---------------------------------------------------------------------------------
void lcdDispPumpNext(u08 all)
{
// first line
//012345678901234567890123
//Next pump is at ??:??:??
if (all)
lcdDispStr(0, 0, "Next pump is at");
if (all || gSysState.update_pn_hour)
{
gSysState.update_pn_hour = 0;
lcdDispTwoDgtls(16, 0, gPumpInfo.next.hour);
}
if (all)
lcdDispChar(18, 0, 0x3A); //:
if (all || gSysState.update_pn_minute)
{
gSysState.update_pn_minute = 0;
lcdDispTwoDgtls(19, 0, gPumpInfo.next.minute);
}
if (all)
lcdDispChar(21, 0, 0x3A); //:
if (all || gSysState.update_pn_second)
{
gSysState.update_pn_second = 0;
lcdDispTwoDgtls(22, 0, gPumpInfo.next.second);
}
//012345678901234567890123
//on ??/??/????. ----*
if (all)
lcdDispStr(0, 1, "on");
if (all || gSysState.update_pn_month)
{
gSysState.update_pn_month = 0;
lcdDispTwoDgtls(3, 1, gPumpInfo.next.month);
}
if (all)
lcdDispChar(5, 1, 0x2F); ///
if (all || gSysState.update_pn_day)
{
gSysState.update_pn_day = 0;
lcdDispTwoDgtls(6, 1, gPumpInfo.next.day);
}
if (all)
lcdDispChar(8, 1, 0x2F); ///
if (all || gSysState.update_pn_year)
{
gSysState.update_pn_year = 0;
lcdDispFourDgtls(9, 1, gPumpInfo.next.year);
}
if (all)
lcdDispChar(13, 1, 0x2E);
if (all)
lcdDispStr(19, 1, "----*");
}