前回で0.96液晶(ST7735)とarduinoの接続とテストが終わりましたので、これで次の段階に進めます。
いよいよSDカードからのBMPファイルの表示を行います。
今回も色々と苦心していますw
今回参考にするのはこのサイトです。
TFT液晶の配線は前回のままです。
(実はこの時の配線用にarduinoの元のスケッチ例の配線とは変えてありました^^;)
SDカードの配線は
SDカードモジュール arduino
GND------------GND
VCC------------5V(製品によっては3.3Vの時も有ります)
MISO-----------D12
MOSI-----------D11
SCK------------D13
CS------------D10です。
SCKとMOSIはTFT液晶の配線と被ります。
VCCについはこのSDカードモジュールは5Vでの駆動です。
はじめ3v3に接続していてSDカードモジュールが機能していなく、どうやっても画像が表示できなくて1日くらい悩みましたww別途購入したSDカードモジュールは3.3Vでも動きました^^
で、上記サイトの配線図見ると液晶との間に抵抗が入っていますが、今回の場合は無くても駆動しました^^
次にSDカードに画像を用意します。
条件は
①BMPファイル 「aaa.bmp」とか書いてあるファイルですね。
②ファイル名は日本語禁止 「画像.BMP」とかは使えません。
ファイル名の長さはこのプログラムでは関係ないようです。
ただ、画像サイズが大きすぎると確認が難しくなりますので(例えば風景画の空の一部だけ表示されて画面全体が青とかw)液晶をrotation(0)の時つまり長軸を縦として使った場合の画像を作ります。
使うのは超高級ソフト!ペイントwウインドウズのアクセサリーの中にあるペイントですねw
画像を開いた後、左上のサイズの変更で、ピクセルを選び水平方向に80と入力してOKボタンを押してください。この液晶は縦160、横80の液晶となります。このサイズを超えた場合は超えた範囲が描画されないだけで特に問題は有りませんが、先ほど書いたような理由である程度の大きさにしておいてください。
このような画像を何枚かSDカードに保存してください。
後は、上記サイトの「Full Arduino code:」と書いてあるプログラムをコピペします。
あとスイッチとしてD2をGNDにつなげると画像がドンドン表示されます。
するとこんな感じになります。
あれwなんか色が変ですし、画像の位置もおかしいですよね?
ちょっとコピペしたプログラムの方を見てください。
35行目に tft.fillScreen(ST77XX_BLUE);
と有りますよね。これ画面を青で塗りつぶす命令なのですが、赤で塗りつぶされていますよね
実はこれこそ、前回ライブラリーの導入でご紹介したこちらのサイトの分からないから飛ばした<動作確認>の所の記述が関係してきてるんです。
はいwここの修正が分かるまで丸1日かかりましたww
では修正していきましょう。
//—————-追記———————————————–
色がおかしくない場合は、
33行目の tft.initR(INITR_BLACKTAB);
↓
tft.initR(INITR_MINI160x80);
で終了です。
//———————————————————————-
このずれはそもそも
33行目の tft.initR(INITR_BLACKTAB);
これが関係しています。
初期化にBLACKTABとか変な名前付いていますよね~。でもよく思い出してください、
単なる保護用のシートと思いましたが、ここにグリーンのタブ付いていますよね。
実はこれの事を言っているんです。
この初期化のコマンドで、このTABを選択することによって色の表示がRGBかBGRにかわるんです。つまりこのコマンド部分を黒のタブでなくグリーンのタブを指定してやります。
33行目 tft.initR(INITR_BLACKTAB); → tft.initR(INITR_GREENTAB);
に変更すると色は通常の表示になります。(コピペの場合は最後の「;」マークを忘れないように、それと前後の空白を含まないようにしてください)
でもそれだけだとまだ位置のずれが治っていないんですよね~。
ここを直すにはもうひと踏ん張り必要です。
ちょっとだけ難しくなりますよ~w
まずはPC内のドキュメントのArduino\libraries\Adafruit_ST7735_and_ST7789_Libraryというフォルダを表示してみてください。ここにある
Adafruit_ST7735.cpp
を編集します。
念のためコピぺで元ファイルをどこか別の場所に保存しておいてください。
このファイルをテキストエディーターもしくはメモ帳で開いて編集していきます。
私の物はAtmel Studoiなので色付きですがその辺は気にせずにw
中を見ていくと後半くらいにこんな記述の部分が有ります。
ちゃんと160x80用の初期化コマンドも有るんです。
この赤線の下に書いてある「 }else 」までのプログラム達が画面の開始位置の設定をしています。
ですから、
_height = ST7735_TFTWIDTH_80;
_width = ST7735_TFTHEIGHT_160;
displayInit(Rcmd2green160x80);
_colstart = 24;
_rowstart = 0;
これを黄色線の下の 「}else if((option・・・・・・・」までの{}の中身部分を消してコピペしてもいいのですが、今後他のグリーンタブの液晶を使うことを考えるとちょっとな^^;てなことでINITR_MINI160x80が使えるようにします。
実はこのINITR_MINI160x80を使うと位置表示は問題なくなるのですが、色が以前の赤と青が入れ替わった表示となってしまいますw
そこでちょっと改修が必要です。
まずは先ほどの画像で表示されて居た部分の少し下に行くと
(赤色の線が先ほどの画像の赤線部分です)
青色線部分
if ((options == INITR_BLACKTAB) || (options == INITR_MINI160x80)) {
と有りますが、この下のコマンドでわざわざ色の表示方法を変えてあるんですねwなんちゅう邪魔なことをしてくれてるんだw
if ((options == INITR_BLACKTAB) || (options == INITR_MINI160x80)) {
↓
if (options == INITR_BLACKTAB) {
と書き換えてINITR_MINI160x80を外してやります。
さらにそこからさらに下のこの部分
とさらに下のこの部分
の赤矢印部分3か所を
if ((tabcolor == INITR_BLACKTAB) || (tabcolor == INITR_MINI160x80)) {
↓
if (tabcolor == INITR_BLACKTAB) {
に変更します。
これで、保存して終了です。
この後、先ほどのあのサイトからコピペしたプログラムの33行目(一回GREENTABに書き換えていますから)
tft.initR(INITR_GREENTAB); → tft.initR(INITR_MINI160x80);
に修正して下さい。
これで
色も表示位置も修正されたと思います。
さて、これでSDカード内の画像の表示が出来ましたが、今このままだと内部の画像を次々に表示されるので色々やるにはちょっと困るw
指定の画像が表示できるようになりたい!
てな方用のプログラムはこちら
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
#include <Adafruit_GFX.h> // include Adafruit graphics library #include <Adafruit_ST7735.h> // include Adafruit ST7735 display library #include <SPI.h> // include Arduino SPI library #include <SD.h> // include Arduino SD library // define ST7735 TFT display connections #define TFT_RST 5 // reset line (optional, pass -1 if not used) #define TFT_CS 6 // chip select line #define TFT_DC 7 // data/command line // initialize Adafruit ST7735 TFT library Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST); void setup(void) { Serial.begin(9600); tft.initR(INITR_MINI160x80); tft.fillScreen(ST77XX_BLUE); SD.begin(); } void loop() { bmpDraw("MISA40.bmp", 0, 0); delay(5000); tft.fillScreen(0); bmpDraw("foker70.bmp", 0, 0); delay(5000); tft.fillScreen(0); } #define BUFFPIXEL 20 void bmpDraw(char *filename, uint8_t x, uint16_t y) { File bmpFile; int bmpWidth, bmpHeight; // W+H in pixels uint8_t bmpDepth; // Bit depth (currently must be 24) uint32_t bmpImageoffset; // Start of image data in file uint32_t rowSize; // Not always = bmpWidth; may have padding uint8_t sdbuffer[3*BUFFPIXEL]; // pixel buffer (R+G+B per pixel) uint8_t buffidx = sizeof(sdbuffer); // Current position in sdbuffer boolean goodBmp = false; // Set to true on valid header parse boolean flip = true; // BMP is stored bottom-to-top int w, h, row, col; uint8_t r, g, b; uint32_t pos = 0, startTime = millis(); if((x >= tft.width()) || (y >= tft.height())) return; bmpFile = SD.open(filename); // Parse BMP header if(read16(bmpFile) == 0x4D42) { // BMP signature Serial.print(F("File size: "));Serial.println(read32(bmpFile)); (void)read32(bmpFile); // Read & ignore creator bytes bmpImageoffset = read32(bmpFile); // Start of image data Serial.print(F("Image Offset: ")); Serial.println(bmpImageoffset, DEC); // Read DIB header Serial.print(F("Header size: ")); Serial.println(read32(bmpFile)); bmpWidth = read32(bmpFile); bmpHeight = read32(bmpFile); if(read16(bmpFile) == 1) { // # planes -- must be '1' bmpDepth = read16(bmpFile); // bits per pixel Serial.print(F("Bit Depth: ")); Serial.println(bmpDepth); if((bmpDepth == 24) && (read32(bmpFile) == 0)) { // 0 = uncompressed goodBmp = true; // Supported BMP format -- proceed! // BMP rows are padded (if needed) to 4-byte boundary rowSize = (bmpWidth * 3 + 3) & ~3; // If bmpHeight is negative, image is in top-down order. // This is not canon but has been observed in the wild. if(bmpHeight < 0) { bmpHeight = -bmpHeight; flip = false; } // Crop area to be loaded w = bmpWidth; h = bmpHeight; if((x+w-1) >= tft.width()) w = tft.width() - x; if((y+h-1) >= tft.height()) h = tft.height() - y; // Set TFT address window to clipped image bounds tft.startWrite(); tft.setAddrWindow(x, y, w, h); for (row=0; row<h; row++) { // For each scanline... // Seek to start of scan line. It might seem labor- // intensive to be doing this on every line, but this // method covers a lot of gritty details like cropping // and scanline padding. Also, the seek only takes // place if the file position actually needs to change // (avoids a lot of cluster math in SD library). if(flip) // Bitmap is stored bottom-to-top order (normal BMP) pos = bmpImageoffset + (bmpHeight - 1 - row) * rowSize; else // Bitmap is stored top-to-bottom pos = bmpImageoffset + row * rowSize; if(bmpFile.position() != pos) { // Need seek? tft.endWrite(); bmpFile.seek(pos); buffidx = sizeof(sdbuffer); // Force buffer reload } for (col=0; col<w; col++) { // For each pixel... // Time to read more pixel data? if (buffidx >= sizeof(sdbuffer)) { // Indeed bmpFile.read(sdbuffer, sizeof(sdbuffer)); buffidx = 0; // Set index to beginning tft.startWrite(); } // Convert pixel from BMP to TFT format, push to display b = sdbuffer[buffidx++]; g = sdbuffer[buffidx++]; r = sdbuffer[buffidx++]; tft.pushColor(tft.color565(r,g,b)); } // end pixel } // end scanline tft.endWrite(); // Serial.print(F("Loaded in ")); //Serial.print(millis() - startTime); // Serial.println(" ms"); } // end goodBmp } } bmpFile.close(); //if(!goodBmp) Serial.println(F("BMP format not recognized.")); } // These read 16- and 32-bit types from the SD card file. // BMP data is stored little-endian, Arduino is little-endian too. // May need to reverse subscript order if porting elsewhere. uint16_t read16(File f) { uint16_t result; ((uint8_t *)&result)[0] = f.read(); // LSB ((uint8_t *)&result)[1] = f.read(); // MSB return result; } uint32_t read32(File f) { uint32_t result; ((uint8_t *)&result)[0] = f.read(); // LSB ((uint8_t *)&result)[1] = f.read(); ((uint8_t *)&result)[2] = f.read(); ((uint8_t *)&result)[3] = f.read(); // MSB return result; } |
要は、あのスイッチとなる部分のプログラムを削って、
bmpDraw(“MISA40.bmp”, 0, 0);
とファイル名を指定してやっただけですw
ちなみに、ファイル名の部分にはかならず「”」のマークを前後に付けてください。
その後ろの「0,0」はその画像の左上の始まる位置で、これによって画像の表示位置を変えることが出来ます。この辺は色々と数字を変えて試してみてください。
ちなみにこのライブラリーでは描画は上書きなので、画像を表示した後前回のグラフィックテストに載っていたコマンドでラインや文字を書き込むことも出来ます。つまりプログラムに書かれた順番が後の方が上に描画されるという事です。
それと色ですが、簡単な物でこの位あります。
ST77XX_BLUEと書かなくても0x001Fと書いてもいいようです。
ちなみにここに書いてあるようにBLUEと書くとエラー出ますw
ST77XX_YELLOWてな感じで「ST77XX_」が必要なようです。
なお画像の表示が一部おかしくなる時もたまにあります。そんな時はブレッドボードの接触不良がほとんどです。
これでこの液晶でのお約束の画像表示完了です!!
ただ、arduinoのコンパイル終了画面見てくださいw
ちょw
フラッシュメモリを71%も使ってますwこれじゃ他のプログラム書いていくとやばいかも・・・・
他の画面表示のプログラム追加すると
やっぱり、やばかったww!!
どうするよσ(゚∀゚ )オレw?? 続くw!
関連すると思われる記事:
- None Found
うむ。お疲れ様ですw
「何かをしたい!」ってエネルギーは大事ですね。
画面を横にして端っこにだけ任意の画像を表示したいっつう
よこしまなパワーがここまで勉強をさせるという。
Arduinoユーザーでよかった。
歩く前に、こんなに道を整備してくれる人たちがいるからw
Vividさんはこれをpicでほぼイチからやろうとしているわけでしょ?
もう神レベル変人ですねww
gyoさん こんにちは!
よこしまパワー全開ですw
gyoさん曰くの、とりあえず敵陣に突っ込んで行ってわけもわからず武器を振り回す感じですねw
多分ね、前回の記事とココの記事でBMP画像の表示は問題なくすんなり出来ると思いますよ。
ぜひ試してみる時にはこの記事の事思い出してやってくださいw
そうなんですよ~arduinoですからこの位で済んでいますが、これをPICで一からとかもう変人レベル通り越して神ですよねw
なんでもSDカードのデーターの読み出しに成功したとの報告も貰いましたw
もうホント凄すぎますw
ふたたびこんばんは!
いや、もうなんとも6jiroさんもすごすぎます。Vividさんはさらに宇宙の果ての領域だし(^^;
ここまできたら、どういう演出が飛び出すのか?この描画速度をどこまで改善して自然に見せてくれるのか?などさらに期待が膨らみます。ESP32も使いこなしちゃえば、SDカードモジュール持たなくてもWifiで外部からデータダウンロードしながら、とかもできちゃいそうでw
こんばんは!
変人です(笑)!
ほんと、6jiroさんのパワー凄いですね。これ、Arduinoに対する「愛」でしょうか?(笑)
当方は、PICのライブラリが見つかって、紆余曲折の末何とかTEXTファイルの読み書きができるようになりましたが、BMPファイルは、ヘッダーの解析などかなり敷居が高くて苦労しています。
あっ、そうそう、ちゃんと動作しているので良いのでしょうが、SDカードの信号線(電源以外)を5Vに10KΩ位でプルアップする必要があるみたいです。
私の場合、SDカードのイニシャライズコマンド(フォーマットではなく)の途中で、コマンドが通らず、ずーっと悩んで、色々調べたらプルアップが必要だとありました。
これをしたらすぐにOKになって、TEXTファイルのR/Wまで行けました。
なおさん 再びおはようございます!
なんか、色々と頑張っちゃいましたが、arduinoの限界も感じちゃいましたw
そもそもメモリーがこんなに少ないと液晶での表現には使えませんwポイッw
ここまで来ましたが、arduinoでのプログラミングは無理です。
次の選定としてESP32、ESP8266となるのですが、この辺でまたひと悶着有りますのでまた後日。
wifiやBluetoothとか使いたいんですけど送信側の問題なんですよね~。スマホのソフト開発なんて出来ないですもん^^;
変人Vividさん 再びおはようございます!
とにかく何とかしたいという意地みたいなものですw
それに色々とネットに情報がありますからね^^
なるほど!SDカードの時はプルアップ必要ですか~。実はその辺もESP32の時は試してみたのですが・・・・・。確かにarduinoでは動きましたが、プルアップした方が良いかもですね。
それにしてもSDカードのデーターのやり取り迄進まれましたか!
ホント出来ないことはありませんねw!やはり神ですw!