Uno - Char Randomizing Thermal Printer

Hello All,

I’m working on a project that needs a long list of variables that can be spat out in random configurations on a thermal printer. I have a working prototype using a small thermal printer and an arduino uno rev3. My challenge now is that the flash memory is so small, I max out the number of variables rather quickly.

I could really use suggestions on how best to expand this flash memory. I’ve found write-ups on PROGMEM options, but I don’t fully understand if I can call on them randomly, or how best to approach expanding memory. I’m open to all suggestions, changing boards, adding shields if need be or some more advanced coding (I am rather new to this). I’ll include the code for what I have so far.

#include <EEPROM.h>
#include <Thermal.h>
#include <avr/pgmspace.h> 
#include "Adafruit_Thermal.h"
#include "SoftwareSerial.h"

#define BUTTON 13
#define TX_PIN 6 // Arduino transmit  YELLOW WIRE  labeled RX on printer
#define RX_PIN 5 // Arduino receive   GREEN WIRE   labeled TX on printer
SoftwareSerial mySerial(RX_PIN, TX_PIN); // Declare SoftwareSerial obj first
Adafruit_Thermal printer(&mySerial);     // Pass addr to printer constructor

bool running = false;

template <class T> int EEPROM_writeAnything(int ee, const T& value)
{
   const byte* p = (const byte*)(const void*)&value;
   int i;
   for (i = 0; i < sizeof(value); i++)
       EEPROM.write(ee++, *p++);
   return i;
}


template <class T> int EEPROM_readAnything(int ee, T& value)
{
   byte* p = (byte*)(void*)&value;
   int i;
   for (i = 0; i < sizeof(value); i++)
       *p++ = EEPROM.read(ee++);
   return i;
}


void BetterRandomSeed( void )
{
 unsigned long __seed;
 
 EEPROM_readAnything( 0, __seed );
 
 srandom( __seed );
}


long BetterRandom( void )
{
 long __seed;
 
 __seed = random();
 
 EEPROM_writeAnything( 0, __seed );

 return( __seed );
}


long BetterRandom( long howbig )
{
 if ( howbig == 0 ) 
 {
   return 0;
 }
 return( BetterRandom() % howbig );
}


long BetterRandom( long howsmall, long howbig )
{
 if ( howsmall >= howbig ) 
 {
   return howsmall;
 }
 long diff = howbig - howsmall;
 
 return( BetterRandom(diff) + howsmall );
}


char *ideas[] ={
"Abstraction",
"Aestheticism",
"Aesthetics",
"Affect",
"Anthropocentrism",
"Art Brut",
"Art Deco",
"Art Nouveau",
"Ashton Kutcher",
"Assemblage",
"Atheism",
"Bauhaus",
"Being in The World",
"Bourgeoisie",
"Bruno Letour",
"Cartesian Dualism",
"Classicism",
"Clowns",
"Collage",
"Colonization",
"Constructivism",
"Consumerism",
"Cubism",
"Cynicism",
"DADA",
"Darkness",
"Deconstructivism",
"Derive",
"Dichotomy",
"Dinosaurs",
"Dionysian",
"Discourse",
"DIY",
"Earth",
"Emancipation",
"Empiricism",
"Excessivism",
"Existentialism",
"Feminism",
"Fetishism",
"Flatness",
"Flowers",
"Fluxus",
"Foucault",
"Futurism",
"Geese",
"Gender",
"George Orwell",
"Graffiti",
"Hate",
"Hermeneutics",
"Humanism",
"Hypermodernism",
"Idiocy",
"Jaques Derrida",
"Kafka",
"Kinetic",
"Kitsch",
"Kittens",
"Land Works",
"Linguistic Anthropology",
"Logical Positivism",
"Love",
"Lowbrow",
"Lunacy",
"Materialism",
"Metaphysics",
"Minimalism",
"Misanthropy",
"Modernism",
"Modernism",
"Modular Constructivism",
"Naiveté",
"Nazis",
"Nearness",
"Nihilism",
"Nudes",
"Object Oriented Ontology",
"Objectivism",
"Oil",
"Ontology",
"Ontology",
"Orientalism",
"Paint",
"Pessimism",
"Phenomenology",
"Photorealism",
"Plastic",
"Platonic Realism",
"Post-Impressionism",
"Postmodernism",
"Primitivism",
"Primitivism",
"Proletariat",
"Punk Rock",
"Realism",
"Realism",
"Religion",
"Rhizomes",
"Rocks",
"Rococo",
"Russia",
"Simplicity",
"Socialist Realism",

};

