128*64白黒液晶にPC画面を転送

秋月で売っている128*64液晶とarduinoをつないでPC画面をキャプチャしたデータを表示しています.ところどころ,転送漏れしてます...

回路の方は http://q61.org/chibimo/ こちらの方の回路をそのまま使わせていただいて,
ソフトは頑張って書いてみました.一応,pure arduino languageです.直接レジスタいじったりしていません(スキルがないだけ).
PyGTK→Python→serial→Arduino→SG12864

回路

arduino スケッチ

class GraphicLcd{
public:
  struct Status {
    int busy;
    int on_off;
    int reset;
  } 
  status;

  GraphicLcd(int di, int rw, int e, int res, int cs1, int cs2,
  int db0, int db1, int db2, int db3,
  int db4, int db5, int db6, int db7);
  void displayOnOFF(int on_off);
  void displayStartLine(int line);
  void setPageAddress(int page);
  void setColumnAddress(int column);
  void setChip(int chip);
  void statusRead(void);
  void writeDisplay(int data);
  int  readDisplay(void);
private :
  int di_pin;
  int rw_pin;
  int e_pin;
  int res_pin;
  int cs1_pin;
  int cs2_pin;

  int _data_pins[8];
  int _data;
	int di;
	int rw;
  int chip;

  void enable(void);
  void setData(void);
  void getData(void);
  int strToData(const char *string);
};

GraphicLcd::GraphicLcd(int di_pin,  int rw_pin,  int e_pin, int res_pin,
int cs1_pin, int cs2_pin, int db0, int db1, int db2, int db3, int db4, int db5,
int db6, int db7)
{
  this->di_pin = di_pin;
  this->rw_pin = rw_pin;
  this->e_pin  = e_pin;
  this->res_pin = res_pin;
  this->cs1_pin = cs1_pin;
  this->cs2_pin = cs2_pin;
  _data_pins[0] = db0;
  _data_pins[1] = db1;
  _data_pins[2] = db2;
  _data_pins[3] = db3;
  _data_pins[4] = db4;
  _data_pins[5] = db5;
  _data_pins[6] = db6;
  _data_pins[7] = db7;
  pinMode(di_pin,  OUTPUT);
  pinMode(rw_pin,  OUTPUT);
  pinMode(e_pin,   OUTPUT);
  pinMode(res_pin, OUTPUT);
  pinMode(cs1_pin, OUTPUT);
  pinMode(cs2_pin, OUTPUT);
  for(int i = 0; i < 8; i++){
    pinMode(_data_pins[i], OUTPUT);
    digitalWrite(_data_pins[i], HIGH);
  }
  digitalWrite(e_pin,    LOW);
  digitalWrite(di_pin,   LOW);
  digitalWrite(rw_pin,   LOW);
  digitalWrite(res_pin,  HIGH);
  digitalWrite(cs1_pin,  LOW);
  digitalWrite(cs2_pin,  LOW);
}

void GraphicLcd::enable(void)
{
  digitalWrite(di_pin, di);
  digitalWrite(rw_pin, rw);
  if(chip%2 == 0){
    digitalWrite(cs1_pin, LOW);
    digitalWrite(cs2_pin, HIGH);
  }
  else{
    digitalWrite(cs1_pin, HIGH);
    digitalWrite(cs2_pin, LOW);
  }
  setData();
  digitalWrite(e_pin, HIGH);
  digitalWrite(e_pin, LOW);
}

void GraphicLcd::setData(void)
{
  for(int i = 0; i < 8; i++){
    digitalWrite(_data_pins[i], (_data>>i)&1);
  }
}

void GraphicLcd::getData(void)
{
  _data = 0;
  for(int i = 0; i < 8; i++){
    _data |= (digitalRead(_data_pins[i])<<i);
  }
}

int GraphicLcd::strToData(const char *string)
{
  int data = 0;
  for(int i = 0; i < 8; i++){
    data <<= 1;
    data += string[i]=='1'?1:0;
  }
  return data;
}

void GraphicLcd::displayOnOFF(int on_off)
{
  di = LOW;
  rw = LOW;
  _data = strToData("00111110");
  _data |= on_off;
  enable();
}

void GraphicLcd::displayStartLine(int line)
{
  di = LOW;
  rw = LOW;
  _data = strToData("11000000");
  _data |= line;
  enable();
}

void GraphicLcd::setPageAddress(int page)
{
  di = LOW;
  rw = LOW;
  _data = strToData("10111000");
  _data |= page;
  enable();
}

void GraphicLcd::setColumnAddress(int column)
{
  di = LOW;
  rw = LOW;
  _data = strToData("01000000");
  _data |= column;

  enable();
}

void GraphicLcd::statusRead(void)
{
  di = LOW;
  rw = HIGH;
  _data = strToData("00000000");
  enable();
  getData();
  status.busy   = (_data>>7)&1;
  status.on_off = (_data>>5)&1;
  status.reset  = (_data>>4)&1;
}

