printingbitmapzebra-printersthermal-printer

Plot an array into bitmap in C/C++ for thermal printer


I am trying to accomplish something a bit backwards from everyone else. Given an array of sensor data, I wish to print a graph plot of it. My test bench uses a stepper motor to move the input shaft of a sensor, stop, get ADC value of sensor's voltage, repeat.

My current version 0.9 bench does not have a graphical output. The proper end solution will. Currently, I have 35 data points, and I'm looking to get 90 to 100. The results are simply stored in an int array. The index is linear, so it's not a complicated plot, but I'm having problems conceptualizing the plot from bottom-left to top-right to display to the operator. I figure on the TFT screen, I can literally translate an origin and then draw lines from point to point...

Worse, I want to also print out this to a thermal printer, so I'll need to translate this into a sub-384 pixel wide graph. I'm not too worried about the semantics of communicating the image to the printer, but how to convert the array to an image.

It gets better: I'm doing this on an Arduino Mega, so the libraries aren't very robust. At least it has a lot of RAM for the code. :/

Here's an example of when I take my data from the Arduino test and feed it into Excel. I'm not looking for color, but I'd like the graph to appear and this setup not be connected to a computer. Or the network. This is the ESC/POS printer, btw.

plot of sensor data


Solution

  • The algorithm for this took three main stages:
    1) Translate the Y from top left to bottom left.
    2) Break up the X into word:bit values.
    3) Use Bresenham's algorithm to draw lines between the points. And then figure out how to make the line thicker.

    For my exact case, the target bitmap is 384x384, so requires 19k of SRAM to store in memory. I had to ditch the "lame" Arduino Mega and upgrade to the ChipKIT uC32 to pull this off, 32k of RAM, 80 MHz cpu, & twice the I/O!

    The way I figured out this was to base my logic on Adafruit's Thermal library for Arduino. In their examples, they include how to convert a 1-bit bitmap into a static array for printing. I used their GFX library to implement the setXY function as well as their GFX Bresenham's algorithm to draw lines between (X,Y)s using my setXY().

    It all boiled down to the code in this function I wrote:

    // *bitmap is global or class member pointer to byte array of size 384/8*384
    // bytesPerRow is 384/8
    void setXY(int x, int y) {
        //  integer divide by 8 (/8) because array size is byte or char
        int xByte = x/8;
        //  modulus 8 (%8) to get the bit to set
        uint8_t shifty = x%8;
        //  right shift because we start from the LEFT
        int xVal = 0x80 >> shifty;
        //  inverts Y from bottom to start of array
        int yRow = yMax - y;
        //  Get the actual byte in the array to manipulate
        int offset = yRow*bytesPerRow + xByte;
        //  Use logical OR in case there is other data in the bitmap,
        //  such as a frame or a grid
        *(bitmap+offset)|=xVal;
    }
    

    The big point is to remember with an array, we are starting at the top left of the bitmap, going right across the row, then down one Y row and repeating. The gotchya's are in translating the X into the word:bit combo. You've got to shift from the left (sort-of like translating the Y backwards). Another gotchya is one-off error in bookkeeping for the Y.

    I put all of this in a class, which helped prevent me from making one big function to do it all and through better design made the implementation easier than I thought it would be.

    Pic of the printout:
    Output from TPS test bench I made
    Write-up of the project is here.