Counting and Timing a shock sensor

Got yet another experiment for you, but like the above, it should be a quickie. What I found was that the BFG has in his globals.h file the following statement :

extern OLEDFourBit lcd;

… which if I understand it correctly, tell the compiler to basically substitute “OLEDFourBit” everywhere it sees “lcd”. So an lcd.setCursor(0,0) is the same as OLEDFourBit.setCursor(0,0) and thus uses his new OLED library. So minor mystery solved … I think. There is no “print()” function in his OLED library so the compiler must be smart enough to know that if it can’t find OLEDFourBit.print() to use the default Arduino library lcd.print(). If that’s the case, and the experiment should prove this, then the prior timer code will need just a couple of tweaks to work with the new OLED display, assuming our prior problems with the old LCD have been resolved (there were 2 IIRC, and 1 I’m sure I fixed). So here’s the (last ?) experimental code …

#include "OLEDFourBit.h"
extern OLEDFourBit lcd;

// initialize the library with the numbers of the interface pins
// with the OLED library this also seems to do the init and begin calls
OLEDFourBit lcd(12, 11, 5, 4, 9, 8);

char buf[21];
unsigned int count = 0;

void setup()
{
  lcd.clear();
  delay(5);
  lcd.setCursor(0, 0);
  delay(5);
  lcd.print("    Incrementing    ");
  delay(5);
  lcd.setCursor(0, 1);
  delay(5);
  lcd.print("     count test     ");
  delay(3000);
}

void loop()
{
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Count = ");
  lcd.print(count);
  count++;
  delay(1000);
}

Now because the declaration is in the test code above, I think I could have used a #define instead of the extern but l don’t think what was done “hurts”.

Actually what

OLEDFourBit lcd;

does is create an object of type OLEDFourBit. Thus when you see LCD.print(…) it is calling that method from the OLEDFourBit code. So while your explanation works, it isn’t technically correct. lcd is just a variable name and you are calling methods on it which is indeed defined in OLEDFourBit.

Dan

dkulinski:
Actually what

OLEDFourBit lcd;

does is create an object of type OLEDFourBit. Thus when you see LCD.print(…) it is calling that method from the OLEDFourBit code. So while your explanation works, it isn’t technically correct. lcd is just a variable name and you are calling methods on it which is indeed defined in OLEDFourBit.

Dan

Thanks ! So what happens when the OLEDFourBit library has no code/method for “print” ? I couldn’t find, in the UberFridge code anywhere, a place where the LCD is initialized so it may well be the code posted on Google is incomplete … but assuming it isn’t, would an lcd.print(XYZ) work w/o a method defined in the OLEDFourBit code ? I guess the above experiment(s) will show us but it would be nice to understand why things work or don’t.

Alright, this is getting into some nuts and bolts of OO (object oriented) programming but I will give it a shot.

If you look at the OLEDFourBit.h file, you see this statement:

