電子工作メモランダム

マイコンみたいなパソコンRaspberry Piの設定とかいじった手順とかの備忘録を淡々と記述するブログです。プログラムなど実行するときは自己責任でお願いします。

過去の記事・まとめ

 過去の記事をプロジェクト毎にまとめたものです。更新頻度はおそらくかなり低いものになると思います。

AVR関連

RaspberryPiからaitendoのLCD[C128X64SPI-12P]への画像表示

 文字はうまくいったので今回は「あの」方法を使って4階調の画像を表示します。それは、白と黒を目に見えない速さで高速で切り替える、という方法です。

用意するもの

  • RaspberryPi
  • 液晶モジュール
  • ソフトウェア
  • 1ms、1μsを縮ようとする気概

プログラム

lcd_pict.c

#include <wiringPi.h>
#include <wiringPiSPI.h>
#include <stdio.h>
#include <iconv.h>
#include <string.h>
#include <stdlib.h>

#define LCD_SDA 12  // GPIO 10
#define LCD_SCL 14  // GPIO 11
#define LCD_A0   6  // GPIO 25
#define LCD_CS  10  // GPIO  8

#define PAGE_SEL 0xB0			// (3)
#define COL_SEL  0x10			// (4)

unsigned char imagedata[8192] = {0}; // 128*64

void glcd_write_data(unsigned char dat)
{
	digitalWrite(LCD_A0, 1);		// 1ならデータ。0ならコマンド。
	// unsigned char datr = ~dat; // 白黒反転
	wiringPiSPIDataRW(0, &dat, 1);
}

// コマンドを出力する
void glcd_write_cmd(unsigned char cmd)
{
	digitalWrite(LCD_A0, 0);		// 1ならデータ。0ならコマンド。
	wiringPiSPIDataRW(0, &cmd, 1);
}

void glcd_init(void)
{
	//RST = 0;
	delay(10);
	//RST = 1;

	glcd_write_cmd(0xE2);			// (14) S/W RESWT
	glcd_write_cmd(0xA3);			// (11) LCD bias(1/7)
	//glcd_write_cmd(0xAF);			// (1)  Display ON
	glcd_write_cmd(0xA0);			// (8)  segment direction.(normal direction)
	glcd_write_cmd(0xC8);			// (15) Common Direction.(normal direction)
	glcd_write_cmd(0x22);			// (17) Regultion resistor select(0x010)  //25
	glcd_write_cmd(0x81);			// (18) EV Select.
	glcd_write_cmd(0x2f);			// (18) Select EV value.(0x101111)
	glcd_write_cmd(0x2f);			// (16) Power control(VB,VR,VF全部1)

	glcd_write_cmd(0x40);			// (2)  Initial display line(0に設定, MAX63)
	glcd_write_cmd(0xB0);			// (3)  Set page address(Y=0に設定, MAX15)
	glcd_write_cmd(0x10);			// (4)  Set coloumn addr MSB
	glcd_write_cmd(0x00);			// (4)  Set coloumn addr LSB(X=0に設定, MAX255)
	//glcd_write_cmd(0xAF);			// (1)  Display ON
	glcd_write_cmd(0xA4);			// (10) all pixel ON(normal display)
	glcd_write_cmd(0xA6);			// (9)  Inverse Display(normal display)

	glcd_write_cmd(0xAF);			// (1)  Display ON
}



// 座標のセット
void glcd_set_axis(int x, int page)
{
	int col;
	
	// Selecting Page (3)
	glcd_write_cmd(PAGE_SEL | page);

	// Selecting Column
	col = (x & 0xF0) >> 4; 			// 上位ビット
	glcd_write_cmd(COL_SEL | col);	// 
	glcd_write_cmd(x & 0x0f);		// 下位ビット
}

void glcd_clear()
{	
	int i,j;
	for (j = 0; j < 8; j++) {
		glcd_set_axis(0, j);
		for (i = 0; i < 128; i++)
			glcd_write_data(0x00);
	}
}

int init_picture()
{
	// ▼画像ファイルオープン
	FILE *fp;

	fp = fopen( "mono.dat", "rb" );
	if( fp == NULL ) {
		printf( "mono.dat が開けません\n" );
		return -1;
	}
	fread( imagedata, sizeof( unsigned char ), 128*64, fp );
	fclose(fp);
}

void show_picture(int time)
{
	int colmun, page, dot;
	unsigned char buf;
	for (page = 0; page < 8; page++)
	{
		glcd_set_axis(0, page);
		for (colmun = 0; colmun < 128; colmun++)
		{
			buf = 0;
			for (dot = 0; dot < 8; dot++)
			{
				if (imagedata[page*128*8+colmun*8+dot] <= time) buf++;
				if (dot != 7) buf = buf << 1;
			}
			glcd_write_data(buf);
		}
	}
}

int main()
{
	// 初期化
	if (wiringPiSetup() == -1)
	{
		printf("wiringPiのセットアップに失敗しました。\n");
		return 1;
	}
	int initv = wiringPiSPISetup(0, 10000000);
	printf("initv=%d\n", initv);
	if (initv < 0)
	{
		printf("wiringPiSPIのセットアップに失敗しました。\n");
		return 1;
	}
	pinMode(LCD_A0, OUTPUT);
	
	glcd_init();
	printf("init ok\n");
	
	// ▼ここからメイン
	glcd_clear();
	init_picture();
	
	int i=0;
	while(1)
	{
		show_picture(i);
		i++; if (i>2) i=0;
		// delay(1000);
	}
	return 0;
}

必要ファイル

 画像のデータです。結果に表示されているような4階調のデータです。普通にプログラムの中で階調数を指定できるようにしておけば良かったです。
mono.dat

実行・出力例

gcc lcd_pict.c -o lcd_pict -I/usr/local/include -L/usr/local/lib -lwiringPi
./lcd_pict

f:id:mas-home:20130119010044j:plain
 静止画だとそれなりに見えてるんですけど、実際にはちらつきがひどくて実用的ではありません。4分の1の面積くらいですとちゃんと見えるので、Raspberry Piの速度の問題のようです。
 とりあえず-O3くらいは入れてみますかね・・・。

RaspberryPiからaitendoのLCD[C128X64SPI-12P]への文字表示 (2) - 解説

 前記事の解説・補足です。

LCDモジュールの組み立て

 商品ページの通りに組み立てれば問題ないです。このときLCDの向きに注意してください。ディスプレイの下に小っちゃい長方形が付いている面が表です。
 裏のパターンを見ると丸っこい模様付きのパッドが4つ、カクカクした模様付きのパッドが1つあります。前者がチップコンデンサで、後者がチップ抵抗です。そのまんまです。BL+端子とグランド間に3.3V印加してバックライトがちゃんと付くか試しておきましょう。

RaspberryPiとの接続

 RaspberryPiのRevesionは2.0の前提で進めていきますが、1.0でも同じはずです。

LCD RaspberryPi(ピン番号) プログラム
GND Ground(P6 or P9 or P14 or P20 or P25) -
BL+ 3V3Power(P1) -
GND Ground -
3.3V 3V3Power -
DAT GPIO10(MOSI)(P19) LCD_SDA
CLK GPIO11(SCLK)(P23) LCD_SCL
A0 GPIO25(P22) LCD_A0
RST 3V3Power -
CS GPIO8(P24) LCD_CS

 A0はコマンドモードとデータモードの切り替えを行う端子です。他の3端子は#defineしてますが、RaspberryPiがうまくやってくれているので使っていません。

プログラム解説

  • void glcd_write_data(unsigned char dat)
  • void glcd_write_cmd(unsigned char cmd)

 それぞれLCDにデータモードとコマンドモードで出力します。

  • void glcd_init(void)

 LCDを初期化します。

  • void glcd_set_axis(int x, int page)

 page行目のx列目にカーソル位置をセットします。
 この液晶128x64ですが、白黒なので一回のglcd_write_dataで8ピクセル分書き込めます。この8ピクセルは横縦1x8で、これが横に128個(列)ならんだものが、さらに縦に8行(ページ)分ならんだような構造になってます。
 glcd_write_dataで書き込んだ後は自動的に右の列に移動します。なので単純な文字列を表示するときは行の移動時だけ実行すればいいです。

  • void output_font(char code)
  • void output_font2(char upper, char lower)
  • void output_text(char* text, int size)

 それぞれ半角1文字、全角1文字、文字列をLCDに出力します。半角文字の場合、大抵の文字コードはASCII文字コードと互換性があるので問題ないですが、全角文字の時は注意しないといけません。

  • void utf2sjis(char utf8code, char outbuf)

 で、その注意しないと行けない文字コードを変換する関数です。文字列の文字コードUTF-8からSJISに変換します。
 実際の所、わざわざここで変換しなくても、プログラムファイルを保存するときにSJISで保存すれば問題ないのですが、文字化けとか嫌なのでUTF-8で統一することにしています。というのもRaspberryPiの初期化時にロケール設定UTF-8にしたからです。
 iconvってのが必要になりますが、Raspbianには最初から入ってるみたいです。

  • int fontOpen()

 フォントを読み込みます。AVRとかPICみたいにRAMが数kBしかない、なんてことはないので全部読み込んじゃいます。富豪的プログラミングですね。

  • int main()

 wiringPiの初期化と文字列の出力です。ポインタややこしいです。
 わりと一瞬で文字の表示が終わります。

