SoftwareSerial and bytes

I have a device (a remote control for a Zoom H4N audio recorder; see for a nice description of the protocol) that uses 2400 baud, 8n1, to communicate with the recorder.

I'm trying to emulate the recorder as a first step in a project. I've got the remote talking to my device (which is an ESP8266 board -- ). To be more honest: I've got my device talking to the remote: I send characters, and the lights on the remote change. When I send a single space (HeX 20), it turns the line 1 light green, and turns off the REC and MIC and line 2 lights.

But since other light combinations (like "turn the mic light red, and everything else off") require sending low-value hex bytes (in this example, I need to send 0x02), I'm having trouble: the software serial "print" and "write" functions seem to be doing something funky, so that when I try to write 0x00 to the remote-control, what it hears is 0x7A, etc.:

Sent Result 0x00 0x7A 0x01 0x72 0x02 0x6C 0x04 0x6F

but when I get up into the range of printable characters, like "a" -> 61, the result is

0x61 0x61

and so on -- things work just fine.

There used to be something that would let you write "mySerial.write(c, BYTE)", but the byte keyword got deprecated and apparently folks were told to use "print"...which for me seems to produce exactly the same results.

In the code that follows, I've written little "translators" to go from things I can type to the things I actually want to send, since you can't type a "ctrl-A" into the serial monitor and get any results, etc.

I'm also getting nothing from the remote device (i.e., no data seems to be arriving, even when I push buttons on the remote); I'd love any thoughts on why that might be.

SoftwareSerial Serial2(D7, D8); // RX, TX

void setup() {
//  Serial1.begin(2  400);
  pinMode(D7, INPUT); 
  pinMode(D8, OUTPUT);

void loop() {
  if (Serial.available()) {      // If anything comes in Serial (USB),
//    Serial1.write(;   // read it and send it out Serial1 (pins 0 & 1)
    char c =;
    byte b[2];
    c = translateDN(c); 
    Serial.print("I sent: ");
    Serial.println(c, HEX);
    Serial2.print((byte) c);

//  if (Serial1.available()) {     // If anything comes in Serial1 (pins 0 & 1)
  if (Serial2.available()) {     // If anything comes in Serial2
    int c =;
    Serial.print("I got: ");
    Serial.print(c, DEC);
    c = translateUP(c);
    Serial.write(c);   // read it and send it out Serial (USB)
    digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
    delay(10);                       // wait for a second
    digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW   

char translateUP(char x) {
  if (x == 0x00) return '0';
  if (x == 0x80) return '^';
  if (x == 0x82) return 'P';
  if (x == 0x81) return 'R';
  if (x == 0x84) return 'S';
  if (x == 0x88) return 'n';
  if (x == 0x90) return 'p';
  if (x == 0x90) return 'p';
  if (x == 0x08) return '+';
  if (x == 0x10) return '-';
  if (x == 0x20) return 'R';
  if (x == 0x01) return 'm';
  if (x == 0x02) return '1';
  if (x == 0x04) return '2';

char translateDN(char x) {
  if (x == 'z') return 0x00;
  if (x == 'r') return 0x01;
  if (x == 'm') return 0x02;
  if (x == 'M') return 0x10;
  if (x == 'o') return 0x04;
  if (x == 'O') return 0x20;
  if (x == 't') return 0x08;
  if (x == 'T') return 0x40;
  return x;

Actually…you can ignore at least some of that question.

I had the wire carrying data from the remote to the nodeMCU plugged into the wrong place. And I had the wire FROM the nodeMCU to the remote plugged into the wrong place.

What I don’t understand is how it can have worked at all…but now that I’ve got them in the right places, I’ve got a whole different set of problems to worry about, but I might be able to debug at least some of those myself.

The problem of not being able to send low-value bytes remains, but the bytes being actually sent seem to differ. In particular, for values 0x00 to 0x10, they’re coming across as 0x30 … 0x3A (i.e., 0x30 is being added to each). After that, the pattern seems to devolve a good deal.

Do you really have a Serial2 connected to the not-really-an-Arduino? If not, why use such a dumb name?

  pinMode(D7, INPUT);
  pinMode(D8, OUTPUT);

You told the SoftwareSerial instance that these were its pins. Why are you now diddling with them?

    Serial2.print((byte) c);

Why are you calling print()? To send binary data, use write(). When you print the value 0, the ASCII character '0' is sent, which has a value of 0x30.