My overall goal is to have an Arduino Uno with an Ethernet Shield send a short (5-character) string via a SoftwareSerial connection and a UDP packet when I press a button.
The device which is receiving the serial message is fixed at 9600 baud, no parity, one stop bit.
For the purposes of debugging my serial problem I have removed the Ethernet Shield. I mention it above only so that potential responders understand my intended final hardware configuration.
I am using a USB/serial adaptor and Kermit to check the serial output.
C-Kermit>show communications
Communications Parameters:
Line: /dev/ttyUSB0, speed: 9600, mode: local, modem: none
Parity: none, stop-bits: 1 (8N1)
Duplex: full, flow: none, handshake: none
Carrier-watch: off, close-on-disconnect: off
Lockfile: /var/lock/LCK..ttyUSB0
Terminal bytesize: 8, escape character: 28 (^\)
My first job on receiving garbled characters was to test my test rig. I connected the predecessor device and was able to receive the expected characters. (It cannot send the UDP packet, which is why it is being replaced.)
One button on the original device sends "X0401", exactly as expected:
$ od -b oldserial⋅
0000000 000 130 060 064 060 061
0000006
Another button on the original device sends "X0402" (which I expected) and also a whole bunch of nuls, which I didn't expect:
$ od -b oldserial⋅
0000000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
0000020 000 000 000 000 000 130 060 064 060 062
0000032
In any event, it seems that the terminal is actually receiving 8N1 data at 9600, so I can trust what it shows me.
I was going kind of nuts trying to figure out what was the problem, because nothing I sent from the Arduino came through properly. Then I stumbled on a suggestion that 'U' made a good test character because an ASCII 'U' is 0123 or 01010101. Indeed, I am able to send sequences of arbitrary length and so long as they contain only the 'U' caracter, they come through correctly.
(I've got three buttons and three different sets of messages, so my tests tend to run in sets of three attempts.)
Next step is to reintroduce a little bit of variety and see what comes through:
Here I send "UUUUU", "UUEUU", and then "UUQUU". 'E' and 'Q' were chosen because they are each just one bit different from 'U'.
What I saw when I sent the first message was:
UUUUU
Then sent the second:
UUUUUUU]UU
Then the third:
UUUUUUU]UUUUWUU
Kermit was also storing the session to a log file, which looked like this:
$ od -b serialUsequesnce⋅
0000000 125 125 125 125 125
0000005
$ od -b serialUsequesnce⋅
0000000 125 125 125 125 125 125 125 135 125 125
0000012
$ od -b serialUsequesnce⋅
0000000 125 125 125 125 125 125 125 135 125 125 125 125 127 125 125
0000017
Somehow, 'E' (0105) turned into 0135 and 'Q' (0121) turned into 0127. In each case, a sequence of three 0 bits were turned into 011, while no 1 bits were changed.
Sending:
UUAUU
Got me:
$ od -b serialUsequesnce2⋅
0000000 000 125 125 137 125 125
0000006
The five consecutive 0 bits in 01000001 were turned into 01111 to give me 01011111 or 0137
Longer strings get weirder.⋅
Test strings of:
UU0123456789UU
UUABCDEFGUU
Got me:
$ od -b serialUsequesnce3
0000000 125 125 326 266 226 166 126 066 026 366 215 125 125 000
0000016
$ od -b serialUsequesnce4
0000000 125 125 137 257 335 325 315 305 125 125 001
0000013
Now I'm seeing not just bits being replaced, but I'm getting fewer characters than I'm sending.
Since I wasn't getting good data from my SoftwareSerial port, I thought I would listen in on the USB traffic, which is also set to 9600 baud.
This text from the Arduino monitor:
UUAUU
Start button pressed
UU0123456789UU
Stop button pressed
UUABCDEFGUU
Light button pressed
Came through as this:
$ od -b serialUSB
0000000 125 125 137 125 125 171 275 165 324 332 027 277 073 025 027 027
0000020 041 043 277 037 031 031 065 067 345 353 000
0000033
$ od -b serialUSB2
0000000 125 125 326 266 226 166 126 066 026 366 215 125 125 345 353 131
0000020 027 041 037 277 073 025 027 027 041 043 277 037 031 031 065 067
0000040 345 353 000
0000043
$ od -b serialUSB3
0000000 125 125 137 257 335 325 315 305 125 125 225 353 147 055 061 057
0000020 027 277 073 025 027 027 041 043 277 037 031 031 065 067 345 353
0000040 000
0000041
I'm guessing that I'm doing something wrong with the hardware, but my serial connector simply has pin 5 connected to ground and pin 2 connected to digital 6 (or 2 when watching USB traffic).
I'm powering the Arduino Uno via its USB connection. When I checked the voltage at Vin and the adjacent ground, I got 4.51 volts.
/*
Listens on three buttons:
- Start
- Stop
- Lights
Sends serial messages to a Color Kinetics iPlayer 2
9600 baud, 8 data bits, no parity, 1 stop bit
Commands are
- X0100 Lights Off
- X0288 Lights at half
- X02FF Lights at full
- X0401 Set Show #1
Created 2016-07-13
by David H. Silber
(Cribbing extensively from the Arduino examples.)
*/
#include <SPI.h> // needed for Arduino versions later than 0018
#include <SoftwareSerial.h>
SoftwareSerial softSerial( 5, 6 ); // RX, TX
const int noButton = 100;
const int startButton = 2;
const int stopButton = 3;
const int lightButton = 4;
bool startTriggered = false;
bool stopTriggered = false;
bool lightTriggered = false;
int lastTriggered = noButton;
unsigned long lastButtonTime = 0;
const char startSerial[] = "UUUUU";
const char stopSerial[] = "UUEUU";
const char lightSerial[] = "UUQUU";
void setup() {
// initialize the pushbutton pin as an input:
pinMode(startButton, INPUT);
pinMode(stopButton, INPUT);
pinMode(lightButton, INPUT);
Serial.begin(9600); // set up Serial library at 9600 bps
Serial.println("Starting"); // prints hello with ending line break⋅
// set the data rate for the SoftwareSerial port
softSerial.begin(9600);
delay( 1000 );
}
void loop() {
// read the state of the pushbutton value:
startTriggered = ( HIGH == digitalRead(startButton) );
stopTriggered = ( HIGH == digitalRead(stopButton) );
lightTriggered = ( HIGH == digitalRead(lightButton) );
if ( startTriggered && (startButton != lastTriggered) ) {
action( "Start button pressed", startSerial );
lastTriggered = startButton;
startTriggered = false;
}
if ( stopTriggered && (stopButton != lastTriggered) ) {
action( "Stop button pressed", stopSerial );
lastTriggered = stopButton;
stopTriggered = false;
}
if ( lightTriggered && (lightButton != lastTriggered) ) {
action( "Light button pressed", lightSerial );
lastTriggered = lightButton;
lightTriggered = false;
}
buttonTimeout();
}
void action( const char usbMessage[], const char serialMessage[] ) {
Serial.println( serialMessage);⋅
Serial.println( usbMessage);⋅
softSerial.write( serialMessage );
lastButtonTime = millis();
}
void buttonTimeout() {
if ( millis() - lastButtonTime > 2000 ) {
lastTriggered = noButton;
}
}