今後の予定

 このLCDに画像を表示させたいです。普通の白黒画像だと簡単すぎるので4階調程度のグレースケール画像を表示しようかと思ってます。白黒ディスプレイなので「あの」方法を使います。

RaspberryPiからaitendoのLCD[C128X64SPI-12P]への文字表示 (1)

 タイトル通りAitendoの液晶ディスプレイモジュール[C128X64SPI-12P]に文字表示を行ったので書きます。

 でその液晶なんですけど、FSTN液晶モジュール(128x64/SPI)@350円です。実際に買ったのはバックライトと基板付きのC128X64SPI-12P-M@580円のほうです。安いですね。その分、説明書のたぐいは一切付いてきません。ただし、サンプルコードが商品ページにあるのでそれを参考にしました。

用意するもの

プログラム

 とりあえず動けばいいんです。もうちょっとポインターとか勉強した方が良いですね、はい。
 仕様としては、全角16文字x8行、半角なら32文字/行で、半角/全角混在可能です。

lcd_text.c

#include <wiringPi.h>
#include <wiringPiSPI.h>
#include <stdio.h>
#include <iconv.h>
#include <string.h>
#include <stdlib.h>


#define LCD_SDA 12  // GPIO 10
#define LCD_SCL 14  // GPIO 11
#define LCD_A0   6  // GPIO 25
#define LCD_CS  10  // GPIO  8

#define PAGE_SEL 0xB0			// (3)
#define COL_SEL  0x10			// (4)

#define MAX_BUF 256

unsigned char chardataHan[1024];
unsigned char chardataZen[70688];

void glcd_write_data(unsigned char dat)
{
	digitalWrite(LCD_A0, 1);		// 1ならデータ。0ならコマンド。
	// unsigned char datr = ~dat; // 白黒反転
	wiringPiSPIDataRW(0, &dat, 1);
}

// コマンドを出力する
void glcd_write_cmd(unsigned char cmd)
{
	digitalWrite(LCD_A0, 0);		// 1ならデータ。0ならコマンド。
	wiringPiSPIDataRW(0, &cmd, 1);
}

void glcd_init(void)
{
	delay(10);

	glcd_write_cmd(0xE2);			// (14) S/W RESWT
	glcd_write_cmd(0xA3);			// (11) LCD bias(1/7)
	//glcd_write_cmd(0xAF);			// (1)  Display ON
	glcd_write_cmd(0xA0);			// (8)  segment direction.(normal direction)
	glcd_write_cmd(0xC8);			// (15) Common Direction.(normal direction)
	glcd_write_cmd(0x22);			// (17) Regultion resistor select(0x010)  //25
	glcd_write_cmd(0x81);			// (18) EV Select.
	glcd_write_cmd(0x2f);			// (18) Select EV value.(0x101111)
	glcd_write_cmd(0x2f);			// (16) Power control(VB,VR,VF全部1)

	glcd_write_cmd(0x40);			// (2)  Initial display line(0に設定, MAX63)
	glcd_write_cmd(0xB0);			// (3)  Set page address(Y=0に設定, MAX15)
	glcd_write_cmd(0x10);			// (4)  Set coloumn addr MSB
	glcd_write_cmd(0x00);			// (4)  Set coloumn addr LSB(X=0に設定, MAX255)
	//glcd_write_cmd(0xAF);			// (1)  Display ON
	glcd_write_cmd(0xA4);			// (10) all pixel ON(normal display)
	glcd_write_cmd(0xA6);			// (9)  Inverse Display(normal display)

	glcd_write_cmd(0xAF);			// (1)  Display ON
}
// 座標のセット
void glcd_set_axis(int x, int page)
{
	int col;
	
	// Selecting Page (3)
	glcd_write_cmd(PAGE_SEL | page);

	// Selecting Column
	col = (x & 0xF0) >> 4; 			// 上位ビット
	glcd_write_cmd(COL_SEL | col);	// 
	glcd_write_cmd(x & 0x0f);		// 下位ビット
}

