Arduino Strings: array of char vs. string object

Hallo,
Strings in Arduino, hoe gaan jullie daarmee om?
array of char vs. string object?
Ik heb verschillende LCD's nagenoeg probleemloos aan de praat gekregen met een Mega 2560.
Nu wil ik een tekst letter per letter laten opkomen met zo'n 0.1 sec tussen de letters bij power up van de Arduino.

Dit alles zou in sub IniMessage() moeten gebeuren met de for loop.
Echter ik krijg niet het gewenste effect en ik zie niet in waarom :(
Aangezien de tekst (Mess_100a) als array van chars gedefinieerd is, dacht ik met de loop counter "i" elke char één voor één op het scherm te kunnen schrijven. Niet dus :(

De lengte van de array (Mess_100a) bepalen om de tekst gecentreerd op de LCD te zetten lukt dan weer wel :)

Ik heb ook geprobeerd met charAt() van het String object maar daar ook geen succes.

Ook het gewoon schrijven naar de LCD van teksten uit PROGMEM lukt niet :(
Zie laatste deel van de Setup routine.

Wie kan lij een duwtje geven in de juiste richting?
Alvast bedankt!

Never forget the KISS principle: Keep It Stupid Simple!!

Uit de Arduino reference :
"Using PROGMEM is also a two-step procedure. After getting the data into Flash memory, it requires special methods (functions), also defined in the pgmspace.h library, to read the data from program memory back into SRAM, so we can do something useful with it."

Ik heb uw voorbeeld geprobeerd (op een Nano) zonder LCD maar met Serial.print, inclusief het commente stukje om de karakters één per één te laten verschijnen.

De lijn:

code:


const String PROGMEM Mess_200a = String("My Test Projecttt");

geeft problemen en heb ik commented.

code:


uit reference:
const dataType variableName[] PROGMEM = {};   // use this form
const PROGMEM  dataType  variableName[] = {}; // or this form
const dataType PROGMEM variableName[] = {};   // not this one

Met de char arrays gewoon in SRAM doet het in de seriële monitor wat het moet doen.
Met de char arrays in PROGMEM verschijnt er niets of rare tekens.

Probeer dus eerst zonder PROGMEM.

...
Om op uw eerste vraag te antwoorden, ik leer C via arduino :).
Bij Arduino heb je dus Strings en strings (let op hoofd- en kleine letter). Alhoewel Strings (voor de niet C programmeur) gemakkelijker lijken te werken en er veel functies beschikbaar zijn, komen strings meer voor, bvb bij seriële communicatie. In de reference zijn voor strings geen functies gedocumenteerd. Die vind je bvb op http://www.cplusplus.com/reference/cstring/.
Daarmee kun je (bijna) evenveel mee.

Mijn thuis is waar mijn Weller staat

Bedankt voor je reactie Pertinax!
Inderdaad, wanneer ik de strings in RAM plaats, dus zonder de PROGMEM, verschijnt alles zoals verwacht op het LCD!

Even de two-step procedure uit de link die je gaf doornemen… … …
Blijkbaar moet de string eerst terug naar RAM vooraleer op het scherm te schrijven, ok why not… …

Nogmaals dank!

[Bericht gewijzigd door mcs51mc op dinsdag 2 augustus 2016 17:46:13 (24%)

Never forget the KISS principle: Keep It Stupid Simple!!

Als je het doet zoals in het 2e voorbeeld uit de reference reserveer je voor een 2*24 LCD =
maximaal 48 karakters voor de buffer voor schrijven naar LCD.

In feite kom je met 24 karakters toe, want je schrijft toch maar 1 lijn per keer tenzij je de terugloop zou gebruiken.

Mijn thuis is waar mijn Weller staat

Mmmmmm, het werkt nu wel maar het is niet echt gebruiksvriendelijk.
En kan het niet aanpassen omdat het mij nog niet 100% duidelijk is.

Het eerste deel zet de constante teksten in flash, piece of cake.

c code:

const PROGMEM char StrName[] = "MyString";

Vervolgens reserveren van n bytes in RAM, ook duidelijk

c code:

Char MsgBuffer [LCDCharsPerLine + 1]

MAAR; wat doet

c code:

const char* const MsgTable[] PROGMEM = {lijst met alle namen van teksten}

In de code zelf moet je dan in de strcpy_P lijn de index van de string in MsgTable gegeven worden terwijl ik daar graag de naam van de tekst zou willen zien.

Nu moet ik de index van elke string gaan bijhouden ?!!?

Ik zou dus willen de index [1] in

c code:

strcpy_P(MsgBuffer, (char*)pgm_read_word(&(MsgTable[1])));

vervangen door de naam van de string Msg_100c in dit geval

c code:

strcpy_P(MsgBuffer, ......pgm_read_word(Msg_100c));

Hoogst waarschijnlijk moet er iets komen in plaats van de puntjes.
Is dit mogelijk??

Ik heb deze http://arduiniana.org/libraries/flash/ op het eerste zicht leuke library gevonden rond Flash geheugen echter deze werkt niet meer onder versie 1.6.9 van de IDE :(

Never forget the KISS principle: Keep It Stupid Simple!!

c code:


const PROGMEM char* msg001 = "blah die blah";
const PROGMEM char* msg002 = "bloh die bloh";

...

strcpy_P (MsgBuffer, msg001);
strcpy_P (MsgBuffer, msg002);

Soms is het simpeler dan je denkt...

code:


strcpy_P(MsgBuffer, ......pgm_read_word(Msg_100c));

kun je ook zo gebruiken.
Er moet niets op de plaats van de puntjes komen:

code:


strcpy_P(MsgBuffer, Msg_100c);

Edit: Blurp was sneller :)

Iedere schrijfinstructie naar de LCD wordt dan wat omslachtiger:

code:


lcd.setCursor(bytStart+i,LCDLine_1);
strcpy_P(MsgBuffer, Msg_100c);
lcd.print(MsgBuffer);

Het zou mooier zijn dat je de strcpy en lcd.print in één functie kunt verwerken, bvb lcdpprint

code:


...
lcd.setCursor(bytStart+i,LCDLine_1);
lcdpprint(Msg_100c);
...

void lcdpprint(xxx){
 strcpy_P(MsgBuffer,xxx);
  Serial.println(MsgBuffer);
  }

Ik geraak er echter niet uit hoe je de array doorgeeft.
Zie hier iets gelijkaardig.
Er zitten hier vast wel CO-ers die dat wel kunnen.

Mijn thuis is waar mijn Weller staat

Het idee van strings in program memory is dat je niet de ruimte in ram hoeft te hebben voor die strings. Als je ze dan voor het printen toch in ram gaat zetten streef je het doel voorbij. Ok.Misschien kan je dan toe met 1 ipv veel meer strings in RAM.

Ik zou liefst gewoon per karakterteken de boel naar de LCD sturen.
dus iets van

code:


void lcd_print_P (char *ps)
{
  char c;

  while ((c = pgm_read_byte (ps++))) {
     lcd.print (c);
  }
}

(of je een karakterteken op deze manier kan printen weet ik niet zeker. Worst case wordt het char c[2]; c[1]=0; ...c[0]=pgm_read.... )

four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/

Ok, bedankt voor de reacties!
Code doet wat het moet doen, bedankt voor jullie inputs!

Toch het volgende opmerken:
@rew: Inderdaad nu slechts 21 bytes in RAM en héééééél veeeeeeel in flash, want ik heb finaal wel meer dan die 5 strings. In mijn 8051 periode schreef ik trouwens altijd constant strings in Code memory, dus wou ik het hier ook doen.

@blurp

c code:

const PROGMEM char* msg001 = "blah die blah";
const PROGMEM char msg001[] = "blah die blah";

Eerste regel code werkt niet hoor, tweede wel.
Foutmelding is “variable ‘Msg_100a’ must be const in order to be put into read-only section by means of ‘__attribute__((progmem))

@Pertinax: Heb geprobeerd om inderdaad alles in één sub te zetten, maar struikel ook over hoe die string door te geven naar de sub. Heb een aantal voorbeelden gezien op het net maar altijd vanuit RAM nooit vanuit flash. Wanneer je die terug eerst moet kopiëren alvorens te kunnen doorgeven, dan schiet die sub zijn doel voorbij… …
Dus voorlopig zo gelaten.

Never forget the KISS principle: Keep It Stupid Simple!!

Zoek eens naar de Pstring library.

Je kunt daarmee rechtstreeks printen in een char array.

Dus dan krijg je zoiets:

LCDstring.print("Blahdieblah");

en om RAM te besparen combineer je dat met de Flashhelper:

LCDstring.print(F("Blahdieblah"));

Hallo BVZ, Ik zie niet goed in hoe die Pstring lib mijn probleem kan oplossen, zelfs door gebruik te maken van de "F" macro.
Al die Pstring stuff is om strings te verwerken in een buffer, right?

Ik wil eigenlijk niets doen met strings, niet combineren, niet vergelijken, niet ... ... noem maar op.

Ik wil op een eenvoudige manier constante strings uit flash naar een LCD krijgen.

Definieren teksten in flash

c code:

// Strings used in project stored in program memory and RAM buffer
const PROGMEM char Msg_100a[]= "My test project";
const PROGMEM char Msg_100c[]= "BLS!";
const PROGMEM char Msg_101a[]= "1234";
const PROGMEM char Msg_101b[]= "String 2";
const PROGMEM char Msg_101c[]= "String 3";

char MsgBuffer[LCDCharsPerLine + 1];

Routine om één van de teksten naar de LCD te schrijven.
Het laatste argument (char Message) geeft aan welke tekst op het LCD moet.
Het is mij niet duidelijk of op dit niveau dit een pointer moet zijn naar de tekst in flash of gewoon de naam van die tekst.
Ik ga ervan uit dat de sub de vertaling van de naam naar een pointer dan doet.

c code:

void lcd_Print_P (byte Line, byte Col, char Message)
// Sub to write a message from Flash to LCD
{
  lcd.setCursor(Col,Line);
  strcpy_P(MsgBuffer,Message);
  lcd.print(MsgBuffer);
}

Oproepen van de routine

c code:

// Write message Msg_100c at given location on LCD
lcd_Print_P (LCDCharsPerLine - 4, LCDLine_1, Msg_100c);

Foutmelding op deze lijn is: invalid conversion from 'const char*' to 'char' [-fpermissive]

No more, no less :)

Never forget the KISS principle: Keep It Stupid Simple!!

Op 3 augustus 2016 12:47:18 schreef mcs51mc:
No more, no less :)

Als dat alles is, waarom dan niet gewoon:

c code:


void LCD_print(byte Line, byte Col, byte msg) {
  lcd.setCursor(Col,Line);  
  switch (msg) {
    case 1: lcd.print(F("My test project")); break;
    case 2: lcd.print(F("BLS!")); break;
    case 3: lcd.print(F("1234")); break;
    case 4: lcd.print(F("String 2")); break;
    default: break;
  }
}

Op 3 augustus 2016 12:47:18 schreef mcs51mc:

c code:

void lcd_Print_P (byte Line, byte Col, char Message) ...

lcd_Print_P (LCDCharsPerLine - 4, LCDLine_1, Msg_100c);

Foutmelding op deze lijn is: invalid conversion from 'const char*' to 'char'

Je lcd_Print_P routine klopt niet, Message moet 'const char*' zijn, niet 'char'
Ik verwacht eigenlijk ook een foutmelding op je 'strcpy_P(.., char)' regel, want strcpy wil normaal een char* hebben.

@BVZ : Omdat dit niet past in het volledig plaatje.
Volgens de actuele menustap moeten x lijnen naar het LCD scherm gestuurd worden.
Soms 1, soms 4 lijnen volgens de actuele stap in het menu.
Dus een "switch" met "msg" is niet ok.
Is waarschijnlijk niet 100% duidelijk, sorry

Maar!!
Met "const char*" werkt alles perfect met de subroutine!
Bedankt blurp!!

Definiëren teksten in flash

c code:

// Strings used in project stored in program memory and RAM buffer
const PROGMEM char Msg_100a[]= "My test project";
const PROGMEM char Msg_100c[]= "BLS!";
const PROGMEM char Msg_101a[]= "1234";
const PROGMEM char Msg_101b[]= "String 2";
const PROGMEM char Msg_101c[]= "String 3";

char MsgBuffer[LCDCharsPerLine + 1];

Routine om één van de teksten naar de LCD te schrijven

c code:

void lcd_Print_P (byte Line, byte Col, const char* Message)
// Sub to write a message from Flash to LCD at given location
{
  lcd.setCursor(Col,Line);
  strcpy_P(MsgBuffer,Message);
  lcd.print(MsgBuffer);
}

Aanroepen van de routine

c code:

  lcd_Print_P (LCDLine_1, LCDCharsPerLine - 4, Msg_100c);
  lcd_Print_P (LCDLine_2, LCDCharsPerLine - 4, Msg_101a);

Meer moest dat niet zijn!
Nogmaals dank voor jullie hulp!
Case closed

Never forget the KISS principle: Keep It Stupid Simple!!