Degree symbol gets corrupted when sketch is saved

I'm using IDE version 1.8.5. I'm coding "ALT + 0176" as a "degrees" sign, and I'm writing data (including that symbol) to an SD card. I've noticed that when writing to the SD card, sometimes the result is ° (as expected). But other times, it comes out as two characters, namely ° which isn't desirable.

After some experimentation, I've found the following:

  1. If I change all the "ALT + 0176" characters in the sketch to (the same) "ALT + 0176", then compile and upload BEFORE saving the sketch, I get ° characters.
  2. If I change all the "ALT + 0176" characters in the sketch to (the same) "ALT + 0176", then compile and upload AFTER saving the sketch, I get ° characters.

I know how to get the results I want, but why is it that saving a sketch alters the subsequent compile and upload's output? What's happening?

(NOTE: I experience the same problem and solution in other projects, each of which uses an 8x32 LED matrix. The erroneous output is slightly different, but the saving/not saving of the sketch works exactly the same. Saving the sketch before compiling and uploading causes unwanted results.)

Read " How to get the best out of this forum "
and post your code.

Here is the code in question:

  SDdataString = "  COLL = ";
  if (collector_temp < 100) {
    SDdataString = SDdataString + ' ';
  }
  SDdataString = SDdataString + String(collector_temp) + "°.  " + "TANK = ";  // Used Alt + Numpad 0176 for degrees sign.
  if (tank_temp < 100) {
    SDdataString = SDdataString + ' ';
  }
  SDdataString = SDdataString + String(tank_temp) +"°.  " + "DIFF = ";
  if ((collector_temp - tank_temp) < 100) {
    SDdataString = SDdataString + ' ';
  }
  SDdataString = SDdataString + String(collector_temp - tank_temp) + "°.";
  
  dataFileCounter = 0;
  dataFile = SD.open("outLoHi.txt", FILE_WRITE);
  wdt_reset();
  if (dataFile) {
    dataFile.println(SDdataString);
    dataFile.close();
  }

Please post complete code.
What arduino are using?

2 Likes

Complete code is unnecessary. My problem is limited to this: Why does saving the sketch change the output of the "ALT + 0176" character. The sketch is huge, and would just cause confusion.
Take the code I've supplied and try it yourself, first NOT saved, then saved. The results written to an SD card are different. I want to know why.
I'm using a Rev 3 MEGA.
Thanks

It is on this forum. The error is very often in the part not posted. The recommended alternative is to post the complete, minimal program that demonstrates the problem.

But what makes you think that "ALT + 0176" is a character supported by Arduino?

Strong hint: avoid using Strings on an MCU. Especially on an AVR-based Arduino, Strings cause memory problems and program crashes.

2 Likes

The editor is saving the file in UTF-8, which all things considered, isn't a bad idea, but the problem here. The difference is easy to show with Mac or Linux; if you're on Windows, maybe you can fire up WSL (and there should be some PowerShell equivalent). At the top of your .ino, add a comment as the first line

// 37°C

Save it if there is no autosave, then dump the bytes for this first line

$ head -n 1 degree.ino | hexdump -C
00000000  2f 2f 20 33 37 c2 b0 43  0a                       |// 37..C.|

176 in hex is b0. Between 37 and C is not one byte, but two: c2 and b0. On Windows c2 is A-circumflex: Â. Compare the encoding of the degree symbol in UTF-8, a multi-byte encoding of Unicode, where the code point is the same U+00B0; and Windows-1252, a single-byte character set:

$ echo "37°C" | iconv -t utf-8 | hexdump -C
00000000  33 37 c2 b0 43 0a                                 |37..C.|
00000006
$ echo "37°C" | iconv -t windows-1252 | hexdump -C
00000000  33 37 b0 43 0a                                    |37.C.|
00000005

It's interesting that compile-without-save preserves the local character set -- although maybe it still saves somewhere, because otherwise how does the compiler get the file? (ETA: oh, it must be that when performing the "magic" to convert the .ino to .ino.cpp, it will use the in-editor bytes, and not what is saved on disk; because maybe you never even saved.)

Anyway, one possible workaround is never use the symbol literally in the code. Instead

const String DEGREE((char) 176);

void setup() {
  Serial.begin(115200);
}

void loop() {
  String test = 37 + DEGREE + "C";
  const char *t = test.c_str();
  Serial.printf("%d %s %02x %02x %02x %02x %02x\n",
      test.length(), t, t[0], t[1], t[2], t[3], t[4]);
  delay(1500);
}

which should yield in the Serial Monitor

4 37�C 33 37 b0 43 00

Note the "unprintable" character, because the encoding is invalid for the Monitor. But if wherever it is eventually displayed supports/expects Windows-1252 (or ISO-8859-1 aka "Latin1"), then it should work.

I wasn't thinking from readers' points of view. Of COURSE complete code is needed for testing. I was hoping someone would simply have encountered this before, and knew the answer (like kenb4, immediately above).

THANK YOU kenb4! That explanation is EXACTLY what I was looking for. I wanted to know what was happening in the background during a "save" command. And yes, I'm using Win 10.

Here is a very small test sketch that can be compiled:

/*
 * Copy and paste the following code into a new sketch.
 * Test # 1:  BEFORE saving the new sketch, compile and upload this to a MEGA.  The SD Card's tossme.txt file will contain °°
 * Test # 2:  Save the new sketch.  Then, compile and upload the saved sketch to a MEGA.  Tossme.txt will contain °°
 * Why does saving the sketch change the output?
 */

#include <SPI.h>
#include <SD.h>
File dataFile;
String SDdataString = "";

void setup() {
  SD.begin(4);
  SDdataString = "°°";   // Each of the 2 characters between the quotes is ALT + Numpad 0176.

  dataFile = SD.open("tossme.txt", FILE_WRITE);
  if (dataFile) {
    dataFile.println(SDdataString);
    dataFile.close();
  }
}

void loop() {
  // Nothing to do here.
}

I'm sorry I didn't do this right the first time.

Replace this with

SDdataString = SDdataString + String(collector_temp) + "\xB0.  " + "TANK = "

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.