long ideas1;
long ideas2;
long ideas3;

int val = 0;
int run; 


String stringOne = "The Intersection of " ;
String stringTwo = ", ";
String stringThree = " & ";
String stringFour = ".";



void setup()
{
 
 BetterRandomSeed();
 pinMode(BUTTON, INPUT);
 mySerial.begin(19200);  // Initialize SoftwareSerial
 printer.begin();        // Init printer (same regardless of serial type)
 run = 0;
 delay(500);

 
}

void loop()
     
{
 
 
 if(digitalRead(BUTTON) == HIGH) //funcitons based off of button pulling input pin LOW
  {
    ideas1 = BetterRandom(sizeof(ideas)/sizeof(char*));
      do
      {
      ideas2 = BetterRandom(sizeof(ideas)/sizeof(char*));
      ideas3 = BetterRandom(sizeof(ideas)/sizeof(char*));
       }

 while ( ideas2 == ideas1 == ideas2 == ideas3 == ideas1);

 printer.justify('L');
 printer.underlineOn();
 printer.println("Your Future Thesis Will Be:");
 printer.underlineOff();
 printer.feed(2);
 printer.println(stringOne + ideas[ideas1] +stringTwo + ideas[ideas2] + stringThree + ideas[ideas3] + stringFour);
 printer.feed(4);
  }
 }

Thank you so much for any and all suggestions.

