Ditto to the previous example about the included libraries. This code reads a bitmap image off an SD card and displays it on an LCD Screen while simultaneously printing it on the thermal printer. It involves a primitive thresholding shown in code here:
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 <SoftwareSerial.h>
#include <Thermal.h>
#include <ST7735.h>
#include <SPI.h>
#include <SD.h>
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
#define BLACK 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 itself
File bmpFile1;
// information we extract about the bitmap file
int 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 20
void 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<bmpWidth; j++) {
// read more pixels
if (buffidx >= 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;
}
Comments: