/* These functions were written using a CFAG12864S-TMI-V#T Graphic display. Any other display based on the ST7920 controller should work but there's no guarantee. These functions make use of direct port manipulation to maximize the display performance, therfor the pin assignments are hard coded and difficult to change without rewriting the entire thing. By using two high speed shift registers we can make use of the display's 8-bit mode while only using five dedicated arduino pins instead of eleven. Extra hardware: 74HC595 Serial in Parallel Out Shift Register 74HC166 Parallel in Serial Out Shift Register NOTE: The "HC" is important as it designates the chips as "High Speed CMOS" any other version of the chip may not be able to keep up with the arduino. Pin Assignments: Pin 4 :: 74HC595 DS Pin 5 :: 74HC595 Latch :: 74HC166 Parallel enable Pin 6 :: 74HC595 Clock :: 74HC166 Clock Pin 7 :: 74HC166 Serial Out Pin 10:: Display RS Pin 11:: Display RW Pin 12:: Display EN Pin 13:: 74HC595 Output Enable Note: pins 4 - 6 can do anything while the arduino is not changing the EN RW and RS pins. Circuit: The 74HC595's Outputs are connected to the data pins of the Display as well as the 74HC166's Parallel inputs. */ #include #include "Symbols.h" //Display Functions #define GRAPHICS_ENABLE 0x36 #define GRAPHICS_DISABLE 0x32 #define CLEAR 0x01 //define some macros to make things easier to read #define command(n) instruction(n, 0) #define data(n) instruction(n, 1) byte current_x = 0xFF; byte current_y = 0xFF; word lastByte = 0x0000; word current_word = 0x0000; const word deletePixel[16] PROGMEM = {32767, 49151, 57343, 61439, 63487, 64511, 65023, 65279, 65344, 65471, 65503, 65519, 65527, 65531, 65533, 65534}; const word addPixel[16] PROGMEM = {32768, 16384, 8192, 4096, 2048, 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1}; /* instruction(byte, boolean) This is the Low level function that writes commands and data to the display. */ void instruction(byte value, boolean rs) { // //prep the display // digitalWrite(RW, LOW); // digitalWrite(RS, rs); // //prepare the 74595 to accept data // digitalWrite(OE, LOW); #ifdef DEBUG_DISPLAY if(!rs) { if((value & 0xFC) == 0x04) Serial.println("E M S"); else if((value & 0xF8) == 0x08) Serial.println("D S"); else if((value & 0xF0) == 0x10) Serial.println("C D S"); else if((value & 0xE0) == 0x20) Serial.println("F S"); else if((value & 0xFE) == 0x06) Serial.println("S O R A S"); else if(value == 0x01) Serial.println("CLR"); else if((value & 0xF0) == 0x10) Serial.println("C A D S C"); else if((value & 0x80) == 0x80); // Serial.println("S G R A"); } // else // Serial.println("Data"); #endif PORTB &= B11010011; //Clear PB5(OE) PB3(RW) PB2(RS) if(rs) PORTB |= B00000100; // digitalWrite(Latch, LOW); PORTD &= B11011111; //Clear PD5(Latch) // load the register with our data for (int i = 0; i < 8; i++) { if((value & (1 << (7 - i)))) PORTD |= B00010000; else PORTD &= B11101111; PORTD |= B01000000; PORTD &= B10111111; } // digitalWrite(Latch, HIGH); PORTD |= B00100000; //Set PD5(Latch) //finally write the the data // digitalWrite(EN, HIGH); PORTB |= B00010000; //Set PB5(EN) delayMicroseconds(1); // digitalWrite(EN, LOW); PORTB &= B11101111; //Clear PB5(EN) if(value == CLEAR) delay(2); else delayMicroseconds(80); } byte shift_166() { byte value = 0; digitalWrite(PE, LOW); //Enable the load function on 74166 digitalWrite(CP, HIGH); //Load in data digitalWrite(CP, LOW); digitalWrite(PE, HIGH); //Disable load for(int i = 0; i < 8; i++) { value |= digitalRead(SO) << (7 - i); digitalWrite(CP, HIGH); digitalWrite(CP, LOW); } return value; } word read16bits(byte x, byte y) { word ByteBuffer = 0x0000; y |= 0x80; //Set GDRAM Address x |= 0x80; // command(y); // command(x); // digitalWrite(OE, HIGH); //set 74595 outputs to high impedance digitalWrite(RW, HIGH); //This is a read digitalWrite(RS, HIGH); //This is a read digitalWrite(EN, HIGH); //start dummy read delayMicroseconds(1); digitalWrite(EN, LOW); //end dummy read delay(1); digitalWrite(EN, HIGH); //Output data on display pins delayMicroseconds(50); //give the display time to change the pins byte temp = shift_166(); //Shift in data ByteBuffer |= (temp << 8); digitalWrite(EN, LOW); //updata display data delay(1); digitalWrite(EN, HIGH); delayMicroseconds(50); // give the display time to change the pins temp = shift_166(); //Shift in data ByteBuffer |= (temp); digitalWrite(EN, LOW); digitalWrite(RW, LOW); //done with this read digitalWrite(RS, LOW); //done with this read digitalWrite(OE, LOW); //re-enable 74595 outputs return ByteBuffer; //and we're done! } void drawPixelGroup(byte x, byte y, byte value1, byte value2) { if(y > 31) { y -= 32; x += 8; } command(y | 0x80); command(x | 0x80); data(value1); data(value2); } void drawPixel(int x, int y, boolean state) { byte ypos = y; byte xpos = x/16; byte pixel = x % 16; word current = 0x0000; if(xpos == current_x && ypos == current_y) { current = current_word; } else { current = read16bits(xpos, ypos); } current_x = xpos; current_y = ypos; if(state) current |= pgm_read_word(addPixel + pixel); else current |= pgm_read_word(deletePixel + pixel); byte value1 = (current >> 8); byte value2 = current; current_word = current; drawPixelGroup(xpos, ypos, value1, value2); } void ClearG() { #ifdef DEBUG_DISPLAY Serial.println(F("*****Clear Begin*****")); #endif for(int y = 0; y < 64; y++) { drawPixelGroup(0,y,0x00,0x00); for(int i = 2; i < 32; i++) data(0x00); } #ifdef DEBUG_DISPLAY Serial.println(F("*****Clear End*****")); #endif } //Readies the display for use void InitDisplay(boolean Cursor = false) { #ifdef DEBUG_DISPLAY Serial.println(F("*****Init Begin*****")); #endif DDRB |= B00111111; DDRD |= B01110000; PORTB &= B11100011; command(0x30); delayMicroseconds(150); command(0x30); delayMicroseconds(50); command(Cursor? 0x0F : 0x0C); command(CLEAR); command(0x06); delay(500); command(GRAPHICS_ENABLE); #ifdef DEBUG_DISPLAY Serial.println(F("*****Init End*****")); #endif } void lcdPlaceCharacter(byte row, byte col, byte character, boolean invert) { byte startBit = (col * 6) % 8 + 1; for(int x = 0; x < 8; x++) { byte pixels = (invert)? 0xFF:0x00; if(x != 7) { if(invert) pixels = 0x3F & ~(pgm_read_byte(&(font[character - 32][x]))); else pixels = pgm_read_byte(&(font[character - 32][x])); } byte startByte = (x + (row *6)) * 16; if(startBit <= 3) { word bits = pixels << 3 - startBit; LineBuffer[startByte + ((col * 6) / 8)] |= bits; } else { word bits = pixels >> startBit - 3; LineBuffer[startByte + ((col * 6) / 8)] |= bits; // Add character bits = pixels << (11 - startBit); LineBuffer[startByte + ((col * 6) / 8) + 1] |= bits; // Add character } } } void writeLittleText(int x, int y, String string, boolean invert, boolean stopShort = false) { char carray[string.length() + 1]; string.toCharArray(carray, string.length() + 1); //prep line buffer for(byte i = 0; i < 128; i++) { LineBuffer[i] = 0; } for(byte i = 0; i < string.length(); i++) lcdPlaceCharacter(0, i + x, carray[i], invert); for(byte i = 0; i < (stopShort? 6:8) ; i++) { for(byte n = 0; n < 8; n++) { byte xpos = i; byte ypos = n + y*8; if(ypos > 31) { xpos += 8; ypos -= 32; } drawPixelGroup(xpos, ypos, LineBuffer[n*16 + i*2], LineBuffer[n*16 + i*2 + 1]); } } #ifdef DEBUG_DISPLAY Serial.println("Display Output :: " + string); #endif } void drawCheck(int x, int y) { word tword; for(int iy = 0; iy < 24; iy++) { tword = (pgm_read_byte(&(check[iy][0])) << 8) | pgm_read_byte(&(check[iy][1])); drawPixelGroup(x*2, iy + y*20,0x00,tword >> 8); drawPixelGroup(x*2 + 1, iy + y*20,tword,0x00); } #ifdef DEBUG_DISPLAY Serial.println(F("Check Icon drawn")); #endif } void drawWrench(int x, int y) { word tword; for(int iy = 0; iy < 24; iy++) { tword = (pgm_read_byte(&(wrench[iy][0])) << 8) | pgm_read_byte(&(wrench[iy][1])); drawPixelGroup(x*2, iy + y*20,(tword >> 8),tword); drawPixelGroup(x*2 + 1, iy + y*20,pgm_read_byte(&(wrench[iy][2])),0x00); } #ifdef DEBUG_DISPLAY Serial.println(F("Wrench Icon drawn")); #endif } void drawBack() { word tword; for(int iy = 0; iy < 24; iy++) { tword = (pgm_read_byte(&(back[iy][0])) << 8) | pgm_read_byte(&(back[iy][1])); drawPixelGroup(6, iy + 40,0x00,(tword >> 8)); drawPixelGroup(7, iy + 40,tword,0x00); } #ifdef DEBUG_DISPLAY Serial.println(F("Back Icon drawn")); #endif } void drawInfo(int x, int y) { word tword; for(int iy = 0; iy < 24; iy++) { for(int ix = 0; ix < 2; ix++) { tword = (pgm_read_byte(&(info[iy][ix*2])) << 8) | pgm_read_byte(&(info[iy][ix*2+1])); drawPixelGroup(ix + x*2, iy + y*20,(tword >> 8),tword); } } #ifdef DEBUG_DISPLAY Serial.println(F("Info Icon drawn")); #endif } void drawHouse(int x, int y) { word tword; for(int iy = 0; iy < 24; iy++) { tword = (pgm_read_byte(&(house[iy][0])) << 8) | pgm_read_byte(&(house[iy][1])); drawPixelGroup(x*2, iy + y*20,0x00,(tword >> 8)); drawPixelGroup(x*2 + 1, iy + y*20, tword,0x00); } #ifdef DEBUG_DISPLAY Serial.println(F("House Icon drawn")); #endif } void drawControl(int x, int y) { word tword; for(int iy = 0; iy < 24; iy++) { tword = (pgm_read_byte(&(control[iy][0])) << 8) | pgm_read_byte(&(control[iy][1])); drawPixelGroup(x*2, iy + y*20,0x00,(tword >> 8)); drawPixelGroup(x*2 + 1, iy + y*20, tword,0x00); } #ifdef DEBUG_DISPLAY Serial.println(F("Control Icon drawn")); #endif } void drawArrowUp(int x, int y) { word tword; for(int iy = 0; iy < 24; iy++) { tword = (pgm_read_byte(&(arrow[iy][0])) << 8) | pgm_read_byte(&(arrow[iy][1])); drawPixelGroup(x*2, iy + y*20, 0x00,(tword >> 8)); drawPixelGroup(x*2 + 1, iy + y*20,tword,0x00); } #ifdef DEBUG_DISPLAY Serial.println(F("Arrow Up Icon drawn")); #endif } void drawArrowDown(int x, int y) { word tword; for(int iy = 23; iy > 0; iy--) { tword = (pgm_read_byte(&(arrow[iy][0])) << 8) | pgm_read_byte(&(arrow[iy][1])); drawPixelGroup(x*2, 23 - iy + y*20, 0x00,(tword >> 8)); drawPixelGroup(x*2 + 1, 23 - iy + y*20, tword, 0x00); } #ifdef DEBUG_DISPLAY Serial.println(F("Arrow Down Icon drawn")); #endif }