class OLEDFourBit : public Print {

This means that OLEDFourBit inherits all the properties of the Print class. Now I took a moment to check out the Print code and here is the important bit from the comments:

Print.h - Base class that provides print() and println()

So when you call the lcd.print() method it is actually invoking the method from the Print class. This ties in to code re-use, writing a generic object which extends the functionality of subclasses.

Let me know if I totally lost you on this one. I don’t think it was a great explanation but hopefully it answers your question.

Dan

Nope, it was a great explanation ! I understand enough OO concepts to qualify at the orangutan level. So in the case of “overlapping” methods, such as setCursor(), the compiler looks first for the code in the OLED library and uses that vs the Arduino library for lcd.setCursor ?

Mee_n_Mac:
Nope, it was a great explanation ! I understand enough OO concepts to qualify at the orangutan level. So in the case of “overlapping” methods, such as setCursor(), the compiler looks first for the code in the OLED library and uses that vs the Arduino library for lcd.setCursor ?

You are exactly correct, you move up the inheritance chain until you find what you need. Now this code, as far as I can tell, never inherits the LCD code so I am not sure if it ever actually calls any of those methods. I’ll take a close look at another time.

Dan

dkulinski:
Now this code, as far as I can tell, never inherits the LCD code so I am not sure if it ever actually calls any of those methods. I’ll take a close look at another time.

Dan

No need to look, I don’t see it (LiquidCrystal.h) mentioned anywhere and so the only methods that will be recognized for “OLEDFourBit” or “lcd” are those specified in the header file. This is all starting to make sense. So if I may bother you some more, how does the preprocessor/compiler/whatever know to use the code in the .cpp file for those methods ? Is simply including the .h file sufficient, the compiler knows to look in other files of the same name (different extension) for anything else it needs ? I don’t think I"ve ever seen a #include “XYX.cpp” before … but then again orangutans don’t get out that much.

And given “lcd” is only used in the main timer code, does the “extern OLEDFourBit lcd” declaration even need to be done ? Would the “OLEDFourBit lcd(12, 11, 5, 4, 9, 8);” be sufficient to let the compiler know there’s going to be this thing called “lcd” and make some space for it ?

Mee_n_Mac:

dkulinski:
Now this code, as far as I can tell, never inherits the LCD code so I am not sure if it ever actually calls any of those methods. I’ll take a close look at another time.

Dan

No need to look, I don’t see it (LiquidCrystal.h) mentioned anywhere and so the only methods that will be recognized for “OLEDFourBit” or “lcd” are those specified in the header file. This is all starting to make sense. So if I may bother you some more, how does the preprocessor/compiler/whatever know to use the code in the .cpp file for those methods ? Is simply including the .h file sufficient, the compiler knows to look in other files of the same name (different extension) for anything else it needs ? I don’t think I"ve ever seen a #include “XYX.cpp” before … but then again orangutans don’t get out that much.

All the library .cpp files along with the arduino code will be supplied to the compiler. I believe you can turn on verbose output so you can see what is going on when you hit compile. Each file .cpp generally gets turned into a .o and then at link time everything is assembled into the ASM output which is then turned into HEX for uploading.

Mee_n_Mac:
And given “lcd” is only used in the main timer code, does the “extern OLEDFourBit lcd” declaration even need to be done ? Would the “OLEDFourBit lcd(12, 11, 5, 4, 9, 8);” be sufficient to let the compiler know there’s going to be this thing called “lcd” and make some space for it ?

I don't know why it is *extern OLEDFourBit* . If OLEDFourBit uses timers, that could be part of it. An extern variable is static (created at run time and only destroyed at exit). You can always try to instantiate it like you have mentioned and see if it works. There is probably a good reason it is extern though.

Dan

I can’t get the sketches to compile.

heres an example from the last one.

Where ever you see buf =, take out the parens.

Dan

Probably doesn’t like the fact that I stuck the “xyzxyz” in paranthesis. Tell you what, go for the gusto and just try the last experiment.

#include "OLEDFourBit.h"
extern OLEDFourBit lcd;

// initialize the library with the numbers of the interface pins
// with the OLED library this also seems to do the init and begin calls
OLEDFourBit lcd(12, 11, 5, 4, 9, 8);

char buf[21];
unsigned int count = 0;

void setup()
{
  lcd.clear();
  delay(5);
  lcd.setCursor(0, 0);
  delay(5);
  lcd.print("    Incrementing    ");
  delay(5);
  lcd.setCursor(0, 1);
  delay(5);
  lcd.print("     count test     ");
  delay(3000);
}

void loop()
{
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Count = ");
  lcd.print(count);
  count++;
  delay(1000);
}

Damn, if I wasn’t stuck with these long hairy arms, I’d type faster.

Now it just says error compiling without even highlighting a line.

In my whole 2 months of experience I’ve never had that happen before.

My guess is that it’s not finding the OLED files. I don’t know how to set up the Arduino environment search path to include where you put those OLED .h and .cpp files.

http://arduino.cc/en/Guide/Environment#libraries

http://arduino.cc/en/Guide/Environment#sketchbook

Libraries
Libraries provide extra functionality for use in sketches, e.g. working with hardware or manipulating data. To use a library in a sketch, select it from the Sketch > Import Library menu. This will insert one or more #include statements at the top of the sketch and compile the library with your sketch. Because libraries are uploaded to the board with your sketch, they increase the amount of space it takes up. If a sketch no longer needs a library, simply delete its #include statements from the top of your code.
There is a list of libraries in the reference. Some libraries are included with the Arduino software. Others can be downloaded from a variety of sources. To install these third-party libraries, create a directory called libraries within your sketchbook directory. Then unzip the library there. For example, to install the DateTime library, its files should be in the /libraries/DateTime sub-folder of your sketchbook folder.
To write your own library, see this tutorial.

From the “readme.txt” file …

*The 3 files in this directory should be in %your arduino dir%\libraries\OLEDFourBit*
The directory name must match the library name for libraries to work.

i was missing the keywords file in the library. I added that and it still says “error compiling”.

the OLEDFourBit does light up orange now though just like all of the other libraries so I would think that is correct.

I note that in the Arduino tutorial on making your own libraries, it says this …

http://arduino.cc/en/Hacking/LibraryTutorial

You need a couple of other things in the header file. One is an #include statement that gives you access to the standard types and constants of the Arduino language (this is automatically added to normal sketches, but not to libraries). It looks like this (and goes above the class definition given previously):
#include “Arduino.h”

That include is not the OLED header file. Somehow it all worked for the BFG but perhaps Arduino 1.0 is different ?? I dunno, stick it in there and see what happens. That you’re not getting a specific error called out makes me think there’s something missing that the compiler can’t find.

Then perhaps comment out the extern OLEDFourBit lcd; line.

Yeah, I’m not sure the line:

extern OLEDFourBit lcd;

is needed.

No luck on the two suggestions.

Perhaps there’s something in the message.

Seems to be some incompatibility w/Arduino 1.0 I’m not sure what to do but have a look at this …

https://github.com/sparkfun/WiFly-Shield/issues/7

Seems like there are 2 problems, one with Arduino.h vs WProgram.h and then the overloads as in the error message.

And from

http://www.arduino.cc/playground/Code/LCD3wires

Note: these libraries aren’t compatible with IDE 1.0 - you will get compiling errors.
To get the original version working on IDE 1.0 you have to copy/paste WConstants.h and wiring.h from IDE 0023 into arduino-1.0\hardware\arduino\cores\arduino
To get the 0.2 version working on IDE 1.0 do the same thing as above and then make the following changes in the LCD3WireLibrary.h and LCD3WireLibrary.cpp files:
In the header file change “virtual void write(uint8_t);” to “virtual size_t write(uint8_t);”
In the C++ file change “void LCD3Wire::write(uint8_t value)” to “inline size_t LCD3Wire::write(uint8_t value)”

And here as well …

http://stackoverflow.com/questions/8749 … 023-to-1-0

So reading the above and taking my best GUESS as to what’s needed, here are the “fixed” files. Save the prior ones away someplace safe and copy these into the library directory. Then change their names back (note the “A” added) to the ones you just moved and give them a try. I was unsure whether the write function in the C++ file should return a 1 as in one of the examples (but not in another fix example) so I put it in but commented it out. Find it and uncomment it if you think it’s needed.

OLEDFourBitA.h

#ifndef OLEDFourBit_h
#define OLEDFourBit_h

#include <inttypes.h>
#include "Print.h"

// commands
#define LCD_CLEARDISPLAY 0x01
#define LCD_RETURNHOME 0x02
#define LCD_ENTRYMODESET 0x04
#define LCD_DISPLAYCONTROL 0x08
#define LCD_CURSORSHIFT 0x10
#define LCD_FUNCTIONSET 0x28
#define LCD_SETCGRAMADDR 0x40
#define LCD_SETDDRAMADDR 0x80

// flags for display entry mode
#define LCD_ENTRYRIGHT 0x00
#define LCD_ENTRYLEFT 0x02
#define LCD_ENTRYSHIFTINCREMENT 0x01
#define LCD_ENTRYSHIFTDECREMENT 0x00

// flags for display on/off control
#define LCD_DISPLAYON 0x04
#define LCD_DISPLAYOFF 0x00
#define LCD_CURSORON 0x02
#define LCD_CURSOROFF 0x00
#define LCD_BLINKON 0x01
#define LCD_BLINKOFF 0x00

// flags for display/cursor shift
#define LCD_DISPLAYMOVE 0x08
#define LCD_CURSORMOVE 0x00
#define LCD_MOVERIGHT 0x04
#define LCD_MOVELEFT 0x00

// flags for function set
#define LCD_8BITMODE 0x10
#define LCD_4BITMODE 0x00
#define LCD_ENGLISH_JAPANESE   0x00
#define LCD_WESTERN_EUROPEAN_1 0x01
#define LCD_ENGLISH_RUSSIAN    0x02
#define LCD_WESTERN_EUROPEAN_2 0x03


class OLEDFourBit : public Print {
public:
  OLEDFourBit(uint8_t rs, uint8_t enable,
		uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7);
  
