過去の記事・まとめ
過去の記事をプロジェクト毎にまとめたものです。更新頻度はおそらくかなり低いものになると思います。
RaspberryPi関連
LED点灯テスト (2013/1/6)
LCD[C128X64SPI-12P]関連 (2013/1/13~)
AVR関連
RaspberryPiからaitendoのLCD[C128X64SPI-12P]への画像表示
文字はうまくいったので今回は「あの」方法を使って4階調の画像を表示します。それは、白と黒を目に見えない速さで高速で切り替える、という方法です。
用意するもの
- RaspberryPi
- 液晶モジュール
- ソフトウェア
- gcc (Debian 4.6.3-12+rpi1) 4.6.3 (デフォルトではいってるはず)
- wiringPi (インストール方法はwiringPiを使ってC言語でGPIOからLEDを点滅させる)
- 画像データ (当記事参照)
- プログラムファイル (当記事参照)
- 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
静止画だとそれなりに見えてるんですけど、実際にはちらつきがひどくて実用的ではありません。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円のほうです。安いですね。その分、説明書のたぐいは一切付いてきません。ただし、サンプルコードが商品ページにあるのでそれを参考にしました。
用意するもの
- RaspberryPi
- 液晶モジュール
- ソフトウェア
- gcc (Debian 4.6.3-12+rpi1) 4.6.3 (デフォルトではいってるはず)
- wiringPi (インストール方法はwiringPiを使ってC言語でGPIOからLEDを点滅させる)
- フォントデータ (当記事参照)
- プログラムファイル (当記事参照)
- 文字コードへの関心
プログラム
とりあえず動けばいいんです。もうちょっとポインターとか勉強した方が良いですね、はい。
仕様としては、全角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
こんな感じ。もう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
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とかを参考にしてください。
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; }
参考
はてな記法一覧 - はてなダイアリーのヘルプ
ソースコードを色付けして記述する(シンタックス・ハイライト) - はてなダイアリーのヘルプ