2009
11.03

Santa came early this year and brought me a S65-Shield revision 1.2 from watterott

 Arduino Goodness : Watterott S65 Shield 172x136 pixels 16 bit color display

S65 displaying random text

It consists of :

– a Siemens S65 16-bit color screen with 172×136 pixels

– a rotary switch (left-right-press)

– a micro-SD slot (bottom)

 Arduino Goodness : Watterott S65 Shield 172x136 pixels 16 bit color display

S65 bottom

You can visit the project page to check progress made to the libraries and hardware.The most recent library is v0.08 . It’s actually more like 3 libraries:  ‘S65Display’, ‘RotaryEncoder’ and ‘SDCard’.

You can check the documentation that comes with the libraries to view this baby shields’ possibilities. So far this shield seems to be a bargain (compaired to other display-shields out there) selling at only €35 that’s equal to $51.36600 or 4640.5276 Japanese  Yen or 149.793533 Polish Zloty or your virginity if you’re misfortuned enough to live in one of those countries, anyhow.

It has some pretty long headers which make it easy to mount on top of the tallest board you own.

 Arduino Goodness : Watterott S65 Shield 172x136 pixels 16 bit color display

S65 mating with Duemilanove

I don’t have a microSD card at hand so I can’t test the SDCard library for now. Which sucks since you can load images stored on the microSD and display them on the screen. You can also use the images for buttons, icons, etc in your sketches… how cool is that?

Here’s an example of the awsome S65-Shield in action on an Arduino Duemilanove with 328 Atmel running a Game of Life sketch. I am not the author of this code, he gave me the code for testing and learning purposes. I just added the rotary delay. Maybe he’ll give his consent later so I can post the code online. Foo Joku gave his consent, the code is posted after the video.

The display and colors look much better in real life, this video was shot with an old digital camera in bad light conditions.

GOL code:
#include <S65Display.h>
#include <RotaryEncoder.h>

#define GRID_X 28
#define GRID_Y 20

#define GRID_X_OFFSET 4
#define GRID_Y_OFFSET 6

#define COLOUR_SWITCH_INTERVAL 30

#define MAX_GENERATIONS 250

S65Display lcd;
RotaryEncoder encoder;

uint8_t grid[2][GRID_X][GRID_Y];
uint8_t current_grid = 0;

uint8_t generations = 0;
uint8_t r = 255,g = 0, b = 0;

// Encoder must be serviced regularly.
ISR(TIMER2_OVF_vect)
{
 TCNT2 -= 250; //1000 Hz
 encoder.service();
}

void setup()
{
 lcd.init(4);
 encoder.init();
 // More encoder stuff
 //init Timer2
 TCCR2B  = (1<<CS22); //clk=F_CPU/64
 TCNT2   = 0x00;
 TIMSK2 |= (1<<TOIE2); //enable overflow interupt

 sei();
 initGrid();
 lcd.clear(0);
 drawGrid();
}

void loop()
{
 //delay(50);
 checkEncoder();
 runGrid();
 drawGrid();
 generations++;
 if (generations > MAX_GENERATIONS || cmpGrid()) {
 generations = 0;
 initGrid();
 }
 cycleColour();
 cycleColour();
 cycleColour();
}

int cmpGrid()
{
 int i, j;
 for (i=0; i < GRID_Y; i++) {
 for (j=0; j < GRID_X; j++) {
 if (grid[0][i][j] != grid[1][i][j]) { return 0; }
 }
 }
 return 1;
}

void initGrid()
{
 int i, j;
 int t;
 lcd.clear(0);
 current_grid = 0;
 for (i = 0; i < GRID_X; i++) {
 for (j = 0; j < GRID_Y; j++) {

 if ((uint8_t)random(255) % 3 == 0) {
 grid[0][i][j] = 1;
 } else {
 grid[0][i][j] = 0;
 }
 }
 }
}

void runGrid()
{
 uint8_t x, y;
 int count;
 char string[2] = {0,0};
 uint8_t value = 0;
 uint8_t new_grid;

 new_grid = 1 - current_grid;
 for (y = 0; y < GRID_Y; y++) {
 for (x = 0; x < GRID_X; x++) {
 count = count_neighbours(x, y);
 string[0] = count+48;
 if (count < 2 || count > 3) { value = 0; }
 else if (count == 3) { value = 3; }
 else { value = grid[current_grid][x][y]; }
 grid[new_grid][x][y] = value;
 }
 }
 current_grid = new_grid;
}

int count_neighbours(int x, int y)
{
 int i, j;
 int sx;
 int result = 0;

 x--;
 y--;
 for (i = 0; i < 3; i++) {
 if (y < 0 || y > (GRID_Y - 1)) { continue; }
 for (j = 0; j < 3; j++) {
 if (x < 0 || x > (GRID_X - 1)) { continue; }
 if (i==1 && j == 1) { x++; continue; } // skip centre
 if (grid[current_grid][x][y]) { result++; }
 x++;
 }
 y++;
 x -= 3;
 }
 return result;
}

void drawGrid()
{
 uint8_t  x,  y;
 uint8_t cx, cy;
 uint8_t grid_next_colour = 0;
 cx = GRID_X_OFFSET;
 cy = GRID_Y_OFFSET;
 for (y = 0; y < GRID_Y; y++) {
 cx = GRID_X_OFFSET;
 for (x = 0; x < GRID_X; x++) {
 if (grid[1-current_grid][x][y] != grid[current_grid][x][y]) {
 if(grid[current_grid][x][y]) {
 lcd.drawRect(cx+1, cy+1, cx+5, cy+5, RGB(r,g,b));
 } else {
 lcd.drawRect(cx, cy, cx+6, cy+6, 0);
 }
 }
 cx += 6;
 }
 cy += 6;
 }
}

inline void cycleColour()
{
 if (!b && r)  { r-=5; g+=5; }
 else if (g) { g-=5; b+=5; }
 else if (b) { b-=5; r+=5; }
}

void checkEncoder(void)
{
 int8_t press;
 press = encoder.sw();

 if ( !press ) { return; }

 if (SW_PRESSED == press || SW_PRESSEDLONG == press) {
 initGrid();
 lcd.clear(0);
 }
}

Back to homepage

2 comments so far

Add Your Comment
  1. Heya,

    That looks suspiciously like my (foojoku) version of the GoL :). If it is, you’re welcome to post the code or, really, do whatever else you want with it.

  2. Hi Foo Joku,

    It is indeed your code but I didn’t get to asking your approval to distribute so I didn’t post it. But now I will since several people have asked me for the code in the past few months. Now that I have some more time I’ll soon write my own versions of GoL.

    Greets,
    Tom

Please leave these two fields as-is:
Prove you are human by reading this resistor:
0Ω+/- 5%

0
0
1
2
3
4
5
6
7
8
9

0
0
1
2
3
4
5
6
7
8
9

0
0
1
2
3
4
5
6
7
8
9

5
5
10
20

Match the sliders on the left to each color band on the resistor.

Click Here for a new resistor image.

If you'd like to learn more, read about resistor color codes here.