Modified Bob Stone's code for ILI9341 QVGA TFT's without touch capability. Navigation is now done with rotary encoders - two for position, & one setting the maxiterations.
Dependencies: SPI_TFT_ILI9341 TFT_fonts mbed
Fork of Mandelbrot by
Should have mentioned in the above: Encoder code is specific to the STM32F4, tested on Nucleo F401, should work on the Nucleo F411..
main.cpp@3:267e7130007d, 2015-01-22 (annotated)
- Committer:
- gregeric
- Date:
- Thu Jan 22 10:01:49 2015 +0000
- Revision:
- 3:267e7130007d
- Parent:
- 2:b1169b84a563
Increase debounce time, shown necessary after round of testing.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
RorschachUK | 0:a954bd7fd162 | 1 | /* Mandelbrot for mbed - April 2013 |
RorschachUK | 0:a954bd7fd162 | 2 | * Uses Peter Drescher's library for Mikroelektronika's TFT-Proto screen, an inexpensive SPI-driven QVGA touch panel |
RorschachUK | 0:a954bd7fd162 | 3 | * Library: http://mbed.org/cookbook/SPI-driven-QVGA-TFT |
RorschachUK | 0:a954bd7fd162 | 4 | * Manufacturer's page for the screen: http://www.mikroe.com/add-on-boards/display/tft-proto/ |
RorschachUK | 0:a954bd7fd162 | 5 | * UK distributor: http://www.mcustore.com/tft-proto-board.html |
RorschachUK | 0:a954bd7fd162 | 6 | * Partly adapted from Kamil Ondrousek's code for another screen: http://mbed.org/users/JLS/code/Mandelbrot-2/ |
RorschachUK | 0:a954bd7fd162 | 7 | */ |
gregeric | 2:b1169b84a563 | 8 | |
gregeric | 2:b1169b84a563 | 9 | |
gregeric | 2:b1169b84a563 | 10 | /* Adaptation for displays without touch screen from Bob Stone's https://developer.mbed.org/users/RorschachUK/code/Mandelbrot/ |
gregeric | 2:b1169b84a563 | 11 | * Instead, using cheap rotary encoders with integral button. |
gregeric | 2:b1169b84a563 | 12 | * Two encoders navigate the complex plane Z, a third changes the maxiterations value. |
gregeric | 2:b1169b84a563 | 13 | * Status (Z, zoom, maxiters) is shown on bottom of screen. |
gregeric | 2:b1169b84a563 | 14 | * |
gregeric | 2:b1169b84a563 | 15 | * Max-iters can be changed on the fly so that its effect on detail & colour rendering can be evaluated quickly. |
gregeric | 2:b1169b84a563 | 16 | * Drawing can be interrupted with any of the buttons to allow re-centering or re-zooming without having to wait for a full redraw. |
gregeric | 2:b1169b84a563 | 17 | * |
gregeric | 2:b1169b84a563 | 18 | * After the rendering is completed, or interrupted, these controls are available: |
gregeric | 2:b1169b84a563 | 19 | * Turning either of the position encoders will move a small cursor around the complex plane. |
gregeric | 2:b1169b84a563 | 20 | * Turning the third encoder will adjust maxiters. |
gregeric | 2:b1169b84a563 | 21 | * The buttons atop the Zr&Zi encoders set new zoom out/in levels & initiate drawing at that new zoom. |
gregeric | 2:b1169b84a563 | 22 | * The button atop the maxiters encoder initiates a re-draw at the current zoom. |
gregeric | 2:b1169b84a563 | 23 | * State rendering/idle is indicated by a '+'/' ' in the bottom right corner. |
gregeric | 2:b1169b84a563 | 24 | * |
gregeric | 2:b1169b84a563 | 25 | * David Lowe Jan 2015 |
gregeric | 2:b1169b84a563 | 26 | */ |
gregeric | 2:b1169b84a563 | 27 | |
RorschachUK | 0:a954bd7fd162 | 28 | #include "mbed.h" |
gregeric | 2:b1169b84a563 | 29 | #include "SPI_TFT_ILI9341.h" |
gregeric | 2:b1169b84a563 | 30 | #include "Encoder.h" |
gregeric | 2:b1169b84a563 | 31 | #include "Arial10x10.h" |
RorschachUK | 0:a954bd7fd162 | 32 | |
RorschachUK | 0:a954bd7fd162 | 33 | #define WIDTH 320 |
RorschachUK | 0:a954bd7fd162 | 34 | #define HEIGHT 240 |
gregeric | 2:b1169b84a563 | 35 | #define ORIENTATION 3 |
gregeric | 2:b1169b84a563 | 36 | SPI_TFT_ILI9341 tt(SPI_MOSI, SPI_MISO, SPI_SCK, D9, D6, D7,"TFT"); // mosi, miso, sclk, cs, reset, dc |
RorschachUK | 0:a954bd7fd162 | 37 | |
gregeric | 2:b1169b84a563 | 38 | // Wire all encoder commons to 3V3, |
gregeric | 2:b1169b84a563 | 39 | // encoder A&B outputs to A0 A1, D4 D5, D10 PB7 |
gregeric | 2:b1169b84a563 | 40 | TIM_Encoder_InitTypeDef encoder2, encoder3, encoder4; |
gregeric | 2:b1169b84a563 | 41 | TIM_HandleTypeDef timer2, timer3, timer4; |
gregeric | 2:b1169b84a563 | 42 | |
gregeric | 2:b1169b84a563 | 43 | //Wire one side of button to 3V3 (same as encoder common connections) |
gregeric | 2:b1169b84a563 | 44 | InterruptIn zoominbutton(D3); //@ encoder3: real (x) axis, button -> redraw zoom out |
gregeric | 2:b1169b84a563 | 45 | InterruptIn zoomoutbutton(D2); //@ encoder2: imaginary (y) axis, button -> redraw zoom in |
gregeric | 2:b1169b84a563 | 46 | InterruptIn zoomsamebutton(USER_BUTTON); //@ encoder4: iterations, button -> redraw zoom unchanged |
gregeric | 2:b1169b84a563 | 47 | |
gregeric | 2:b1169b84a563 | 48 | //Setup base Mandelbrot |
gregeric | 2:b1169b84a563 | 49 | double centrex = -0.5; |
gregeric | 2:b1169b84a563 | 50 | double centrey = -0.0; |
gregeric | 2:b1169b84a563 | 51 | double zoom=0.5; |
gregeric | 2:b1169b84a563 | 52 | int32_t log2zoom=-1; |
RorschachUK | 0:a954bd7fd162 | 53 | |
gregeric | 2:b1169b84a563 | 54 | #define MAXITERS 8192 |
gregeric | 2:b1169b84a563 | 55 | #define MINITERS 64 |
gregeric | 2:b1169b84a563 | 56 | #define maxiters (MINITERS+TIM4->CNT) |
gregeric | 2:b1169b84a563 | 57 | uint16_t lastiters=MINITERS; |
gregeric | 2:b1169b84a563 | 58 | |
gregeric | 3:267e7130007d | 59 | enum nextaction_t { |
gregeric | 2:b1169b84a563 | 60 | idle=0, |
gregeric | 2:b1169b84a563 | 61 | zoomin, |
gregeric | 2:b1169b84a563 | 62 | zoomout, |
gregeric | 2:b1169b84a563 | 63 | zoomsame, |
gregeric | 2:b1169b84a563 | 64 | interrupted |
gregeric | 2:b1169b84a563 | 65 | }; |
gregeric | 2:b1169b84a563 | 66 | |
gregeric | 3:267e7130007d | 67 | nextaction_t buttonpressed; |
gregeric | 2:b1169b84a563 | 68 | |
gregeric | 2:b1169b84a563 | 69 | void GotZoomIn(void) |
gregeric | 2:b1169b84a563 | 70 | { |
gregeric | 2:b1169b84a563 | 71 | buttonpressed=zoomin; |
gregeric | 2:b1169b84a563 | 72 | } |
RorschachUK | 0:a954bd7fd162 | 73 | |
gregeric | 2:b1169b84a563 | 74 | void GotZoomOut(void) |
gregeric | 2:b1169b84a563 | 75 | { |
gregeric | 2:b1169b84a563 | 76 | buttonpressed=zoomout; |
gregeric | 2:b1169b84a563 | 77 | } |
RorschachUK | 0:a954bd7fd162 | 78 | |
gregeric | 2:b1169b84a563 | 79 | void GotZoomSame(void) |
gregeric | 2:b1169b84a563 | 80 | { |
gregeric | 2:b1169b84a563 | 81 | buttonpressed=zoomsame; |
gregeric | 2:b1169b84a563 | 82 | } |
gregeric | 2:b1169b84a563 | 83 | |
gregeric | 2:b1169b84a563 | 84 | void UpdateStats(void) |
gregeric | 2:b1169b84a563 | 85 | { |
gregeric | 2:b1169b84a563 | 86 | //invert orientation & set cursor to top left (our bottom right at usual orientation) |
gregeric | 2:b1169b84a563 | 87 | tt.set_orientation(ORIENTATION^2); |
gregeric | 2:b1169b84a563 | 88 | tt.locate(0,0); |
gregeric | 2:b1169b84a563 | 89 | //indicate "rendering active" & erase a few chars at line end |
gregeric | 2:b1169b84a563 | 90 | tt.printf("+ "); |
RorschachUK | 0:a954bd7fd162 | 91 | |
gregeric | 2:b1169b84a563 | 92 | //write current infos to bottom of screen: real, imag, log2(zoom), maxiters |
gregeric | 2:b1169b84a563 | 93 | tt.set_orientation(ORIENTATION); |
gregeric | 2:b1169b84a563 | 94 | tt.locate(0,240-10); |
gregeric | 2:b1169b84a563 | 95 | tt.printf("%1.16f%+1.16fi %d %d", centrex, -centrey, log2zoom, maxiters); |
gregeric | 2:b1169b84a563 | 96 | } |
gregeric | 2:b1169b84a563 | 97 | |
gregeric | 2:b1169b84a563 | 98 | void DrawMandelbrot(void) |
gregeric | 2:b1169b84a563 | 99 | { |
gregeric | 2:b1169b84a563 | 100 | double xmin = centrex - 1.0/zoom; |
gregeric | 2:b1169b84a563 | 101 | double xmax = centrex + 1.0/zoom; |
gregeric | 2:b1169b84a563 | 102 | double ymin = centrey - HEIGHT / (WIDTH * zoom); |
gregeric | 2:b1169b84a563 | 103 | double ymax = centrey + HEIGHT / (WIDTH *zoom); |
gregeric | 2:b1169b84a563 | 104 | |
gregeric | 2:b1169b84a563 | 105 | double dx = (xmax - xmin) / WIDTH; |
gregeric | 2:b1169b84a563 | 106 | double dy = (ymax - ymin) / HEIGHT; |
gregeric | 2:b1169b84a563 | 107 | |
gregeric | 2:b1169b84a563 | 108 | double y = ymin; |
gregeric | 2:b1169b84a563 | 109 | |
gregeric | 2:b1169b84a563 | 110 | double c; |
RorschachUK | 0:a954bd7fd162 | 111 | unsigned int cr, cg, cb; |
gregeric | 2:b1169b84a563 | 112 | |
RorschachUK | 0:a954bd7fd162 | 113 | for (int j = 0; j < HEIGHT; j++) { |
gregeric | 2:b1169b84a563 | 114 | double x = xmin; |
RorschachUK | 0:a954bd7fd162 | 115 | |
RorschachUK | 0:a954bd7fd162 | 116 | for (int i = 0; i < WIDTH; i++) { |
gregeric | 2:b1169b84a563 | 117 | double a = x; |
gregeric | 2:b1169b84a563 | 118 | double b = y; |
RorschachUK | 0:a954bd7fd162 | 119 | int n = 0; |
RorschachUK | 0:a954bd7fd162 | 120 | |
gregeric | 2:b1169b84a563 | 121 | if (maxiters!=lastiters) { //update stats if user changes maxiters on-the-fly |
gregeric | 2:b1169b84a563 | 122 | UpdateStats(); |
gregeric | 2:b1169b84a563 | 123 | lastiters=maxiters; |
gregeric | 2:b1169b84a563 | 124 | } |
gregeric | 2:b1169b84a563 | 125 | |
gregeric | 2:b1169b84a563 | 126 | while (n < maxiters) { |
gregeric | 2:b1169b84a563 | 127 | double aa = a * a; |
gregeric | 2:b1169b84a563 | 128 | double bb = b * b; |
gregeric | 2:b1169b84a563 | 129 | double twoab = 2.0 * a * b; |
RorschachUK | 0:a954bd7fd162 | 130 | |
RorschachUK | 0:a954bd7fd162 | 131 | a = aa - bb + x; |
RorschachUK | 0:a954bd7fd162 | 132 | b = twoab + y; |
RorschachUK | 0:a954bd7fd162 | 133 | |
RorschachUK | 0:a954bd7fd162 | 134 | if(aa + bb > 16.0) { |
RorschachUK | 0:a954bd7fd162 | 135 | break; |
RorschachUK | 0:a954bd7fd162 | 136 | } |
RorschachUK | 0:a954bd7fd162 | 137 | n++; |
RorschachUK | 0:a954bd7fd162 | 138 | } |
RorschachUK | 0:a954bd7fd162 | 139 | |
gregeric | 2:b1169b84a563 | 140 | if (n == maxiters) { |
RorschachUK | 0:a954bd7fd162 | 141 | //It's in the set - Black |
RorschachUK | 0:a954bd7fd162 | 142 | tt.pixel(i,j,Black); |
RorschachUK | 0:a954bd7fd162 | 143 | } else { |
RorschachUK | 0:a954bd7fd162 | 144 | //Not in the set - pick a colour |
gregeric | 2:b1169b84a563 | 145 | c = 3.0 * (maxiters-n)/maxiters; |
RorschachUK | 0:a954bd7fd162 | 146 | cr = ((c < 1.0) ? 255 * ( 1.0 - c) : (c > 2.0) ? 255 * (c - 2.0) : 0); |
RorschachUK | 0:a954bd7fd162 | 147 | cg = ((c < 1.0) ? 255 * c : (c > 2.0) ? 0 : 255 * (2.0 - c)); |
RorschachUK | 0:a954bd7fd162 | 148 | cb = ((c < 1.0) ? 0 : (c > 2.0) ? 255 * (3.0 - c) : 255 * (c - 1.0)); |
RorschachUK | 0:a954bd7fd162 | 149 | tt.pixel(i,j, RGB(cr,cg,cb)); |
RorschachUK | 0:a954bd7fd162 | 150 | } |
RorschachUK | 0:a954bd7fd162 | 151 | x += dx; |
gregeric | 2:b1169b84a563 | 152 | if (buttonpressed) return; |
RorschachUK | 0:a954bd7fd162 | 153 | } |
RorschachUK | 0:a954bd7fd162 | 154 | y += dy; |
RorschachUK | 0:a954bd7fd162 | 155 | } |
RorschachUK | 0:a954bd7fd162 | 156 | } |
RorschachUK | 0:a954bd7fd162 | 157 | |
gregeric | 2:b1169b84a563 | 158 | void PixelBrot(int i, int j) |
gregeric | 2:b1169b84a563 | 159 | { |
gregeric | 2:b1169b84a563 | 160 | double xmin = centrex - 1.0/zoom; |
gregeric | 2:b1169b84a563 | 161 | double xmax = centrex + 1.0/zoom; |
gregeric | 2:b1169b84a563 | 162 | double ymin = centrey - HEIGHT / (WIDTH * zoom); |
gregeric | 2:b1169b84a563 | 163 | double ymax = centrey + HEIGHT / (WIDTH *zoom); |
gregeric | 2:b1169b84a563 | 164 | |
gregeric | 2:b1169b84a563 | 165 | double dx = (xmax - xmin) / WIDTH; |
gregeric | 2:b1169b84a563 | 166 | double dy = (ymax - ymin) / HEIGHT; |
gregeric | 2:b1169b84a563 | 167 | |
gregeric | 2:b1169b84a563 | 168 | double x=xmin+dx*i; |
gregeric | 2:b1169b84a563 | 169 | double y=ymin+dy*j; |
gregeric | 2:b1169b84a563 | 170 | |
gregeric | 2:b1169b84a563 | 171 | double a = x; |
gregeric | 2:b1169b84a563 | 172 | double b = y; |
gregeric | 2:b1169b84a563 | 173 | int n = 0; |
gregeric | 2:b1169b84a563 | 174 | double c; |
gregeric | 2:b1169b84a563 | 175 | unsigned int cr, cg, cb; |
gregeric | 2:b1169b84a563 | 176 | |
gregeric | 2:b1169b84a563 | 177 | while (n < maxiters) { |
gregeric | 2:b1169b84a563 | 178 | double aa = a * a; |
gregeric | 2:b1169b84a563 | 179 | double bb = b * b; |
gregeric | 2:b1169b84a563 | 180 | double twoab = 2.0 * a * b; |
gregeric | 2:b1169b84a563 | 181 | |
gregeric | 2:b1169b84a563 | 182 | a = aa - bb + x; |
gregeric | 2:b1169b84a563 | 183 | b = twoab + y; |
gregeric | 2:b1169b84a563 | 184 | |
gregeric | 2:b1169b84a563 | 185 | if(aa + bb > 16.0) { |
gregeric | 2:b1169b84a563 | 186 | break; |
gregeric | 2:b1169b84a563 | 187 | } |
gregeric | 2:b1169b84a563 | 188 | n++; |
gregeric | 2:b1169b84a563 | 189 | } |
gregeric | 2:b1169b84a563 | 190 | |
gregeric | 2:b1169b84a563 | 191 | if (n == maxiters) { |
gregeric | 2:b1169b84a563 | 192 | //It's in the set - Black |
gregeric | 2:b1169b84a563 | 193 | tt.pixel(i,j,Black); |
gregeric | 2:b1169b84a563 | 194 | } else { |
gregeric | 2:b1169b84a563 | 195 | //Not in the set - pick a colour |
gregeric | 2:b1169b84a563 | 196 | c = 3.0 * (maxiters-n)/maxiters; |
gregeric | 2:b1169b84a563 | 197 | cr = ((c < 1.0) ? 255 * ( 1.0 - c) : (c > 2.0) ? 255 * (c - 2.0) : 0); |
gregeric | 2:b1169b84a563 | 198 | cg = ((c < 1.0) ? 255 * c : (c > 2.0) ? 0 : 255 * (2.0 - c)); |
gregeric | 2:b1169b84a563 | 199 | cb = ((c < 1.0) ? 0 : (c > 2.0) ? 255 * (3.0 - c) : 255 * (c - 1.0)); |
gregeric | 2:b1169b84a563 | 200 | tt.pixel(i,j, RGB(cr,cg,cb)); |
gregeric | 2:b1169b84a563 | 201 | } |
gregeric | 2:b1169b84a563 | 202 | |
gregeric | 2:b1169b84a563 | 203 | } |
gregeric | 2:b1169b84a563 | 204 | |
gregeric | 2:b1169b84a563 | 205 | void EraseCursor(int x, int y) |
gregeric | 2:b1169b84a563 | 206 | { |
gregeric | 2:b1169b84a563 | 207 | int x1,x2,y1,y2; |
gregeric | 2:b1169b84a563 | 208 | |
gregeric | 2:b1169b84a563 | 209 | x1=x-3; |
gregeric | 2:b1169b84a563 | 210 | if (x1<0) x1=0; |
gregeric | 2:b1169b84a563 | 211 | if (x1>WIDTH-1) x1=WIDTH-1; |
gregeric | 2:b1169b84a563 | 212 | x2=x+3; |
gregeric | 2:b1169b84a563 | 213 | if (x2<0) x2=0; |
gregeric | 2:b1169b84a563 | 214 | if (x2>WIDTH-1) x2=WIDTH-1; |
gregeric | 2:b1169b84a563 | 215 | |
gregeric | 2:b1169b84a563 | 216 | y1=y-3; |
gregeric | 2:b1169b84a563 | 217 | if (y1<0) y1=0; |
gregeric | 2:b1169b84a563 | 218 | if (y1>HEIGHT-1) y1=HEIGHT-1; |
gregeric | 2:b1169b84a563 | 219 | y2=y+3; |
gregeric | 2:b1169b84a563 | 220 | if (y2<0) y2=0; |
gregeric | 2:b1169b84a563 | 221 | if (y2>HEIGHT-1) y2=HEIGHT-1; |
gregeric | 2:b1169b84a563 | 222 | |
gregeric | 2:b1169b84a563 | 223 | if (x<0) x=0; |
gregeric | 2:b1169b84a563 | 224 | if (x>WIDTH-1) x=WIDTH-1; |
gregeric | 2:b1169b84a563 | 225 | |
gregeric | 2:b1169b84a563 | 226 | if (y<0) y=0; |
gregeric | 2:b1169b84a563 | 227 | if (y>HEIGHT-1) y=HEIGHT-1; |
gregeric | 2:b1169b84a563 | 228 | |
gregeric | 2:b1169b84a563 | 229 | //Overwite crosshair |
gregeric | 2:b1169b84a563 | 230 | int i; |
gregeric | 2:b1169b84a563 | 231 | for(i=x1; i<=x2; i++) PixelBrot(i,y); |
gregeric | 2:b1169b84a563 | 232 | for(i=y1; i<=y2; i++) PixelBrot(x,i); |
gregeric | 2:b1169b84a563 | 233 | } |
gregeric | 2:b1169b84a563 | 234 | |
gregeric | 2:b1169b84a563 | 235 | void DrawCursor(int x, int y) |
gregeric | 2:b1169b84a563 | 236 | { |
gregeric | 2:b1169b84a563 | 237 | int x1,x2,y1,y2; |
gregeric | 2:b1169b84a563 | 238 | |
gregeric | 2:b1169b84a563 | 239 | x1=x-3; |
gregeric | 2:b1169b84a563 | 240 | if (x1<0) x1=0; |
gregeric | 2:b1169b84a563 | 241 | if (x1>WIDTH-1) x1=WIDTH-1; |
gregeric | 2:b1169b84a563 | 242 | x2=x+3; |
gregeric | 2:b1169b84a563 | 243 | if (x2<0) x2=0; |
gregeric | 2:b1169b84a563 | 244 | if (x2>WIDTH-1) x2=WIDTH-1; |
gregeric | 2:b1169b84a563 | 245 | |
gregeric | 2:b1169b84a563 | 246 | y1=y-3; |
gregeric | 2:b1169b84a563 | 247 | if (y1<0) y1=0; |
gregeric | 2:b1169b84a563 | 248 | if (y1>HEIGHT-1) y1=HEIGHT-1; |
gregeric | 2:b1169b84a563 | 249 | y2=y+3; |
gregeric | 2:b1169b84a563 | 250 | if (y2<0) y2=0; |
gregeric | 2:b1169b84a563 | 251 | if (y2>HEIGHT-1) y2=HEIGHT-1; |
gregeric | 2:b1169b84a563 | 252 | |
gregeric | 2:b1169b84a563 | 253 | if (x<0) x=0; |
gregeric | 2:b1169b84a563 | 254 | if (x>WIDTH-1) x=WIDTH-1; |
gregeric | 2:b1169b84a563 | 255 | |
gregeric | 2:b1169b84a563 | 256 | if (y<0) y=0; |
gregeric | 2:b1169b84a563 | 257 | if (y>HEIGHT-1) y=HEIGHT-1; |
gregeric | 2:b1169b84a563 | 258 | |
gregeric | 2:b1169b84a563 | 259 | //Draw crosshair |
gregeric | 2:b1169b84a563 | 260 | tt.line(x,y1,x,y2,White); |
gregeric | 2:b1169b84a563 | 261 | tt.line(x1,y,x2,y,White); |
gregeric | 2:b1169b84a563 | 262 | } |
gregeric | 2:b1169b84a563 | 263 | |
gregeric | 2:b1169b84a563 | 264 | void InitEncoders(void) |
gregeric | 2:b1169b84a563 | 265 | { |
gregeric | 2:b1169b84a563 | 266 | //TIM1 is used by mbed for SPI clocking |
gregeric | 2:b1169b84a563 | 267 | |
gregeric | 2:b1169b84a563 | 268 | //A0 A1, common to 3V3 |
gregeric | 2:b1169b84a563 | 269 | //counting on both B-input only, 2 ticks per cycle, full 32-bit count |
gregeric | 2:b1169b84a563 | 270 | EncoderInit(encoder2, timer2, TIM2, 0xffffffff, TIM_ENCODERMODE_TI2); |
gregeric | 2:b1169b84a563 | 271 | |
gregeric | 2:b1169b84a563 | 272 | //D4 D5, common to 3V3 |
gregeric | 2:b1169b84a563 | 273 | //counting on B-input only, 2 ticks per cycle, full 16-bit count |
gregeric | 2:b1169b84a563 | 274 | EncoderInit(encoder3, timer3, TIM3, 0xffff, TIM_ENCODERMODE_TI2); |
gregeric | 2:b1169b84a563 | 275 | |
gregeric | 2:b1169b84a563 | 276 | //D10 PB7, common to 3V3 |
gregeric | 2:b1169b84a563 | 277 | //counting on both A&B edges, 4 ticks per cycle, max count used to limit maxiters to range (MINITERS..MAXITERS) |
gregeric | 2:b1169b84a563 | 278 | EncoderInit(encoder4, timer4, TIM4, MAXITERS-MINITERS+3, TIM_ENCODERMODE_TI12); |
gregeric | 2:b1169b84a563 | 279 | |
gregeric | 2:b1169b84a563 | 280 | //TIM5 is used by mbed for us_ticker |
gregeric | 2:b1169b84a563 | 281 | } |
gregeric | 2:b1169b84a563 | 282 | |
RorschachUK | 0:a954bd7fd162 | 283 | int main() |
RorschachUK | 0:a954bd7fd162 | 284 | { |
RorschachUK | 0:a954bd7fd162 | 285 | //Setup screen |
RorschachUK | 0:a954bd7fd162 | 286 | tt.background(Black); // set background to black |
RorschachUK | 0:a954bd7fd162 | 287 | tt.foreground(White); // set chars to white |
RorschachUK | 0:a954bd7fd162 | 288 | tt.cls(); // clear the screen |
gregeric | 2:b1169b84a563 | 289 | tt.set_font((unsigned char*)Arial10x10); |
gregeric | 2:b1169b84a563 | 290 | |
gregeric | 2:b1169b84a563 | 291 | InitEncoders(); |
RorschachUK | 0:a954bd7fd162 | 292 | |
gregeric | 2:b1169b84a563 | 293 | zoominbutton.rise(&GotZoomIn); |
gregeric | 2:b1169b84a563 | 294 | zoominbutton.mode(PullDown); |
gregeric | 2:b1169b84a563 | 295 | zoomoutbutton.rise(&GotZoomOut); |
gregeric | 2:b1169b84a563 | 296 | zoomoutbutton.mode(PullDown); |
gregeric | 2:b1169b84a563 | 297 | zoomsamebutton.rise(&GotZoomSame); |
gregeric | 2:b1169b84a563 | 298 | zoomsamebutton.mode(PullDown); |
RorschachUK | 0:a954bd7fd162 | 299 | |
RorschachUK | 0:a954bd7fd162 | 300 | while(true) { |
gregeric | 2:b1169b84a563 | 301 | |
gregeric | 2:b1169b84a563 | 302 | //log status @ PC serial port |
gregeric | 2:b1169b84a563 | 303 | printf("%1.18f%+1.18fi, %+d, %d\n\r", centrex, -centrey, log2zoom, maxiters); |
gregeric | 2:b1169b84a563 | 304 | |
gregeric | 3:267e7130007d | 305 | wait(0.3); //debounce |
gregeric | 2:b1169b84a563 | 306 | buttonpressed=idle; |
gregeric | 2:b1169b84a563 | 307 | |
gregeric | 2:b1169b84a563 | 308 | UpdateStats(); |
gregeric | 2:b1169b84a563 | 309 | |
gregeric | 2:b1169b84a563 | 310 | //Draw the thing, can be interrupted by a button press |
gregeric | 2:b1169b84a563 | 311 | tt.set_orientation(ORIENTATION); |
gregeric | 2:b1169b84a563 | 312 | DrawMandelbrot(); |
gregeric | 2:b1169b84a563 | 313 | |
gregeric | 3:267e7130007d | 314 | wait(0.3); //debounce |
gregeric | 2:b1169b84a563 | 315 | //flag that we should update status bar, but not commence new render |
gregeric | 2:b1169b84a563 | 316 | if (buttonpressed) buttonpressed=interrupted; |
gregeric | 2:b1169b84a563 | 317 | |
gregeric | 2:b1169b84a563 | 318 | //throw away any user-twiddling of real & imaginary encoders made while rendering |
gregeric | 2:b1169b84a563 | 319 | TIM2->CNT=0; |
gregeric | 2:b1169b84a563 | 320 | TIM3->CNT=0; |
gregeric | 2:b1169b84a563 | 321 | |
gregeric | 2:b1169b84a563 | 322 | int16_t shiftx, shifty; |
gregeric | 2:b1169b84a563 | 323 | int16_t lastshiftx=0, lastshifty=0; |
gregeric | 2:b1169b84a563 | 324 | |
gregeric | 2:b1169b84a563 | 325 | while(true) { // loop until a redraw button is pressed, then go draw something |
gregeric | 2:b1169b84a563 | 326 | |
gregeric | 2:b1169b84a563 | 327 | while(true) { //loop forever until real or imag or iters dials have moved, or any of the redraw buttons pressed |
gregeric | 2:b1169b84a563 | 328 | shiftx=(int16_t)TIM2->CNT/2; |
gregeric | 2:b1169b84a563 | 329 | shifty=(int16_t)TIM3->CNT/2; |
gregeric | 2:b1169b84a563 | 330 | if (buttonpressed) break; |
gregeric | 2:b1169b84a563 | 331 | if (shiftx!=lastshiftx || shifty!=lastshifty || maxiters!=lastiters) break; |
gregeric | 2:b1169b84a563 | 332 | } |
gregeric | 2:b1169b84a563 | 333 | |
gregeric | 3:267e7130007d | 334 | if(maxiters==lastiters) { //we're here cos cursor moved (speeds up redraw when twiddling maxiter knob |
gregeric | 3:267e7130007d | 335 | EraseCursor(WIDTH/2+lastshiftx, HEIGHT/2+lastshifty); |
gregeric | 3:267e7130007d | 336 | DrawCursor(WIDTH/2+shiftx, HEIGHT/2+shifty); |
gregeric | 3:267e7130007d | 337 | } |
gregeric | 2:b1169b84a563 | 338 | |
gregeric | 2:b1169b84a563 | 339 | lastshiftx=shiftx; |
gregeric | 2:b1169b84a563 | 340 | lastshifty=shifty; |
gregeric | 2:b1169b84a563 | 341 | lastiters=maxiters; |
gregeric | 2:b1169b84a563 | 342 | |
gregeric | 2:b1169b84a563 | 343 | if(buttonpressed==interrupted) buttonpressed=idle; //draw was halted, update status & wait for new controls |
gregeric | 2:b1169b84a563 | 344 | if(buttonpressed) break; //go redraw whole screen with updated centre/zoom/maxiters |
gregeric | 2:b1169b84a563 | 345 | |
gregeric | 2:b1169b84a563 | 346 | //erase a few chars at line end |
gregeric | 2:b1169b84a563 | 347 | tt.set_orientation(ORIENTATION^2); |
gregeric | 2:b1169b84a563 | 348 | tt.locate(0,0); |
gregeric | 2:b1169b84a563 | 349 | tt.printf(" "); |
gregeric | 2:b1169b84a563 | 350 | |
gregeric | 2:b1169b84a563 | 351 | //write ammended infos to bottom of screen: real, imag, log2(zoom), maxiters |
gregeric | 2:b1169b84a563 | 352 | tt.set_orientation(ORIENTATION); |
gregeric | 2:b1169b84a563 | 353 | tt.locate(0,240-10); |
gregeric | 2:b1169b84a563 | 354 | tt.printf("%1.16f%+1.16fi %d %d",centrex+((double)(shiftx*2))/(WIDTH*zoom), |
gregeric | 2:b1169b84a563 | 355 | -(centrey+((double)(shifty*2))/(WIDTH*zoom)), |
gregeric | 2:b1169b84a563 | 356 | buttonpressed==1 ? log2zoom+2 : (buttonpressed==2 ? log2zoom-2 : log2zoom), |
gregeric | 2:b1169b84a563 | 357 | maxiters); |
RorschachUK | 0:a954bd7fd162 | 358 | } |
gregeric | 2:b1169b84a563 | 359 | |
gregeric | 2:b1169b84a563 | 360 | centrex += ((double)(shiftx*2))/(WIDTH*zoom); |
gregeric | 2:b1169b84a563 | 361 | centrey += ((double)(shifty*2))/(WIDTH*zoom); |
gregeric | 2:b1169b84a563 | 362 | |
gregeric | 2:b1169b84a563 | 363 | if(buttonpressed==zoomin) { |
gregeric | 2:b1169b84a563 | 364 | zoom*=4.0; |
gregeric | 2:b1169b84a563 | 365 | log2zoom+=2; |
gregeric | 2:b1169b84a563 | 366 | } |
gregeric | 2:b1169b84a563 | 367 | if(buttonpressed==zoomout) { |
gregeric | 2:b1169b84a563 | 368 | zoom/=4.0; |
gregeric | 2:b1169b84a563 | 369 | log2zoom-=2; |
gregeric | 2:b1169b84a563 | 370 | } |
gregeric | 2:b1169b84a563 | 371 | //buttonpressed==zoomsame, redraw with zoom unchanged |
RorschachUK | 0:a954bd7fd162 | 372 | } |
RorschachUK | 0:a954bd7fd162 | 373 | } |