Ich habe ein Display mit einem "komischen" Zeichensatz. Alphanumerische Zeichen (0..9, a..Z) sind ok, aber bei öäü gibt es Vertauschungen mit anderen Sonderzeichen. Ich habe bei den Zeichenketten, die ich ins Flash lege, bisher immer statt z.B. const __flash char TEST = "Töfftöff"; sowas geschrieben: const __flash char TEST = "T%fft%ff"; So funktioniert das natürlich, ist aber eher unschön. Ich suche nach einer automatischen Lösung. Eine Alternative ist natürlich, die Zeichen zur Laufzeit in der Displayroutine einzeln ersetzen zu lassen, was aber unnötig Rechenzeit und Flash kostet. Sowas müsste doch eigentlich auch zur Compilezeit bzw. im Präprozessor gehen? Hat jemand Tipps?
Ist es denn irgendein Standard-Zeichensatz? Dann könntest du den im gcc als execution character set einstellen.
Standard ist da leider gar nichts. Da liegen u.a. auch japanische Zeichen zwischen den Umlauten usw.
Otto Normalverbraucher schrieb: Und sowas? >#define oe "\x8a" > const __flash char Toeff_Toeff[] = "T"oe"fft"oe"ff";
Wenn Du weißt, welchen Zeichencode Du ausgeben willst, wieso schreibst Du ihn nicht einfach hin?
1 | const char *leberkaes = "Leberk\x84s"; |
2 | const char *knoedel = "Kn\x94del"; |
Ich möchte die Texte einfach auf natürliche Art und Weise schreiben. Ohne Sonderzeichen dazwischen, ohne \x-Verrenkungen. Wenn ich "Sülze" ausgeben will, möchte ich "Sülze" schreiben.
..besser wartbar wirds mit ein paar lesbaren Defines, z.B. sowas in der Art:
1 | #define sAUML "\x84" |
2 | #define sOUML "\x94" |
3 | |
4 | const char* const pLeberkaes = "Leberk" sAUML "se"; |
5 | const char* const pKnoedel = "Kn" sOUML "del"; |
> Wenn ich "Sülze" ausgeben will, möchte ich "Sülze" schreiben.
Textersetzung pre-compile-Event oder zur Laufzeit machen. Hat aber alles
Vor- und Nachteile, such Dir aus, welche Du haben willst.
Otto Normalverbraucher schrieb: > Ohne Sonderzeichen dazwischen, ohne \x-Verrenkungen. Wenn ich "Sülze" > ausgeben will, möchte ich "Sülze" schreiben. Ich möcht' auch viel. Manchmal muß man halt mit dem zufrieden sein, was man kriegt ;). Du kannst natürlich auch dein komisches Display wegschmeissen und dir eins kaufen, das mit Sonderzeichen besser umgehen kann. Wenn's dir das wert ist.
Otto Normalverbraucher schrieb: > as aber unnötig Rechenzeit > und Flash kostet. Ist der Display-Code so laufzeitrelevant, dass das so schlimm wäre? Ich kenne deine Anwendung nicht, aber für ein paar Statusmeldungen auf einem Display kann man sich für jedes Zeichen durchaus ein switch-case mit 8 Möglichkeiten (ÄÖÜäöüß, default) leisten. Das ist immer noch um einige Größenordnungen schneller, als man lesen kann.
Und wie wär's mit Fallunterscheidungen in der Ausgaberoutine?
1 | extern void real_write_c (char); |
2 | |
3 | static char map_uml (char c) |
4 | {
|
5 | switch (c) |
6 | {
|
7 | default: break; |
8 | case 'ä': c = '\x12'; break; |
9 | case 'ö': c = '\x8f'; break; |
10 | ...
|
11 | }
|
12 | return c; |
13 | }
|
14 | |
15 | void write_c (char c) |
16 | {
|
17 | real_write_c (map_ump (c)); |
18 | }
|
im Sourcecode-Text ganz normal schreiben damit man es auch vernünftig lesen kann. In der LcdWriteChar() die Umlaute, Sonderzeichen etc. bei der Ausgabe durch die entsprechenden Werte des LCD-Zeichensatzes ersetzen.
schade war zu spät :-) Johann L. hat es auf den Punkt gebracht.
In C++11 gehts auch ganz ohne Präprozessor:
1 | #include <cstddef> |
2 | #include <array> |
3 | #include <cstdio> |
4 | |
5 | template <typename T, T... I> |
6 | struct IntegerSequence { |
7 | using value_type = T; |
8 | static constexpr size_t size () { return sizeof... (I); } |
9 | };
|
10 | |
11 | namespace Helper { |
12 | template <typename T, typename S1, typename S2> |
13 | struct ConcatSequence; |
14 | |
15 | template <typename T, T... S1, T... S2> |
16 | struct ConcatSequence<T, IntegerSequence<T, S1...>, IntegerSequence<T, S2...>> { |
17 | using type = IntegerSequence<T, S1..., (sizeof...(S1) + S2)...>; |
18 | };
|
19 | |
20 | template <typename T, T N, bool isZero, bool isOne> |
21 | struct GenSeqI; |
22 | }
|
23 | template <typename T, T N> |
24 | using GenSeq = typename Helper::GenSeqI<T, N, N == 0, N == 1>::type; |
25 | |
26 | namespace Helper { |
27 | template <typename T, T N> |
28 | struct GenSeqI<T, N, false, false> { |
29 | using type = typename ConcatSequence<T, GenSeq<T, N/2>, GenSeq<T, N-N/2>>::type; |
30 | };
|
31 | template <typename T, T N> |
32 | struct GenSeqI<T, N, true, false> { |
33 | using type = IntegerSequence<T>; |
34 | };
|
35 | template <typename T, T N> |
36 | struct GenSeqI<T, N, false, true> { |
37 | using type = IntegerSequence<T, 0>; |
38 | };
|
39 | }
|
40 | |
41 | inline constexpr char replace (char value) { |
42 | return
|
43 | value == 'ö' ? 'o' : |
44 | value == 'ä' ? 'a' : |
45 | value == 'ü' ? 'u' : |
46 | value; |
47 | }
|
48 | |
49 | template <size_t N, size_t... I> |
50 | inline constexpr const std::array<char, N> replace (const char (&str) [N], IntegerSequence<size_t, I...>*) { |
51 | return {{ replace (str [I])... }}; |
52 | }
|
53 | |
54 | template <size_t N> |
55 | inline constexpr const std::array<char, N> replace (const char (&str) [N]) { |
56 | return replace<N> (str, static_cast<GenSeq<size_t, N>*> (nullptr)); |
57 | }
|
58 | |
59 | /// ----------
|
60 | |
61 | constexpr auto myString1 = replace ("Hällö Leüte"); |
62 | |
63 | int main () { |
64 | puts (myString1.data ()); |
65 | }
|
Hier werden testweise Umlaute durch die normalen Vokale ersetzt, das kannst du dann deinen Bedürfnissen anpassen. Die Ersetzung erfolgt zur Compile-Zeit und im Programm landet der fertig verarbeitete String. Zum Kompilieren sollte dieser Code als ISO-8859-15 gespeichert werden, denn bei UTF-8 nehmen Umlaute mehrere Bytes ein und 'ä' funktioniert nicht mehr. Wichtig ist dass pro String-Literal eine globale/statische Variable (hier myString1) angelegt wird, auf der man dann später .data() aufrufen kann um den "const char*" zu erhalten. Einfach nur replace ("...").data() funktioniert nicht.
Niklas G. schrieb: > In C++11 gehts auch ganz ohne Präprozessor: Boah, wer will solchen Monstercode lesen, pflegen oder verstehen? Und mit avr-gcc übersetzbar ist er auch nicht...
Vielleicht fällt ja noch jemandem was ein, wenn der TO mal die Bezeichnung des Dipslays postet - oder sogar so nett ist und das Datenblatt verlinkt.
Johann L. schrieb: > Boah, wer will solchen Monstercode lesen, pflegen oder verstehen? Nicht so schlimm wenn man C++ kann. > Und mit avr-gcc übersetzbar ist er auch nicht... Stimmt, weil dem AVR-GCC ein paar C++ Header Files fehlen. Im Anhang eine Version die std::array nachbildet und auch mit dem AVR-GCC funktioniert, und für die Grundlagen die C-Header verwendet. Habe außerdem noch ein Makro hinzugefügt das Lambdas missbraucht um die Verwendung zu vereinfachen (doch keine globale Variable nötig):
1 | puts (LCD_REPLACE_STR("Hällö Leüte")); |
Ansonsten hätte ich einfach mal einen Perl-Script geschrieben, der die Zeichen ersetzt. Die Strings einfach in eine separate Header-Datei schreiben und mit dem Script die relevanten Zeichen ersetzen. (sed, awk und Konsorten gingen natürlich auch).
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.