// 半角一文字出力
void output_font(char code)
{
	int j;
	for (j = 0; j < 4; j++)
		glcd_write_data(chardataHan[code*4+j]);
}
// 全角一文字出力
void output_font2(char upper, char lower)
{
	// 文字コードから文字データ配列のアドレスへと変換
	int hosei = (upper- (upper >= 0xE0 ? 0xE0 : 0x81)) * 4 + (lower>0x7F ? 1 : 0) + (upper >= 0xE0 ? 0x7C : 0);
	int num = ((upper - (upper >= 0xE0 ? 0xE0 : 0x81))*0xC0 + lower-0x40 - hosei + (upper >= 0xE0 ? 0x1740 : 0))*8;

	printf("cc=%d, hosei=%d\n", num/8,hosei);
	int j;
		for (j = 0; j < 8; j++) // 全角
			glcd_write_data(chardataZen[num+j]);
}
// 文字列出力
void output_text(char* text, int size)
{
	int j;
	for (j = 0; j < size; j++)
	{
		char code = text[j];
		if (code < 0x80 | (code >= 0xA0 & code < 0xE0))
		{
			printf("code=%x\n",text[j]);
			output_font(text[j]); 				// 半角
		} else {
			printf("code=%x %x\n",text[j], text[j+1]);
			output_font2(text[j], text[j+1]);	// 全角
			j++;
		}
	}
}

void utf2sjis(char utf8code[], char outbuf[])
{
	// ▼文字コード変換
	int j;
	char	inbuf[MAX_BUF+1] = { 0 };
	
	char	*in = inbuf;
	char	*out = outbuf;
	size_t	in_size = (size_t)MAX_BUF;
	size_t	out_size = (size_t)MAX_BUF;
	iconv_t ic = iconv_open("SJIS", "UTF-8");

	memcpy( in, utf8code, 64 );

	iconv( ic, &in, &in_size, &out, &out_size );
	iconv_close(ic);

	for (j = 0; j < 16; j++) printf("%x ", outbuf[j] );
}
int fontOpen()
{
	// ▼フォントファイルオープン
	FILE *fp;
	unsigned char buf[1024];
	int size;

	fp = fopen( "misakiHan.dat", "rb" );
	if( fp == NULL ) {
		printf( "misakiHan.dat が開けません\n" );
		return -1;
	}
	size = fread( chardataHan, sizeof( unsigned char ), 1024, fp );
	fclose(fp);

	// ▼フォントファイルオープン
	unsigned char buf2[70688];
	int size2;

	fp = fopen( "misakiZen_gothic.dat", "rb" );
	if( fp == NULL ) {
		printf( "misakiZen_gothic.dat が開けません\n" );
		return -1;
	}
	size2 = fread( chardataZen, sizeof( unsigned char ), 70688, fp );
	fclose(fp);
}

int main()
{
	// ▼初期化
	if (wiringPiSetup() == -1)
	{
		printf("wiringPiのセットアップに失敗しました。\n");
		return 1;
	}
	int initv = wiringPiSPISetup(0, 1000000);
	printf("initv=%d\n", initv);
	if (initv < 0)
	{
		printf("wiringPiSPIのセットアップに失敗しました。\n");
		return 1;
	}
	pinMode(LCD_A0, OUTPUT);
	
	glcd_init();
	printf("init ok\n");
	
	// ▼ここからメイン
	int fresult = fontOpen();
	char outbuf[MAX_BUF+1] = { 0 };
	
	glcd_set_axis(0,0);
	char* buff2 = "    ==謹賀新年==    "; utf2sjis(buff2, outbuf);
	output_text(outbuf, 64);
	glcd_set_axis(0,1);
	char* buff3 = "あけましておめでとうございます。"; utf2sjis(buff3, outbuf);
	output_text(outbuf, 64);
	glcd_set_axis(0,2);
	char* buff4 = " 今年もよろしくお願いします。 "; utf2sjis(buff4, outbuf);
	output_text(outbuf, 64);
	glcd_set_axis(0,3);
	char* buff5 = "  平成25年1月10日(木)     "; utf2sjis(buff5, outbuf);
	output_text(outbuf, 64);
	glcd_set_axis(0,4);
	char* buff6 = "                "; utf2sjis(buff6, outbuf);
	output_text(outbuf, 64);
	glcd_set_axis(0,5);
	char* buff7 = "X / _ / X <来週も見てくださいね!"; utf2sjis(buff7, outbuf);
	output_text(outbuf, 64);
	glcd_set_axis(0,6);
	char* buff8 = "                "; utf2sjis(buff8, outbuf);
	output_text(outbuf, 64);
	glcd_set_axis(0,7);
	char* buff9 = "魑魅魍魎檸檬薔薇雲霧霜霰雹 凜 "; utf2sjis(buff9, outbuf);
	output_text(outbuf, 64);
	
	return 0;
}

