Print bitmaps, cellular automata, drawings and text..
if ( digitalRead(btnPin) == HIGH ){ tft.fillCircle(cur_x, cur_y, 2,WHITE); int x_index = cur_x / 8; int y_index = constrain(cur_y,0, pic_height-8); for (int j = 0; j < 8; j++){ int i = x_index + ((y_index+j)*pic_width); bitmap[i] = 0xFF ; }
On a button press we draw a WHITE circle, and then translate between the 2D point on the screen to the 1D point in the bitmap array. The 1D bitmap array is a flattened version of of 2D pixel array. We divide by 8 to translate from bytes to bits. Now, how do we make it print?
if ( digitalRead(btnPin) == HIGH && cur_x < 20 && cur_y < 20){ printer.printBitmap(pic_width*8,pic_height,bitmap); delay(100); tft.fillScreen(BLACK); delay(100); bitmap_white(); }
If the button is pressed when the cursor is in the top left corner (i.e. cur_x < 20 && cur_y < 20) then we call printer.printBitmap(pic_width*8,pic_height,bitmap); And out comes our drawing!
/* LucidTronix joystick drawings * printed on a thermal printer * For instructions, details and schematic, See: * http://www.lucidtronix.com/tutorials/28 * Printer needs strong power source > 1.5A, * 5V-9V */#include#include #include #include int printer_RX_Pin = 6; // This is the green wireint printer_TX_Pin = 7; // This is the yellow wireThermal printer(printer_RX_Pin, printer_TX_Pin);#define cs 10 // for MEGAs you probably want this to be pin 53#define dc 9#define rst 8 // you can also connect this to the Arduino reset// Color definitions#defineBLACK 0x0000#defineBLUE 0x001F#defineRED 0xF800#defineGREEN 0x07E0#define CYAN 0x07FF#define MAGENTA 0xF81F#define YELLOW 0xFFE0 #define WHITE 0xFFFFST7735 tft = ST7735(cs, dc, rst);const int bitmap_size = 1600;const int pic_width = 16;const int pic_height = 100;uint8_t bitmap[bitmap_size];int btnPin = 1;void setup(){ tft.initR(); // initialize a ST7735R chip tft.writecommand(ST7735_DISPON); tft.fillScreen(BLACK); delay(500); int bx = 0; int by = 0; for(int i = 0 ; i < bitmap_size; i++){ if( (bx > 4 && bx < 8 && by > 30 && by < 60) ||(bx > 10 && bx < 15 && by > 70 && by < 90) ) bitmap[i] = 0xFF ; else bitmap[i] = 0x00 ; bx++; if ( bx == pic_width){ bx = 0; by++; } } printer.justify('C'); //sets text justification (right, left, center) accepts 'L', 'C', 'R' bitmap_white(); pinMode(btnPin, OUTPUT);}int cur_x = 64;int cur_y = 80;void loop(){ int y_in = (1024-analogRead(1)); int x_in = (analogRead(0)); if ( x_in > 700 && cur_x < 125 ) cur_x++; else if ( x_in < 130 && cur_x > 5 ) cur_x--; if ( y_in > 700 && cur_y < 157 ) cur_y++; else if ( y_in < 300 && cur_y > 5 ) cur_y--; int cur_r = 10; int cur_g = 20; int cur_b = 10; int color = cur_r | (cur_g << 5) | (cur_b << 11); if ( digitalRead(btnPin) == HIGH ){ tft.fillCircle(cur_x, cur_y, 2,WHITE); int x_index = cur_x / 8; int y_index = constrain(cur_y,0, pic_height-8); for (int j = 0; j < 8; j++){ int i = x_index + ((y_index+j)*pic_width); bitmap[i] = 0xFF ; } } else tft.drawCircle(cur_x, cur_y, 2,color); delay(10); if ( digitalRead(btnPin) == HIGH && cur_x < 20 && cur_y < 20){ printer.printBitmap(pic_width*8,pic_height,bitmap); delay(100); tft.fillScreen(BLACK); delay(100); bitmap_white(); } if ( digitalRead(btnPin) == HIGH && cur_x < 20 && cur_y > 130){ delay(100); tft.fillScreen(BLACK); delay(100); bitmap_white(); } testdrawtext(0,0,"Print", WHITE); testdrawtext(0,150,"Clear", WHITE);}void bitmap_white(){ for(int i = 0 ; i < bitmap_size; i++){ bitmap[i] = 0x00 ; }}void testdrawtext(int ax, int ay, char *text, uint16_t color) { tft.drawString(ax, ay, text, color);}
boolean a_bit = 1; if (bb+gg+pp > 384) a_bit = 0; set_bit_from_index(j, a_bit);bb, gg, and pp are the red green and blue values from the bitmap each stored in a byte. We sum them together and check if the total is less than 384 which is the expected value of a uniformly distributed random variable on the interval of 256 + 256 + 256 = 768. We fill the scanline with a 1 or 0 depending on the brightness (or average of the color channels). We the print the scanline and start over. Each scanline is a row pixels.Similar idea for the cellular automata except now the values are derived by applying the cellular automata rule not from reading an SD card. The relevant code is shown below:
for (int i = 1; i < (scanline_size*8)-1; i++) { int left = get_bit_from_index(i-1); // Left neighbor state int me = get_bit_from_index(i); // Current state int right = get_bit_from_index(i+1); // Right neighbor state boolean abit = get_bit_from_rules(left,me,right); // Compute next generation state based on ruleset set_bit_from_index(i, abit); if ( i < 160) { if (abit ) tft.drawPixel(cur_y, i, CYAN); else tft.drawPixel(cur_y, i, MAGENTA); } } cur_y++; if (cur_y > 128) cur_y = 0; printer.printScanline( scanline_size*8, nextline); for (int i = 0; i < scanline_size; i++) { scanline[i] = nextline[i]; }
Post a comment if you have a question!
/* LucidTronix bitmap and cellular automata * printed on a thermal printer * For instructions, details and schematic, See: * http://www.lucidtronix.com/tutorials/28 * Printer needs strong power source > 1.5A, * 5V-9V */#include#include #include #include #include int printer_RX_Pin = 6;int printer_TX_Pin = 7;Thermal printer(printer_RX_Pin, printer_TX_Pin);#define cs 10 // for MEGAs you probably want this to be pin 53#define dc 9#define rst 8 // you can also connect this to the Arduino reset#define sclk 13#define mosi 11// Color definitions#defineBLACK 0x0000 #define WHITE 0xFFFF#define SD_CS 4 // Set the chip select line to whatever you use (4 doesnt conflict with the library)// the file itselfFile bmpFile1;// information we extract about the bitmap fileint bmpWidth, bmpHeight;uint8_t bmpDepth, bmpImageoffset;ST7735 tft = ST7735(cs, dc, rst);const int scanline_size = 30;uint8_t scanline[scanline_size];uint8_t nextline[scanline_size];boolean rules[] = { 0,1,0,1,1,0,1,0}; int btnPin = 1;int cur_y = 0;void setup(){ pinMode(cs, OUTPUT); digitalWrite(cs, HIGH); tft.initR(); // initialize a ST7735R chip tft.writecommand(ST7735_DISPON); tft.fillScreen(BLACK); tft.drawString(12,22, "Try SD" ,BLUE); if (!SD.begin(SD_CS)) { tft.drawString(12,42, "SD Failed" ,RED); return; } tft.drawString(12,42, "SD GOOD" ,BLUE); delay(1000); tft.fillScreen(BLACK); int bx = 0; int by = 0; //printer.testScanline(); delay(2000); pinMode(btnPin, OUTPUT); for (int i = 0; i < scanline_size; i++) { scanline[i] = 0; if ( i == scanline_size/2) scanline[i] = 0x08; } bmp_load_and_draw_image("face66.bmp"); printer.println(" "); }void loop(){ for (int i = 1; i < (scanline_size*8)-1; i++) { int left = get_bit_from_index(i-1); // Left neighbor state int me = get_bit_from_index(i); // Current state int right = get_bit_from_index(i+1); // Right neighbor state boolean abit = get_bit_from_rules(left,me,right); // Compute next generation state based on ruleset set_bit_from_index(i, abit); if ( i < 160) { if (abit ) tft.drawPixel(cur_y, i, CYAN); else tft.drawPixel(cur_y, i, MAGENTA); } } cur_y++; if (cur_y > 128) cur_y = 0; printer.printScanline( scanline_size*8, nextline); for (int i = 0; i < scanline_size; i++) { scanline[i] = nextline[i]; } }void testdrawtext(int ax, int ay, char *text, uint16_t color) { tft.drawString(ax, ay, text, color);}boolean get_bit_from_index(int index){ int byte_index = index / 8; int bit_index = 7 - (index % 8); byte cur_b = scanline[byte_index]; if ( (cur_b & (1 << bit_index)) != 0x00 ) return 1; else return 0;}void set_bit_from_index(int index, boolean abit){ int byte_index = index / 8; int bit_index = 7-(index % 8); byte cur_b = nextline[byte_index]; if ( abit) cur_b |= (1 << bit_index); else cur_b &= ~(1 << bit_index) ; nextline[byte_index] = cur_b;}int get_bit_from_rules(int a, int b, int c) { if (a == 1 && b == 1 && c == 1) return rules[0]; if (a == 1 && b == 1 && c == 0) return rules[1]; if (a == 1 && b == 0 && c == 1) return rules[2]; if (a == 1 && b == 0 && c == 0) return rules[3]; if (a == 0 && b == 1 && c == 1) return rules[4]; if (a == 0 && b == 1 && c == 0) return rules[5]; if (a == 0 && b == 0 && c == 1) return rules[6]; if (a == 0 && b == 0 && c == 0) return rules[7]; return 0; } void bmp_load_and_draw_image(char* filename) { bmpFile1 = SD.open(filename); if (! bmpFile1) { tft.drawString(12,62, "Coodn't find image" ,RED); while (1); } if (! bmpReadHeader(bmpFile1,0)) { tft.drawString(12,82, "BAD image" ,RED); return; } tft.drawString(12,102, "TRY 2 draw image" ,GREEN); delay(1500); bmpdraw(bmpFile1, 0, 0);}/*********************************************/// This procedure reads a bitmap and draws it to the screen// its sped up by reading many pixels worth of data at a time// instead of just one pixel at a time. increading the buffer takes// more RAM but makes the drawing a little faster. 20 pixels' worth// is probably a good place#define BUFFPIXEL 20void bmpdraw(File f, int x, int y) { bmpFile1.seek(bmpImageoffset); uint32_t time = millis(); uint16_t p; uint8_t g, b; int i, j; uint8_t sdbuffer[3 * BUFFPIXEL]; // 3 * pixels to buffer uint8_t buffidx = 3*BUFFPIXEL; //Serial.print("rotation = "); Serial.println(tft.getRotation(), DEC); //set up the 'display window' tft.setAddrWindow(x, y, x+bmpWidth-1, y+bmpHeight-1); uint8_t rotback = tft.getRotation(); //tft.setRotation(); for (i=0; i< bmpHeight; i++) { // bitmaps are stored with the BOTTOM line first so we have to move 'up' for (j=0; j = 3*BUFFPIXEL) { bmpFile1.read(sdbuffer, 3*BUFFPIXEL); buffidx = 0; } b = sdbuffer[buffidx++]; // blue g = sdbuffer[buffidx++]; // green p = sdbuffer[buffidx++]; // red boolean a_bit = 1; int bb = b; int gg = g; int pp = p; if (bb+gg+pp > 384) a_bit = 0; set_bit_from_index(j, a_bit); // convert pixel from 888 to 565 p >>= 3; p <<= 6; g >>= 2; p |= g; p <<= 5; b >>= 3; p |= b; //Serial.print(p, HEX); // write out the 16 bits of color tft.drawPixel(j, i, p); //tft.pushColor(p); } printer.printScanline( scanline_size*8, nextline); }}boolean bmpReadHeader(File f, int mode) { // read header uint32_t tmp; if (read16(f) != 0x4D42) { // magic bytes missing return false; } // read file size tmp = read32(f); //Serial.print("size 0x"); Serial.println(tmp, HEX); // read and ignore creator bytes read32(f); bmpImageoffset = read32(f); //Serial.print("offset "); Serial.println(bmpImageoffset, DEC); // read DIB header tmp = read32(f); //Serial.print("header size "); Serial.println(tmp, DEC); bmpWidth = read32(f); bmpHeight = read32(f); if (read16(f) != 1) return false; bmpDepth = read16(f); if (read32(f) != 0) { // compression not supported! return false; } return true;}/*********************************************/// These read data from the SD card file and convert them to big endian // (the data is stored in little endian format!)// LITTLE ENDIAN!uint16_t read16(File f) { uint16_t d; uint8_t b; b = f.read(); d = f.read(); d <<= 8; d |= b; return d;}// LITTLE ENDIAN!uint32_t read32(File f) { uint32_t d; uint16_t b; b = read16(f); d = read16(f); d <<= 16; d |= b; return d;}
| Title | Description | # | Cost | Link | Picture |
| Thermal Printer | Thermal printer can print text, barcodes, bitmaps (so so) | 1 | $49.95 | Link |
|
| HSB Joy PCB | PCB controls a screen, thermal printer, joystick and SD card | 1 | $11.95 | Link |
|
| TFT LCD Screen | 1.8 inch 160 x 128 pixels LCD screen. ST7735R driver. JDT-1800. | 1 | $9.95 | Link |
|
| Joystick | Thumb joystick with push button. | 1 | $3.95 | Link |
|
| microSD Card Connector | Secure Digital - microSD™ Push In, Push OutValue: microSD | 1 | $3.44 | Link |
|
| ATMEGA328P-AU | Integrated Circuits (ICs) MCU AVR 32K FLASH 32TQFPValue:1.8 V ~ 5.5 V 20MHz | 1 | $3.05 | Link |
|
| Potentiometer | POT ROTARY, Linear 10K OHM 9MM SNAPINValue:10k | 3 | $0.76 | Link |
|
| USB connector | USB Mini type BValue:female | 1 | $0.68 | Link |
|
| Crystal | CRYSTAL 16.00000 MHZ 20PF SMDValue:16MHz | 1 | $0.53 | Link |
|
| Voltage Regulator 3v3 SMD | IC REG LDO 3.3V .15A SOT23 Up to 6V input output 3.3V 150mA (Max)Value:3.3V | 1 | $0.46 | Link |
|
| CD4050 | IC BUFF/CONVERTER HEX 16SOICN 8mA, 48mAValue: 3 V ~ 18 V | 1 | $0.45 | Link |
|
| Capacitor | Ceramic Capacitors CAP CER 0.1UF 50V 20% RADIALValue: 0.1µF | 4 | $0.24 | Link |
|
| Button | Tactile switch SMD SPST 0.05A 12VValue:SPST | 3 | $0.2 | Link |
|
| Resistor | RES 10K OHM 1/4W 5% CF MINIValue:10k | 6 | $0.08 | Link |
|
Comments: