I have the following two functions that I use to print strings to an I2C LCD:
void lcd_write_char(char character)
{
Wire.beginTransmission(LCD_I2C_ADDRESS);
Wire.write( character );
Wire.endTransmission();
delayMicroseconds( 200 );
}
void lcd_print_string(char* string)
{
uint8_t i=0;
while( string[i] != '\0' )
{
lcd_write_char( string[i] );
i++;
}
}
They work just fine when I print like this:
lcd_print_string( "Hello World!" );
However, when I use the F() macro like this:
lcd_print_string( F("Hello World!") );
I get the following error in my sketch:
Arduino: 1.5.7 (Windows 7), Board: "Arduino Uno"
Using library SPI in folder: C:\Users\Jiggy\Desktop\PortableApps\PortableApps\arduino-1.5.7\hardware\arduino\avr\libraries\SPI (legacy)
Using library Wire in folder: C:\Users\Jiggy\Desktop\PortableApps\PortableApps\arduino-1.5.7\hardware\arduino\avr\libraries\Wire (legacy)
Using library BasicEncoder in folder: C:\Users\Jiggy\Documents\1) Flash Drive Documents\Arduino\libraries\BasicEncoder (legacy)
C:\Users\Jiggy\Desktop\PortableApps\PortableApps\arduino-1.5.7/hardware/tools/avr/bin/avr-g++ -c -g -Os -w -fno-exceptions -ffunction-sections -fdata-sections -MMD -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=157 -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR -IC:\Users\Jiggy\Desktop\PortableApps\PortableApps\arduino-1.5.7\hardware\arduino\avr\cores\arduino -IC:\Users\Jiggy\Desktop\PortableApps\PortableApps\arduino-1.5.7\hardware\arduino\avr\variants\standard -IC:\Users\Jiggy\Desktop\PortableApps\PortableApps\arduino-1.5.7\hardware\arduino\avr\libraries\SPI -IC:\Users\Jiggy\Desktop\PortableApps\PortableApps\arduino-1.5.7\hardware\arduino\avr\libraries\Wire -IC:\Users\Jiggy\Documents\1) Flash Drive Documents\Arduino\libraries\BasicEncoder C:\Users\Jiggy\AppData\Local\Temp\build8412383002145879208.tmp\DDS.cpp -o C:\Users\Jiggy\AppData\Local\Temp\build8412383002145879208.tmp\DDS.cpp.o
C:\Users\Jiggy\Desktop\PortableApps\PortableApps\arduino-1.5.7/hardware/tools/avr/bin/avr-g++ -c -g -Os -w -fno-exceptions -ffunction-sections -fdata-sections -MMD -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=157 -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR -IC:\Users\Jiggy\Desktop\PortableApps\PortableApps\arduino-1.5.7\hardware\arduino\avr\cores\arduino -IC:\Users\Jiggy\Desktop\PortableApps\PortableApps\arduino-1.5.7\hardware\arduino\avr\variants\standard -IC:\Users\Jiggy\Desktop\PortableApps\PortableApps\arduino-1.5.7\hardware\arduino\avr\libraries\SPI -IC:\Users\Jiggy\Desktop\PortableApps\PortableApps\arduino-1.5.7\hardware\arduino\avr\libraries\Wire -IC:\Users\Jiggy\Documents\1) Flash Drive Documents\Arduino\libraries\BasicEncoder C:\Users\Jiggy\AppData\Local\Temp\build8412383002145879208.tmp\Frequency_Generator.cpp -o C:\Users\Jiggy\AppData\Local\Temp\build8412383002145879208.tmp\Frequency_Generator.cpp.o
Frequency_Generator.ino: In function 'void print_digital_amplitude(amplitude_t)':
Frequency_Generator.ino:681:32: error: cannot convert 'const __FlashStringHelper*' to 'char*' for argument '1' to 'void lcd_print_string(char*)'
How can I modify or overload my lcd_print_string function to work with the F() macro?
Derive your LCD printing class from Print and then it should work OK.
Example here:
class I2C_graphical_LCD_display : public Print
{
Example:
#include <Wire.h>
class my_LCD_class : public Print
{
public:
size_t write(uint8_t c);
// other stuff here
};
const int LCD_I2C_ADDRESS = 42;
size_t my_LCD_class::write (uint8_t character)
{
Wire.beginTransmission(LCD_I2C_ADDRESS);
Wire.write( character );
Wire.endTransmission();
delayMicroseconds( 200 );
}
my_LCD_class foo;
void setup ()
{
foo.print (F ("Hello, world"));
}
void loop () { }
This also gives you access to all the printing functions (eg. print a string, print a number, print a float, etc.)
Is there a way I can directly use the __FlashStringHelper* type by overloading my function rather than rewriting my display driver code?
If not, I'll commence rewriting.
Finally got around to rewriting my LCD code to be like Nick suggested, and it works perfectly. Fantastic use of virtual functions, very elegant.
Found that too, which is what I originally went with:
void lcd_print_string(const __FlashStringHelper* ifsh)
{
PGM_P p = reinterpret_cast<PGM_P>(ifsh);
while(1)
{
char c = pgm_read_byte(p++);
if( c=='\0' ) break;
lcd_write_char( c );
}
}*/
Basically just copy & pasted from the Print::print function. Nick's way is quite elegant though, and will give me much more flexibility.
Thank you everyone.
Thank you. Now I re-read the thread it seems I left a return out of the function. I'm surprised one of the C++ experts didn't pick me up on that.
size_t my_LCD_class::write (uint8_t character)
{
Wire.beginTransmission(LCD_I2C_ADDRESS);
Wire.write( character );
Wire.endTransmission();
delayMicroseconds( 200 );
return 1; // we output one byte
}
Or to be more pedantic, if the transmission fails, we should (probably) return zero:
size_t my_LCD_class::write (uint8_t character)
{
Wire.beginTransmission(LCD_I2C_ADDRESS);
Wire.write( character );
uint8_t result = Wire.endTransmission();
delayMicroseconds( 200 );
if (result == 0)
return 1; // we output one byte
else
return 0; // we failed to output anything
}
I'm surprised the compiler didn't pick up on it. Shouldn't it give warnings for stuff like that? I have verbose output turned on.
Your "more pedantinc" function works just fine, so I'll run with that.
Thank you again.
In verbose mode with IDE 1.0.5 I get:
sketch_aug27a.ino: In member function ‘virtual size_t my_LCD_class::write(uint8_t)’:
sketch_aug27a.ino:21: warning: no return statement in function returning non-void
That was the warning.
I'm using 1.5.7 and got no warning that I could see.
The Arduino developers seem strangely reluctant to let us see compiler warnings. There may be an option for it somewhere in preferences.
system
September 17, 2014, 1:12pm
13
Took a liberty to modify your post.
I may be dreaming, but it would be nice to be able to select errors only, warnings only and than compiler progress messages.
But if the developers goal is to support "blinking LED" code only, there is really no need for knowing all of this.
And it generates traffic to this site....
Cheers Vaclav
Seeing warnings helps you know you are doing something (probably) wrong, for example using a variable which is not initialized. Without seeing the warning, people then post here that something has gone wrong, and they need help. With the warning they might work it out for themselves.