char *ideas[] ={
"Abstraction",
"Aestheticism",
"Aesthetics",
"Affect",
"Anthropocentrism",
"Art Brut",
"Art Deco",

Why are these strings wasting precious RAM?

maddjake:
I could really use suggestions on how best to expand this flash memory. I've found write-ups on PROGMEM options, but I don't fully understand if I can call on them randomly,

How would the fact that you decided randomly which one to pick affect whether or not you could access one? Put them all in an array in PROGMEM, pick a random number, read out that string.

( ideas2 == ideas1 == ideas2 == ideas3 == ideas1)

That doesn't do what you think it does.

IF ideas2 == ideas1 then the result of the first comparison is true. SO next it compares true to ideas2 which will obviously be false. Then it compares false to ideas3 which is false again. And finally compares false to ideas1 which is again false. So you might as well have written while(false).

(stringOne + ideas[ideas1] +stringTwo + ideas[ideas2] + stringThree + ideas[ideas3] + stringFour)

Watch out for the concatenation operator on the String class on a microcontroller with limited memory and no garbage collection. This could end in a crash. Generally, the String class is a thing to avoid on a microcontroller. If you used normal c-style strings you could get the same output by just using several print statements and would use less code space, less memory, be faster, and be more stable.

Thank you both,

I was having trouble using PROGMEM, but I think I was expecting it to be simpler (or more linear) instead of needing the multiple steps to put them in PROGMEM, set int, create pointers etc (if I understand the process correctly. This is all still new, and pretty damn fun.)

I see now exactly what you mean with the == statements, I was scat coding until something worked. I really appreciate the clarification on that.

The concatenation operator was used as a cheat to make it print as one statement. If not the printer would print each println on a separate line. That was the easiest solution with my limited knowledge. I’ll keep reading and try something more elegant.

Thank you.

maddjake:
The concatenation operator was used as a cheat to make it print as one statement. If not the printer would print each println on a separate line. That was the easiest solution with my limited knowledge. I'll keep reading and try something more elegant.

Yes, if you use println. Do you know the difference between print and println? That's something worth looking at.

That makes all the sense in the world (print vs println). Yes, I'll rewrite a bunch of this, thank you.

Why are these strings wasting precious RAM?

AWOL: I meant to say: when I tried putting them in PROGMEM the first time I didn't really understand the process of retrieving them, giving them pointers, assigning them integers, and such. I think I have some better idea of it for attempt two.

I think I'm getting slightly closer. Now when I print though it's merely returning an integer, so I'm trying to find a way to get the information back from PROGMEM. (cut the randomizing code out to make it easier to read). Specifically, I'm finding the placement of the buffer and strcpy problematic (a total lack of coding empathy or understanding)

const char id_0[] PROGMEM = "Abstraction";
const char id_1[] PROGMEM ="Aestheticism";
const char id_2[] PROGMEM ="Aesthetics";
const char id_3[] PROGMEM ="Affect";
const char id_4[] PROGMEM ="Anthropocentrism";
const char id_5[] PROGMEM ="Art Brut";

const char* const ideas[] PROGMEM = {id_0,id_1, id_2, id_3, id_4, id_5};

char buffer[100];

long ideas1;
long ideas2;
long ideas3;

int run; 

void setup()
{
 
 BetterRandomSeed();
 pinMode(BUTTON, INPUT);
 mySerial.begin(19200);  // Initialize SoftwareSerial
 printer.begin();        // Init printer (same regardless of serial type)
 run = 0;
 delay(500);

 
}

void loop()
  {
 
 if(digitalRead(BUTTON) == HIGH) //funcitons based off of button pulling input pin LOW
  {
    ideas1 = BetterRandom(sizeof(ideas)/sizeof(char*));
      do
      {
      ideas2 = BetterRandom(sizeof(ideas)/sizeof(char*));
      ideas3 = BetterRandom(sizeof(ideas)/sizeof(char*));
       }

while (ideas1 != ideas2);(ideas2 !=ideas3);
  strcpy_P(buffer, (char*)pgm_read_word(&(ideas[ideas1])));
  strcpy_P(buffer, (char*)pgm_read_word(&(ideas[ideas2])));
  strcpy_P(buffer, (char*)pgm_read_word(&(ideas[ideas3])));

 printer.justify('L');
 printer.underlineOn();
 printer.print(F("Your Future Thesis Will Be:"));
 printer.underlineOff();
 printer.feed(2);
 
  printer.print(F("The Intersection of ")) ;
  printer.print(ideas1, buffer);
  printer.print(F( ", "));
  printer.print(ideas2, buffer);
  printer.print(F( " & "));
  printer.print(ideas3, buffer);
  printer.print(F("."));

 printer.feed(4);
  }
 }
while (ideas1 != ideas2);(ideas2 !=ideas3);

Nope. Try again. Please stop making up syntax. It's never going to work out. Take a little time to learn the basics of the language. That right there is a program freeze.

strcpy_P(buffer, (char*)pgm_read_word(&(ideas[ideas1])));
  strcpy_P(buffer, (char*)pgm_read_word(&(ideas[ideas2])));
  strcpy_P(buffer, (char*)pgm_read_word(&(ideas[ideas3])));

So at the end what's in buffer? Just ideas[ideas3]. What was the point of copying over the other two if you were just going to overwrite them on the next line by writing into the same buffer?

printer.print(ideas1, buffer);

Is there a version of print that takes a char pointer as the second argument? That should throw a compile error. I think you want to print buffer. If you want to print two things, a comma is not how you do that.

I really appreciate your help. I know this must look like pulling teeth. I see exactly what I was doing now, and defined 3 different buffers. That was total idiocy on my part.

Getting the statements to print if the boolean is false still puzzles me, but it seems to work as this

while (ideas1 == ideas2 && ideas2 == ideas3);

This is all super new to me, but having the boneheaded assumptions pointed out has made me re-read a bunch of syntax related posts, and I'm slowly understanding the structure better (small increments -- only relative to my own incompetence).

Thank you for all your help.

Your while is getting closer but is still an empty infinite loop. Should a while have a semicolon? What does the semicolon mean? What does it do? What do we use it for in C?