必要ファイル

 フォントデータが無いと動きません。美咲フォントという素晴らしい漢字フォントがあるのでそれを使うことにしました。そのままでは使えないのであらかじめ変換しています。変換ソフトもそのうち公開予定です。
misaki_4x8_jisx0201.dat
misaki_gothic.dat
 二つのファイルをプログラムファイルと同じディレクトリに入れるか、プログラムを変更してください。
あ、名前違いますね。misaki_4x8_jisx0201.datはmisakiHan.datに、misaki_gothic.datはmisakiZen_gothic.datにリネームしてください。

実行・出力例

sudo gcc lcd_test.c -o lcd_test -I/usr/local/include -L/usr/local/lib -lwiringPi
sudo ./lcd_test

f:id:mas-home:20130110014447j:plain
こんな感じ。もう13日ですけどね。

wiringPiを使ってC言語でGPIOからLEDを点滅させる

 LCDになんか表示させるために、まずはC言語でGPIOの制御をできるようにすることを目的として、LEDの点灯実験を行います。

wiringPiのインストール

 参考URL先のをそのままコピペしてます。変える必要もないですしね。

cd /tmp
wget http://project-downloads.drogon.net/files/wiringPi.tgz

tar xfz wiringPi.tgz
cd wiringPi/wiringPi
make
sudo make install
cd ../gpio
make
sudo make install

参考URL
Raspberry pi をArduinoみたいに使う - how to code something

wiringPiのテスト

 wiringPiがちゃんとインストールされているかどうか確認するために、まずはshellからLEDの点灯を行います。詳細は参考URLを見てください。

gpio -g mode 17 out  # GPIO 17をoutputにする
gpio -g write 17 1   # GPIO 17のHIGHにする
gpio -g write 17 0   # GPIO 17をLOWにする

 wiringPiとRaspberry Piのピン番号は違うらしく、GPIO 17は「0」らしいです。Cで書くときはこっちの数字を使います。ちなみに変えることもできるみたいです。

gpio mode 0 out  # GPIO 17をoutputにする
gpio write 0 1   # GPIO 17のHIGHにする
gpio write 0 0   # GPIO 17をLOWにする

 どっちでも同じ動作なはずです。

参考URL
Raspberry Pi (3) « stastaka's Blog

プログラム

 これも上の参考URLとかを参考にしてください。

test.c

#include <wiringPi.h>
#include <stdio.h>

int main (void)
{
    int pin = 0; // GPIO 17

    if (wiringPiSetup() == -1)
        return 1;
    printf("setupOK\n");

    pinMode(pin, OUTPUT);

    while (1)
    {
        printf("loop\n");
        digitalWrite(pin, 1);
        delay(1000);
        digitalWrite(pin, 0);
        delay(1000);
    }

    return 0;
}

実行

sudo gcc test.c -o test -I/usr/local/include -L/usr/local/lib -lwiringPi
sudo ./test

でコンパイル&実行。

 よし。ちゃんと動いた。

ソースコード入力テスト

#include <stdio.h>

int main (void)
{
    int i;
    double d;
    int xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx,yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy,zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz;
    for (i = 0; i < 40000; i++)
    {
        d += 1;
    }
    return 0;
}

参考
はてな記法一覧 - はてなダイアリーのヘルプ
ソースコードを色付けして記述する(シンタックス・ハイライト) - はてなダイアリーのヘルプ