/* 0.96インチOLEDにマンデルブロ集合を描く write mandelbrot set on 0.96inch OLED 2020/05/26 ラジオペンチ http://radiopench.blog96.fc2.com/ */ #include #include #include #define zRatio 2.0 // ズーム比率 zoom up ratio Adafruit_SSD1306 oled(128, 64, &Wire, -1); // device name is oled struct body { // 条件表の構造 structure of table int s_pN; // プログラムNo. prog. No. float s_x; // X座標 x position float s_y; // Y座標 y position float s_mag; // 初期倍率(表示サイズ)initial plane size int s_zN; // ズーム回数 zooming times int s_iN; // イタレーション回数 iteration times }; struct body recipe[10] = { // 表示レシピの設定表 spec. table for display { 1, -0.65, 0.0, 0.0625, 4, 100}, // 全体像 over view of mandelbot set { 2, -0.22255579, 1.119984429, 1.0, 19, 100}, // 本体上部のエンドレスなヒゲ endless whisker { 3, -1.2556, 0.380974, 1.0, 7, 100}, // 隠れた集合hiddon shape { 4, -1.73959677, 2.562320E-4, 100.0, 9, 100}, // ワーム warm { 5, -1.941239, 0.0, 0.5, 10, 100}, // 左端付近に隠れた集合 flower and mandelblot set { 6, -1.7489405, 0.0, 2000.0, 5, 100}, // 魚の骨と花 fish bone and flower(high mag) { 7, -1.26233923, 0.40812936, 2.0, 9, 100}, // 左の丸の上に隠れた集合 hidden set { 8, 0.269194959, 0.00440711, 1000.0, 5, 100}, // アンモナイトAmmonite { 9, 999.9, 0.0, 1.00, 1, 100} // 終了 end definition }; void setup() { pinMode(12, INPUT_PULLUP); // 一時停止スイッチ pause switch (pause when connect to GND) pinMode(13, OUTPUT); // 計算中表示LED calculation status display LED Serial.begin(115200); oled.begin(SSD1306_SWITCHCAPVCC, 0x3C); // OLEDのI2Cアドレス(モジュールの設定に合わせる)set I2C address for the module startScreen(); // 開始画面表示 display start screen } void loop() { // main int px, py; // 画面の作画座標 screen address float x0, y0; // マンデルブロ空間の中心位置 center address of screen float mag, pitch; // サイズ display size variable float x, y; // マンデルブロ判定座標 mandelbrot judgement position int pN; // プログラム番号 program No. int mResult; // マンデルブロ領域判定結果 mandelbrot judgement result int zN; // ズーム回数 zooming Number int col; // 表示色 dosplay color int iN; // イタレーション回数 iteration number for (int i = 0; i < 10; i++) { // 設定されたパターンを読み出して順に実行 execute the pattern in sequence pN = recipe[i].s_pN; // プログラムNo. program nunber x0 = recipe[i].s_x; // X座標 x position if (abs(x0) >= 900) { // もし値が900以上なら if the value over 900 break; // 中止(最初に戻る) end this loop and return begginig } y0 = recipe[i].s_y; // Y y position mag = recipe[i].s_mag; // 初期倍率(サイズ)initial magnification(size) zN = recipe[i].s_zN; // ズーム回数 zooming number of times iN = recipe[i].s_iN; // イタレーション回数 iteration numbers oled.clearDisplay(); // 先頭で画面を全クリア clear display writeBorder(); // 外形枠を描く write border graphic area for (int z = 0; z <= zN; z++) { // 指定のズーム回数繰り返す execute specified timescount pitch = 1.0 / (30.0 * mag); // y軸サイズ=±30画素(61画素)pitch value calc. Serial.print(pN); Serial.print(", "); Serial.println(mag, 2); paraDisp(pN, z, x0, y0, mag); // display numeric informations oled.display(); for (py = 1; py <= 61; py++) { // Y軸画面サイズ(1-61) display position of x for (px = 40; px <= 126; px++) { // X軸画面サイズ指定(40-126) display position of y x = (83 - px) * pitch - x0; // calculate the position value y = - (31 - py) * pitch - y0; mResult = mandelbrot(x, y, iN); // マンデルブロ判定 Mandelbrot judgement if (mResult == 0) { // 内側なら if inside of the area col = BLACK; // 黒で塗る paint black } else { // 外側なら if outside and, if ((mResult % 2) == 0) { // 判定結果が偶数なら、if result is even number col = WHITE; // 白!paint white } else { // そうでなかったら、odd number, so col = BLACK; // 黒!paint black } } oled.drawPixel(px, py, col); // 画面にプロット plot result on OLED } // x loop completed oled.display(); // 実際の表示(1行ずつ更新)display execute (line by line) } delay(1000); // 次の面の開始までちょっと待つ wait while (digitalRead(12) == LOW) { // ピン12がLOW(ONだったら)if halt switch is ON } // wait mag *= zRatio; // 拡大 zoom up next show } delay(2000); // プログラムの境で長めに待つ long wait between program } // end of main } int mandelbrot(float a, float b, int maxN) { // マンデルブロ領域判定, Mandelbrot area judgment float xM = 0.0, yM = 0.0; // xMemory,yMemory float x1, y1; // temporary register for calc. for (int n = 1; n < maxN; n++) { // 指定回数までチェック, check up to specified times digitalWrite(13, HIGH); x1 = xM * xM - yM * yM - a; // element of calc. y1 = 2.0 * xM * yM - b; digitalWrite(13, LOW); if ( x1 * x1 + y1 * y1 > 4.0 ) { // 発散していたら, if it was diverging (over 4) return n; // その回数を返す return the count } xM = x1; // 次のループ用に値を保存 Save value for next loop yM = y1; } return 0; // 指定回数内で発散しなければ(収束したとみなす)Returns zero if it dooes't diverge } void paraDisp(int i, int z, float x0, float y0, float mag) { oled.fillRect(0, 0, 37, 64, BLACK); // erase character display area oled.setCursor(0, 0); oled.setTextColor(WHITE); oled.print("P:"); // disp prog. No. oled.print(i); oled.print(","); oled.println(z); oled.println("mag:"); // disp magnification if (mag < 1) { oled.println(mag, 2); // *.** } else { oled.println(mag, 0); // ** } oled.println(); oled.println("x:"); // x poition oled.println(x0, 3); oled.println("y:"); // y position oled.println(y0, 3); } void writeBorder() { // write graphic area border line oled.drawFastHLine( 39, 0, 43, WHITE); // upper left hrizontal line oled.drawFastHLine( 85, 0, 43, WHITE); // upper right oled.drawFastHLine( 39, 62, 43, WHITE); // lower left oled.drawFastHLine( 85, 62, 43, WHITE); // lower right oled.drawFastHLine( 37, 31, 3, WHITE); // left center short mark (y0) oled.drawFastHLine( 127, 31, 1, WHITE); // right center mark (y0) oled.drawFastVLine( 39, 0, 30, WHITE); // left upper oled.drawFastVLine( 39, 33, 30, WHITE); // left lower oled.drawFastVLine(127, 0, 30, WHITE); // right upper oled.drawFastVLine(127, 33, 30, WHITE); // right lower oled.drawFastVLine( 83, 0, 1, WHITE); // upper center dot (x0) oled.drawFastVLine( 83, 62, 2, WHITE); // lower center short line (x0) } void startScreen() { // 開始時表示画面 oled.clearDisplay(); oled.setTextColor(WHITE); oled.println("Mandelbrot set"); oled.println("version 0.7"); // version No. oled.println("by radiopench1"); // oled.display(); delay(2000); }