Subscribe via RSS

Sending full bytes over .NET Serial Ports to the Arduino

Ok, I have just spent a good two nights of my life diagnosing why I could send all bytes up to value '127' and no higher. In hindsight, it all makes perfect sense and the documentation is clear, but when you've been taught to think in strings, you might hit this very quickly.

The Scenario

I have my MAX7219 + LedControl Library set up on my Arduino and all works fine. I use two functions to control it: setLed and setRow. setLed simply takes a boolean to determine if the LED you are pointing at is to be on or off, but setRow requires a byte. This is all fairly straight-forward as each 'row' in the LED matrix has 8 LEDs, and a byte has 8 bits. So, starting from the lowest significant bit, a value of b00000001 will turn on the first LED in a specified row. (i.e. setRow(DEVICE,ROW,BITS);).

All communications between my application and the Arduino had been based on strings and so I had previously been using one character (one byte) to set one LED. Due to this being a complete waste of bandwidth, I decided that each byte I sent through the channel should be a byte to control full row of LEDs. This meant that I could therefore no longer 'see' the output as a string (or ASCII), as the characters I would create from setting the bits may no longer be in ASCII range... this was no big deal, as I could just view the byte values and decode it all myself.

So, on the client end (C#.NET Application) I started encoding the bytes from bit values. This all worked until I tried to set the last bit...

byte b = 1 | (1 << 7); //let's set the first and last LED.
string buffer = (char)b + "\0";
serialPort.WriteLine(buffer);
Data Sent LEDs lit Correct?
b00000001 1st OK
b01010101 1st, 3rd, 5th, 7th OK
b10101010 1st, 2nd, 3rd, 4th, 5th, 6th WRONG
b10000001 1st, 2nd, 3rd, 4th, 5th, 6th WRONG
b01000000 7th OK
b10000000 1st, 2nd, 3rd, 4th, 5th, 6th WRONG

What the hell was going on? That 8th bit is fishy!

The Answer

So, after reading numerous blogs and not finding my answer, I went to the Arduino Forums and posted a topic asking for help. I was given advice to write a very simple test app to work out where the bytes were failing... but I never did get to write that app, instead I went to the MSDN site as soon as I saw that the Write() procedure could be overloaded.

And look what I found at the article on MSDN:

By default, SerialPort uses ASCIIEncoding to encode the characters. ASCIIEncoding encodes all characters greater than 127 as (char)63 or '?'. To support additional characters in that range, set Encoding to UTF8Encoding, UTF32Encoding, or UnicodeEncoding.

And guess what... ASCII Character ? is 63 in decimal and therefore b00111111 in binary!
So, whenever I was setting the 8th bit, the .NET Framework (in all its wisdom) would translate this to a question mark as it was not expecting to send an invalid ASCII character. Ladies and Gentlemen, ASCII is only 7 bits!

The work-around?

byte[] b = new byte[] { 1, 127, 128, 129, 255 }; //let's set the first bit, last bit, etc...
serialPort.Write(b, 0, b.Length);

And then everything just worked. Do not send chars to your port if your receiver wants bytes.

avatar

About stevenh

Trains… trains… trains… + Electronics + Japan.

Comments (2) Trackbacks (0)
  1. Why in the Lord’s holy name would a function like that attempt to re-encode the byte you are sending? That strikes me as…over-thinking what the function is supposed to do?

    I would have been banging my head against the wall for weeks, even had I seen what you did, as I long ago forgot that ASCII is technically only 7 bits, and that there were once upon a time parts of the world that didn’t use some kind of extended-ASCII character set.

    Good work!

    So, where is this going? Very intrigued. Also, have you considered using Wiring instead of .NET, for portability’s sake?

    • ‘Wiring’ you say? I thought that was part of the Arduino internals and not a portable library… will do some research.

      Meanwhile, this is just an Application to control the layout. It receives sensor output from the layout and then acts appropriately. Currently it can set the throttle, pause and change LEDs. Next will be point control, sounds (although not too soon) and whatever else I can think of.


Leave a comment


*

No trackbacks yet.