Sadly I don't really have the time to play with this anymore, as I have some other ongoing projects right now.
Feel free to modify the library as you see fit.
Rob has already covered the scroll question, I'll try answering the inversion question.
Thee PCD8544 supports an invert command where you can invert the whole screen without changing anything in memory.
Although you could probably run a 'NOT' loop on the content of the memory section you want to invert.
The library doesn't support it, but it shouldn't be too difficult to implement.
Hi,
Thanks for the library.
Maybe i am lucky/pushing my luck. But i am running my LCD without level shifter or resistors.
I connected all pins to arduino pro mini directly. (Measured 5V at LCD Vcc and Gnd).
This LCD is salvaged from old nokia phone.
Had to use ( lcd.begin(false, 0xB2, 0x05 , 0x14); ) otherwise LCD becomes completely black.
I tried 4-5 of these salvaged LCD's. Looks like there are differences between each of them.
@robtillaart
i would see two behaviours with the scroll functions. In one case i log rows of text to the screen, at the screenend the text should scroll up/down and the old messages could fall simply off the edge. incomming pixels could be blank. in the secound behaviour i want to draw a menu with more rows than visible. in this case i would need a secound buffer for the menuitems that are not in the screen to scroll them in. On the top of the screen theres a header bitmap which should not be scrolled.
Maybe some can post a function for moving rows in the m_Buffer?
@theCoolest
inversion is now done and could be added to the library...
I want to share some functions i added to the library.
Invert the hole screen, invert single pixels, invert a given area, draw a bargraph in horizontal and vertical orientation...
Copy Functionprototypes to public: PCD8544_SPI_FB(); section in PCD8544.H
void invert(bool invert);
void invertPixel(uint8_t x, uint8_t y);
void invertArea(uint8_t x, uint8_t y, uint8_t width, uint8_t height);
void writeHBar(uint8_t x, uint8_t y, uint8_t width, uint8_t height, uint8_t val);
void writeVBar(uint8_t x, uint8_t y, uint8_t width, uint8_t height, uint8_t val);
Copy Functiondefinitions to PCD8544_SPI_FB.CPP
void PCD8544_SPI_FB::invertPixel(uint8_t x, uint8_t y)
{
if (x >= PCD8544_X_PIXELS || y >= PCD8544_Y_PIXELS) return;
uint8_t bank = y / 8;
uint8_t bitMask = 1 << (y % 8);
uint8_t &byte = this->m_Buffer[(PCD8544_X_PIXELS * bank) + x];
byte ^= bitMask;
}
void PCD8544_SPI_FB::invertArea(uint8_t x, uint8_t y, uint8_t width, uint8_t height)
{
uint8_t myx, myy;
for (myx = x; myx < (x+width); myx++) {
for (myy = y; myy < (y+height); myy++) {
this->invertPixel(myx,myy);
}
}
}
void PCD8544_SPI_FB::invert(bool invert){
uint8_t invertSetting = invert ? 0x0D : 0x0C;
this->writeLcd(PCD8544_COMMAND, 0x20); //We must send 0x20 before modifying the display control mode
this->writeLcd(PCD8544_COMMAND, invertSetting); //Set display control, normal mode. 0x0D for inverse
}
void PCD8544_SPI_FB::writeHBar(uint8_t x, uint8_t y, uint8_t width, uint8_t height, uint8_t val)
{
if (height < 3) {
return;
}
this->writeRect(x, y, width, height, false);
this->writeRect(x + 1, y + 1, map(val, 0, 255, 0, width), height - 2, true);
}
void PCD8544_SPI_FB::writeVBar(uint8_t x, uint8_t y, uint8_t width, uint8_t height, uint8_t val)
{
if (width < 3) {
return;
}
this->writeRect(x, y, width, height, false);
this->writeRect(x + 1, y + 1 + map(255 - val, 0, 255, 0, height - 2), width - 2, height - 2 - map(255 - val, 0, 255, 0, height - 2) , true);
}
Thanks for the invert code!
tip: don't check every single pixel if OK that adds up!
Do the check on a higher level.
void PCD8544_SPI_FB::invertPixel(uint8_t x, uint8_t y)
{
uint8_t bank = y / 8;
uint8_t bitMask = 1 << (y % 8);
uint8_t &byte = this->m_Buffer[(PCD8544_X_PIXELS * bank) + x];
byte ^= bitMask;
}
void PCD8544_SPI_FB::invertArea(uint8_t x, uint8_t y, uint8_t width, uint8_t height)
{
uint8_t myx, myy;
for (myx = x; myx < (x+width); myx++)
{
if (myx >= PCD8544_X_PIXELS ) break;
for (myy = y; myy < (y+height); myy++)
{
if (myy >= PCD8544_Y_PIXELS) break;
this->invertPixel(myx,myy);
}
}
}
it would be a serious speed up when it would be possible to invert 8 pixels in a row
void PCD8544_SPI_FB::invertEightPixels(uint8_t x, uint8_t y)
{
uint8_t bank = y / 8;
uint8_t &byte = this->m_Buffer[(PCD8544_X_PIXELS * bank) + x];
byte ^= 255;
}
you would need to make invertArea "aware" of the byte boundaries in the inner loop.
I grabbed this code a few months ago and made quite a few changes. Mainly, I have created a LCD font builder that works really well and takes a few seconds to create a font or bitmap and place in the program. Fonts are in progmem and you can change fonts on the fly with no real speed penalty.
Also added ability to have portrait or landscape orientation.
Basically portrait is the default and behaves as currently implemented. If landscape then X & Y dimensions are swapped and when it's rendered bytes are sent a different way to "flip" the screen 90 degrees.
Also implemented a bitmap blit function that will clip x & y.
Only just got the screens from China today (lol 3 @ $2 each! brand new) so will get more functionality completed. Prior to that, for testing was dumping a matrix of characters to the serial monitor >_>
I hope to release the LCD maker and modified code soon.
Hi,
Thanks a lot for the library.
However, I failed to understand how the PRINT function works - it is not declared in the library. I am wondering if it is possible to print large text - say 16x10 pixels?
Thanks!
This library uses the built-in-Arduino Print class. Thus it doesn't require a separate print function.
Print makes a 'write' call for each character, and you'll notice that 'write' is still there. 'write' is where the actual output to the display occurs for each character received by 'print'.
It should be possible, and not too hard to do. Read the post before yours, it has some interesting info.
Hi,
I have crudely added a function to print individual LARGE (16x11px) numbers 0-9. It was enough for my purposes. Maybe someone will find this useful.
And just in case, I spent some time trying to find a good font and the way to create bitmap array of suitable format. The free program "TheDotFactory-0.1.4" was very simple and useful for this - you may easily create your bitmaps and fonts there.
The library with large digits printout is below.
https://drive.google.com/file/d/0BxM_X2k-WUvvRHp2TmV4OFZoUEU/edit?usp=sharing
uint8_t writeLargeNumber(uint8_t number, uint8_t x, uint8_t y); It prints only one digit a time.
Hi.
Nice lib, and great work.
I'm trying to get it work to display some info from serial to display it on nokia LCD, the demo version is OK, but got error when try to compile it after adding serial reading.
{
size_t len;
lcd.clear();
unsigned long time = micros();
if (Serial.available()) {
// wait a bit for the entire message to arrive
while (Serial.available() > 0) {
// display each character to the LCD
char data = Serial.read();
len = lcd.print(F(data));
}
}
I got error:
rs3310.ino: In function 'void loop()':
rs3310:42: error: initializer fails to determine size of '__c'
The " len = lcd.print(F(data)); " cause this error.
Any clue to get this working ?
Thanks.
len = lcd.print(data);
The F macro is only for data in Flash (readonly code) memory
Hi
Thanks robtillaart.
I got it.
Now got another issue sending data over serial I only got on LCD last char.
I used my code from my project with a 16x2 lcd and I2C
if (Serial.available()) {
delay(200);
// wait a bit for the entire message to arrive
while (Serial.available() > 0) {
// display each character to the LCD
char inChar = (char)Serial.read();
lcd.print(inChar);
lcd.renderAll();
}
if I send from terminal: echo "testing" > /dev/tts/1, I only "g" on the nokia display.
What could be wrong ?
Again, thanks a lot.
I'm not sure why you can only see 'g' on the screen, but you should really use renderAll() outside of the while loop.
Hi
Thanks TheCoolest.
I tried some place for render; got it working.
void loop()
{
if (Serial.available()) {
delay(200);
// wait a bit for the entire message to arrive
while (Serial.available() > 0) {
// display each character to the LCD
char inChar = (char)Serial.read();
lcd.print(inChar);
}
lcd.renderAll();
}
}
Working as I need. Now is only cosmetic stuff to do; define end of line to receive next message, spacing for better reading, etc.
So again, thanks a lot bro.
PS: some update: as nice is your lib is fast.. i got real-time on it ( secs are in sync with NTP server. for human reading)
I will use it to show some info, on a asus wl500gp with dd-wrt. Date, time, connection, etc.
Hi,
thanks for nice library and great work.
however I tried to display 5 bitmaps in sequence but it didnt work..
with trial and error method I found out that I ran out of RAM
as Im only able to display 3 bitmaps to make it work properly.
so maybe stupid question for more advanced users,
but is it possible to store bitmaps in progmem with this libary?
sample code would be much appreciated
I did search google but w/out succes
at least you can
- store bitmaps in PROGMEM and copy them first to RAM and then display (only need one bitmap in RAM)
- store bitmaps in PROGMEM and copy them line by line (only need one line in RAM)
scenario 2 is probably a bit slower but uses less RAM.
you could consider using runlength compressed images to save RAM (depends on the image)
Thanks for advice,
I'm trying option 1
but need help with data types:
uint8_t is used to store bitmaps but it's not supported by pgmspace.h library,
so Im not even able to store the bitmap in flash.
Is there any workaround?
uint8_t is the same 'physical' size as char, so you can use that to store the data in progmem.
Im gettin error:
invalid conversion from 'uint8_t' to 'const uint8_t*' ...
Please post the code where you get this error.
the code is probably not correct
prog_uchar bmpsport[] PROGMEM = {
0xFE, 0xFF, 0xFF, 0x03, 0x01.....
...bitmap seems to be stored in flash...OK
but this code is getting error:
lcd.writeBitmap(pgm_read_byte(bmpsport), 0, 0, 59, 6);
thank you