void GraphicLcd::writeDisplay(int data)
{
  di = HIGH;
  rw = LOW;
  _data = data;
  enable();
}

int GraphicLcd::readDisplay()
{
  di = HIGH;
  rw = HIGH;
  enable();
  getData();

  return _data;
}

void GraphicLcd::setChip(int chip)
{
  this->chip = chip;
}

GraphicLcd glcd(17, 18, 19, 13, 11, 12,
2, 3, 4, 5,
6, 7, 8, 9);

#define BUFFER_SIZE 1024+512

unsigned char buf[BUFFER_SIZE];
int sbufp, ebufp;
int i, j;

void glcd_write(int i, int j, int data)
{
  glcd.setChip(1-j/64);
  glcd.setPageAddress(i);
  glcd.setColumnAddress(j%64);
  glcd.writeDisplay(data);
}

void setup(void)
{
  glcd.displayStartLine(0xC0);
  glcd.setChip(0);
  glcd.displayOnOFF(1);
  glcd.setChip(1);
  glcd.displayOnOFF(1);
  Serial.begin(57600);
  sbufp = 0;
  ebufp = 0;
}

void loop(void)
{
  while(Serial.available()&&!(ebufp-sbufp >= BUFFER_SIZE-1 || (ebufp+(BUFFER_SIZE-sbufp) >= BUFFER_SIZE-1 && ebufp < sbufp))){
    buf[ebufp++] = Serial.read();
    if(!(ebufp-BUFFER_SIZE)) ebufp = 0;
  }
  if(ebufp-sbufp >= 3 || (ebufp+(BUFFER_SIZE-sbufp) >= 3 && ebufp < sbufp)){
    i = buf[sbufp++];
    if(!(ebufp-BUFFER_SIZE)) ebufp = 0;
    if(8<=i)
      return;
    j = buf[sbufp++];
    if(!(ebufp-BUFFER_SIZE)) ebufp = 0;
    glcd_write(i,j,buf[sbufp++]);
    if(!(ebufp-BUFFER_SIZE)) ebufp = 0;
  }
}

PC側プログラム

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import pygtk
import gtk
import time
import threading
import gobject
import sys

class graphicsLCD:
	def __init__(self, scale=1):
		self.scale = scale
		self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
		self.window.set_size_request(128*self.scale, 0)
		self.window.show()
		self.window.connect("event", self.get_coordinates)
		self.x = 0
		self.y = 0
		self.disp_array = [[0 for j in range(128)] for i in range(64)];
		self.temp_array = [[0 for j in range(128)] for i in range(64)];
		gobject.timeout_add(1, self.timeout)

	def main(self):
		gtk.main()

	def get_coordinates(self, widget, event) :
		" ウインドウ座標取得 "
		(self.x, self.y) = self.window.get_position()

	def timeout(self):
		" キャプチャ "
		root = gtk.gdk.get_default_root_window()
		pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, False, 8, 128*self.scale, 64*self.scale)
		pixbuf.get_from_drawable(root, gtk.gdk.colormap_get_system(),
			self.x, self.y+30, 0, 0, 128*self.scale, 64*self.scale)
		pixels = pixbuf.get_pixels()

		" グレースケール化 "
		for i in range(64):
			for j in range(128):
				self.temp_array[i][j] =(
					(ord(pixels[i*self.scale*128*self.scale*3+j*self.scale*3])*0.298912
					+ord(pixels[i*self.scale*128*self.scale*3+j*self.scale*3+1])*0.586611
					+ord(pixels[i*self.scale*128*self.scale*3+j*self.scale*3+2])*0.114478))

		" しきい値(平均を求める) "
		sum = 0
		for i in range(64):
			for j in range(128):
				sum += self.temp_array[i][j]
		siki = sum/(64*128)

		" 二値化 "
		array = [[0 for j in range(128)] for i in range(64)];
		for i in range(64):
			for j in range(128):
				if self.temp_array[i][j] > siki :
					array[i][j] = 0
				else :
					array[i][j] = 1

		" 転送 "
		f = open('/dev/ttyUSB0', 'w');
		for i in range(8):
			for j in range(128):
				reDrawFlag = False
				data = 0
				for k in range(8):
					if self.disp_array[8*i+k][j] != array[8*i+k][j] :
						reDrawFlag = True
					data += (array[8*i+k][j])*2**k
				" データに変更があったときのみ転送 "
				if reDrawFlag == True :
					f.write("%c%c%c" % (chr(i), chr(j), chr(data)))
#					time.sleep(0.000008)
				
#		for i in range(64):
#			for j in range(128):
#				if array[i][j] == 0:
#					sys.stdout.write(' ')
#				else :
#					sys.stdout.write('*')
#			print
#		print "--send data--"
#		time.sleep(0.01)
				
		self.disp_array = array

		gobject.timeout_add(1, self.timeout)

print __name__
if __name__ == "__main__":
	glcd = graphicsLCD(4)
	glcd.main()