  void init(uint8_t rs, uint8_t enable,
	    uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7);
    
  void begin(uint8_t cols, uint8_t rows);

  void clear();
  void home();

  void noDisplay();
  void display();
  void noBlink();
  void blink();
  void noCursor();
  void cursor();
  void scrollDisplayLeft();
  void scrollDisplayRight();
  void leftToRight();
  void rightToLeft();
  void autoscroll();
  void noAutoscroll();

  void createChar(uint8_t, uint8_t[]);
  void setCursor(uint8_t, uint8_t); 
  //virtual void write(uint8_t);
  virtual size_t write(uint8_t);

  void command(uint8_t);
  
private:
  void send(uint8_t, uint8_t);
  void write4bits(uint8_t);
  void pulseEnable();
  void waitBusy();

  uint8_t _rs_pin; // LOW: command.  HIGH: character.
  uint8_t _enable_pin; // activated by a HIGH pulse.
  uint8_t _busy_pin;
  uint8_t _data_pins[4];

  uint8_t _displayfunction;
  uint8_t _displaycontrol;
  uint8_t _displaymode;
  uint8_t _initialized;
  uint8_t _currline;
  uint8_t _numlines;
};

#endif

OLEDFourBitA.cpp

#include "OLEDFourBit.h"

#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include "arduino.h"

OLEDFourBit::OLEDFourBit(uint8_t rs, uint8_t enable,
			     uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7)
{
  init(rs, enable, d4, d5, d6, d7);
}

void OLEDFourBit::init(uint8_t rs, uint8_t enable,
			 uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7)
{
  _rs_pin = rs;
  _enable_pin = enable;
  _busy_pin = d7;
  
  _data_pins[0] = d4;
  _data_pins[1] = d5;
  _data_pins[2] = d6;
  _data_pins[3] = d7; 


  pinMode(_rs_pin, OUTPUT);
  pinMode(_enable_pin, OUTPUT);
  
  _displayfunction = LCD_FUNCTIONSET | LCD_4BITMODE;
   
  begin(20, 4);  
}

void OLEDFourBit::begin(uint8_t cols, uint8_t lines) {
  _numlines = lines;
  _currline = 0;
  
  pinMode(_rs_pin, OUTPUT);
  pinMode(_enable_pin, OUTPUT);
  
  digitalWrite(_rs_pin, LOW);
  digitalWrite(_enable_pin, LOW);
  
  // SEE PAGE 20 of NHD-0420DZW-AY5 
  delayMicroseconds(50000); // wait 50 ms just to be sure tha the lcd is initialized
  
  // Now we pull both RS and R/W low to begin commands
  
  for (int i = 0; i < 4; i++) {
    pinMode(_data_pins[i], OUTPUT);
    digitalWrite(_data_pins[i], LOW);
  }

  delayMicroseconds(100000);
  write4bits(0x03);
  delayMicroseconds(100000);
  write4bits(0x02);
  delayMicroseconds(10000);
  write4bits(0x02);
  delayMicroseconds(10000);
  write4bits(0x08);
   
  
  //command(0x28);
  delayMicroseconds(10000);
  
  command(0x08);	// Display off
  delayMicroseconds(10000);
	
  command(0x01);	// display clear
  delayMicroseconds(10000);

  command(0x06);	// Entry Mode Set:
  delayMicroseconds(10000);

	
  command(0x02);	// Home
  delayMicroseconds(10000);

  command(0x0C);	// display on/ cursor on/ cursor blink
  delayMicroseconds(10000);
	
	
}

/********** high level commands, for the user! */
void OLEDFourBit::clear()
{
  command(LCD_CLEARDISPLAY);  // clear display, set cursor position to zero
}

void OLEDFourBit::home()
{
  command(LCD_RETURNHOME);  // set cursor position to zero
}

void OLEDFourBit::setCursor(uint8_t col, uint8_t row)
{
  uint8_t row_offsets[] = { 0x00, 0x40, 0x14, 0x54 };
  if ( row >= _numlines ) {
    row = 0;  //write to first line if out off bounds
  }
  
  command(LCD_SETDDRAMADDR | (col + row_offsets[row]));
}

// Turn the display on/off (quickly)
void OLEDFourBit::noDisplay() {
  _displaycontrol &= ~LCD_DISPLAYON;
  command(LCD_DISPLAYCONTROL | _displaycontrol);
}
void OLEDFourBit::display() {
  _displaycontrol |= LCD_DISPLAYON;
  command(LCD_DISPLAYCONTROL | _displaycontrol);
}

// Turns the underline cursor on/off
void OLEDFourBit::noCursor() {
  _displaycontrol &= ~LCD_CURSORON;
  command(LCD_DISPLAYCONTROL | _displaycontrol);
}
void OLEDFourBit::cursor() {
  _displaycontrol |= LCD_CURSORON;
  command(LCD_DISPLAYCONTROL | _displaycontrol);
}

// Turn on and off the blinking cursor
void OLEDFourBit::noBlink() {
  _displaycontrol &= ~LCD_BLINKON;
  command(LCD_DISPLAYCONTROL | _displaycontrol);
}
void OLEDFourBit::blink() {
  _displaycontrol |= LCD_BLINKON;
  command(LCD_DISPLAYCONTROL | _displaycontrol);
}

// These commands scroll the display without changing the RAM
void OLEDFourBit::scrollDisplayLeft(void) {
  command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT);
}
void OLEDFourBit::scrollDisplayRight(void) {
  command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT);
}

