Grey-scale rendering
From Gamebuino Wiki
The following is outdated as the GREY color is now part of the core library. Please refer to gb.display.setColor.
The following code shows how to display 3 colors on the Gamebuino LCD: black, white and grey. It achieves this by alternating the color of the grey pixels across subsequent frames. The demo also scrolls the background to show that real-time flicker-free full-screen rendering is indeed possible.
The image in this demo was provided by Gamebuino Forum user Erico and is a concept mock-up of a "Moon Patrol" style game. A video of this demo in action can be found at https://www.youtube.com/watch?v=JHqHEXQQD6M
// Gamebuino full-screen grey-scale rendering demo - by Mark Feldman (aka "Myndale") // // Based on the PCD8544 display code at http://playground.arduino.cc/Code/PCD8544 #include <TimerOne.h> // enable this to scroll the image horizontally every frame #define SCROLLING // when this is enable only the bottom 40 rows are scrolled #define SCORE_BAR // how often to update the screen, 41 seems to be the magic number to minimize flicker #define FRAME_RATE 41 #define PIN_SCE A1 #define PIN_RESET A0 #define PIN_DC A2 #define PIN_SDIN 11 #define PIN_SCLK 13 #define PIN_BACKLIGHT 5 #define PORT_SCLK PORTB #define SCLK_BIT 5 #define PORT_SDIN PORTB #define SDIN_BIT 3 #define LCD_C LOW #define LCD_D HIGH #define LCD_X 84 #define LCD_Y 48 #define LCD_CMD 0 int frame = 0; // which of the two buffer's we're displaying int ofs = 0; // horizontal offset, mainly used for scrolling // declare two display buffers, the interrupt will use then to update the LCD // this isn't the most memory-efficient way of representing a 3-color screen // but it'll work fine for this demo byte buffers[2][LCD_X*LCD_Y/8] = { { 0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef, 0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0x0f,0x0f,0xef,0xaf,0xef,0x0f,0xef,0xaf,0xef,0x0f,0x2f, 0xef,0x2f,0x0f,0x0f,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0x0f,0x0f,0xcf,0x4f, 0xef,0x0f,0x2f,0xef,0x2f,0x0f,0x2f,0xef,0x8f,0x0f,0xef,0x6f,0x6f,0x0f,0x6f,0xef,0xef,0x0f,0xef,0xaf,0xef, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xef, 0xd7,0xc7,0xd7,0xc7,0xd7,0xef,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfa,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdf,0xef,0xe7,0xfb,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xef,0xcf,0xbf,0x9f,0xbf,0xcf,0xef,0xff,0xff,0xff,0xff,0xfe,0xfd,0xfc,0xfd,0xfe,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xf9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0x7f,0xff,0x7f,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xfe,0xff,0xfe,0xfd,0xfa,0xfc,0xf8,0xf8,0xfc,0xfe,0xfe,0xfe,0x7f,0x7f,0xff,0xff,0xff,0x7f,0x7f,0xfe, 0xff,0xfe,0xfd,0xfa,0xf0,0xf8,0xf8,0xc8,0xfd,0xfc,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe, 0xfc,0xfe,0xfc,0xfe,0xfc,0xfc,0xf8,0xf4,0xf8,0xf4,0xf8,0xf0,0xe8,0xf0,0xc0,0x80,0xc0,0xf0,0xf8,0xfc,0xfe, 0xfe,0xfe,0xfe,0xfe,0xfe,0xfc,0xfa,0xe0,0xf0,0xf8,0xfc,0xfe,0xfe,0xfe,0xff,0xff,0xff,0xff,0xfe,0xfe,0xfe, 0x00,0x00,0x00,0x00,0x07,0x01,0x3f,0x03,0x07,0x05,0x05,0x02,0x02,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x19,0x00,0x01,0x01,0x01,0x01,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,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x1f,0x1f,0x1f,0x7f,0xff,0xff,0xff,0xbf,0xbf,0xbf,0xff,0xbf,0xbf,0x3f,0x9f,0x7f,0x1f,0x1f,0x1f,0x1f,0x1f, 0x1f,0x1f,0x1f,0x0f,0x0f,0x0f,0x0f,0x0f,0xdf,0xef,0xff,0xef,0xff,0x6f,0x5f,0xcf,0x0f,0x0f,0x4f,0xaf,0x4f, 0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x0f,0x07,0x01,0x00,0x00,0x00,0x00,0x00, 0x00,0x01,0x07,0x0f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x0f,0x0f,0x0f,0x1f,0x1f,0x1f, }, { 0xef,0x4f,0x4f,0x4f,0x4f,0x4f,0xcf,0x4f,0x4f,0x4f,0x0f,0x0f,0x8f,0x0f,0x0f,0x0f,0x0f,0x0f,0x8f,0x0f,0x0f, 0x0f,0x0f,0x0f,0x8f,0x0f,0x0f,0x0f,0x0f,0x0f,0x8f,0x0f,0x0f,0xef,0xaf,0xef,0x0f,0xef,0xaf,0xef,0x0f,0x2f, 0xef,0x2f,0x0f,0x0f,0x0f,0x2f,0x6f,0x2f,0x0f,0x2f,0x6f,0x2f,0x0f,0x2f,0x6d,0x2f,0x0f,0x0f,0x0f,0xcf,0x4f, 0xef,0x0f,0x2f,0xef,0x2f,0x0f,0x2f,0xef,0x8f,0x0f,0xef,0x6f,0x6f,0x0f,0x6f,0xef,0xef,0x0f,0xef,0xaf,0xef, 0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xef, 0xd7,0xc7,0xc7,0xc7,0xd7,0xef,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf8,0xf8,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xcf,0xcf,0xe7,0xe1,0x99,0x9f,0xff,0xff,0xff,0xff,0xff,0xf7,0xff,0xff,0xff, 0xff,0xff,0xff,0xef,0xcf,0x9f,0x9f,0x9f,0xcf,0xef,0xff,0xff,0xff,0xff,0xfe,0xbc,0xfc,0xfc,0xfe,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xf9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x3f,0x7f,0x7f,0x3f,0x3f,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xfe,0xfc,0xdc,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xfc,0xfe,0xfe,0xfe,0x7f,0x7f,0xff,0xff,0xfe,0x7e,0x7e,0xfc, 0xfc,0xf8,0xf0,0xf0,0xf0,0xf8,0xf8,0xc8,0xfd,0xfc,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0x7e,0xfc,0xfc,0xfc, 0xfc,0xfc,0xf8,0xf8,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xe0,0xe0,0xc0,0xc0,0x80,0x80,0xc0,0xf0,0xf8,0xfc,0xfe, 0xfe,0xfe,0xfc,0xfc,0xf8,0xf0,0xe0,0xe0,0xf0,0xf8,0xfc,0xfe,0xfe,0xfe,0xff,0xff,0xff,0xff,0xfe,0xfe,0xfe, 0x00,0x00,0x00,0x00,0x07,0x01,0x3f,0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x19,0x00,0x00,0x01,0x01,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,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x1f,0x1e,0x1d,0x7e,0xfd,0xda,0x14,0x08,0x12,0x08,0x00,0x10,0x00,0x10,0x00,0x10,0x10,0x10,0x10,0x18,0x10, 0x10,0x18,0x10,0x08,0x08,0x08,0x08,0x08,0x58,0xe8,0x58,0xe8,0xd8,0x68,0x58,0xc8,0x08,0x08,0x48,0xa8,0x48, 0x10,0x18,0x10,0x10,0x18,0x10,0x10,0x10,0x18,0x12,0x10,0x1a,0x15,0x0b,0x07,0x01,0x00,0x00,0x00,0x00,0x00, 0x00,0x01,0x07,0x0b,0x15,0x1a,0x10,0x12,0x18,0x10,0x18,0x10,0x10,0x18,0x10,0x08,0x08,0x08,0x10,0x18,0x10 } }; void LcdClear(void) { for (int index = 0; index < LCD_X * LCD_Y / 8; index++) { LcdWrite(LCD_D, 0x00); } } void LcdInitialise(void) { pinMode(PIN_SCE, OUTPUT); pinMode(PIN_RESET, OUTPUT); pinMode(PIN_DC, OUTPUT); pinMode(PIN_SDIN, OUTPUT); pinMode(PIN_SCLK, OUTPUT); digitalWrite(PIN_RESET, LOW); digitalWrite(PIN_RESET, HIGH); LcdWrite( LCD_CMD, 0x21 ); // LCD Extended Commands. LcdWrite( LCD_CMD, 0xB9 ); // Set LCD Vop (Contrast). //B1 LcdWrite( LCD_CMD, 0x04 ); // Set Temp coefficent. //0x04 LcdWrite( LCD_CMD, 0x14 ); // LCD bias mode 1:48. //0x13 LcdWrite( LCD_CMD, 0x0C ); // LCD in normal mode. 0x0d for inverse LcdWrite(LCD_C, 0x20); LcdWrite(LCD_C, 0x0C); } void LcdWrite(byte dc, byte data) { digitalWrite(PIN_DC, dc); digitalWrite(PIN_SCE, LOW); shiftOut(PIN_SDIN, PIN_SCLK, MSBFIRST, data); digitalWrite(PIN_SCE, HIGH); } void gotoXY(int x, int y) { LcdWrite( 0, 0x80 | x); // Column. LcdWrite( 0, 0x40 | y); // Row. } void setup(void) { LcdInitialise(); LcdClear(); pinMode(PIN_BACKLIGHT, OUTPUT); digitalWrite(PIN_BACKLIGHT, HIGH); Timer1.initialize(1000000/FRAME_RATE); // initialize timer1, and set a 1/2 second period Timer1.pwm(9, 512); // setup pwm on pin 9, 50% duty cycle Timer1.attachInterrupt(callback); // attaches callback() as a timer overflow interrupt } /* this code works but digitalWrite is much slower than directly writing to the port #define bitOut(val, bit) { \ digitalWrite(PIN_SDIN, !!(val & (1 << bit))); \ digitalWrite(PIN_SCLK, HIGH); \ digitalWrite(PIN_SCLK, LOW); \ } */ #define bitOut(val, bit) { \ if (val & (1 << bit)) \ PORT_SDIN |= _BV(SDIN_BIT); \ else \ PORT_SDIN &= ~_BV(SDIN_BIT); \ PORT_SCLK |= _BV(SCLK_BIT); \ PORT_SCLK &= ~_BV(SCLK_BIT); \ } inline void byteOut(byte val) { bitOut(val, 0); bitOut(val, 1); bitOut(val, 2); bitOut(val, 3); bitOut(val, 4); bitOut(val, 5); bitOut(val, 6); bitOut(val, 7); } void callback() { digitalWrite(PIN_DC, LCD_D); digitalWrite(PIN_SCE, LOW); for (int i=0; i<504; i++) byteOut(buffers[frame][i+ofs]); digitalWrite(PIN_SCE, HIGH); frame = 1 - frame; #ifdef SCROLLING if (frame == 0) scrollBuffers(); #endif // SCROLLING } void scrollBuffers() { for (int frame=0; frame<2; frame++) { #ifdef SCORE_BAR int y = 1; #else int y = 0; #endif byte * buffer = buffers[frame] + y*84; for (; y<(LCD_Y/8); y++, buffer+=LCD_X) { byte start = *buffer; for (int x=0; x<LCD_X-1; x++) buffer[x] = buffer[x+1]; buffer[LCD_X-1] = start; } } } void loop(void) { // loop still gets called, and the LCD is being updated via an interrupt // so put your game code here and update the display buffers at whatever // frame rate you like }