// This is for text that flows Left to Right
void OLEDFourBit::leftToRight(void) {
  _displaymode |= LCD_ENTRYLEFT;
  command(LCD_ENTRYMODESET | _displaymode);
}

// This is for text that flows Right to Left
void OLEDFourBit::rightToLeft(void) {
  _displaymode &= ~LCD_ENTRYLEFT;
  command(LCD_ENTRYMODESET | _displaymode);
}

// This will 'right justify' text from the cursor
void OLEDFourBit::autoscroll(void) {
  _displaymode |= LCD_ENTRYSHIFTINCREMENT;
  command(LCD_ENTRYMODESET | _displaymode);
}

// This will 'left justify' text from the cursor
void OLEDFourBit::noAutoscroll(void) {
  _displaymode &= ~LCD_ENTRYSHIFTINCREMENT;
  command(LCD_ENTRYMODESET | _displaymode);
}

// Allows us to fill the first 8 CGRAM locations
// with custom characters
void OLEDFourBit::createChar(uint8_t location, uint8_t charmap[]) {
  location &= 0x7; // we only have 8 locations 0-7
  command(LCD_SETCGRAMADDR | (location << 3));
  for (int i=0; i<8; i++) {
    write(charmap[i]);
  }
}

/*********** mid level commands, for sending data/cmds */

inline void OLEDFourBit::command(uint8_t value) {
  send(value, LOW);
  waitBusy();
}

//inline void OLEDFourBit::write(uint8_t value) {
inline size_t OLEDFourBit::write(uint8_t value) {
  send(value, HIGH);
  waitBusy();
  //return 1;
}

/************ low level data pushing commands **********/

// write either command or data
void OLEDFourBit::send(uint8_t value, uint8_t mode) {
  digitalWrite(_rs_pin, mode);
  
  write4bits(value>>4);
  write4bits(value);
}

void OLEDFourBit::pulseEnable(void) {
  digitalWrite(_enable_pin, HIGH);
  delayMicroseconds(100);    // enable pulse must be >450ns
  digitalWrite(_enable_pin, LOW);
}

void OLEDFourBit::write4bits(uint8_t value) {
  for (int i = 0; i < 4; i++) {
    pinMode(_data_pins[i], OUTPUT);
    digitalWrite(_data_pins[i], (value >> i) & 0x01);
  }
  delayMicroseconds(100);
  pulseEnable();
}

void OLEDFourBit::waitBusy(void) {
  delayMicroseconds(5000);
}