Long time lurker, first post...
I’m trying to run servos, a 16x4 LCD, and hardware serial on a Sanguino board. When there’s no incoming serial, I get an occasional and barely perceptible twitch on the one servo connected. When the Sanguino is receiving serial data, the servo jitters continuously. The same code runs on a Mega2560 without the jitter.
The jitter can be measured with an o-scope when the servo and LCD are removed, so it’s not the hardware, power supply, or grounds. A 1500uS pulse will jump by 50 to 90 uS. Just to make sure it’s not the transmitter end, I even substituted a Duemilanove running a short piece of code.
Since I’ve eliminated all the external hardware, I have to suspect incompatibility between the Sanguino core files and Arduino libraries. Is anyone willing to confirm this, suggest a fix, or find an error in my program?
Sanguino receiver:
/* receiver serial in
Serial data is 21 byte frame.
Frame prefix is 0xaa, 0xaa.
Frame suffix is 0xed, 0xed.
Eight 'little-endian' words, followed by one byte.
High nibble of high byte indicates channel number.
Value of Low three nibbles is 2 * pulsewidth in microseconds.
LCD pin Arduino pin
1 = GND GND
2 = VCC VCC
3 = n/c (LCD contrast)
4 = RS D7
5 = R/W D6
6 = ENB D5
7 = D1 n/c
8 = D2 n/c
9 = D3 n/c
10 = D7 n/c
11 = D4 D4
12 = D5 D3
13 = D6 D2
14 = D7 D1
*/
#include <LiquidCrystal.h> //The liquid crystal display library
//LiquidCrystal(rs, rw, enable, d4, d5, d6, d7);
LiquidCrystal lcd(7, 6, 5, 4, 3, 2, 1); //Assign pin functions
//Servo library and servo initialization
#include <Servo.h>
Servo ch1Out;
Servo ch2Out;
Servo ch3Out;
Servo ch4Out;
Servo ch5Out;
Servo ch6Out;
Servo ch7Out;
Servo ch8Out;
//Initialize 21 byte frame buffer
byte rcv[] = {0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00,
0x00};
byte printFormat = 1; //0 prints raw data. 1 prints decoded data
byte lcdDiag = 1; //0 bypasses LCD printing, 1 prints to LCD
byte clearLCD = 0; //Flag for "Ready" message erased
unsigned long elapsedStart; // microseconds since last LCD update
void setup() {
Serial1.begin(125000); //Yes, 125000 baud!
lcd.begin (16,4); //16 x 4 LCD
//Tell user we're ready
lcd.setCursor (0,0);
lcd.print ("Ready");
//attach the servos
ch1Out.attach(15);
ch2Out.attach(16);
ch3Out.attach(17);
ch4Out.attach(18);
ch5Out.attach(19);
ch6Out.attach(20);
ch7Out.attach(21);
ch8Out.attach(22);
elapsedStart = micros();
}
void loop() {
if (Serial1.available() >0) { //Read byte from uart if available
rcv[20] = Serial1.read();
if ((rcv[0] == 0xaa) && (rcv[1] == 0xaa) && (rcv[19] == 0xed) && (rcv[20] == 0xed)) {
//We have a valid frame, process it.
ch1Out.writeMicroseconds(xlate(3));
ch2Out.writeMicroseconds(xlate(5));
ch3Out.writeMicroseconds(xlate(7));
ch4Out.writeMicroseconds(xlate(9));
ch5Out.writeMicroseconds(xlate(11));
ch6Out.writeMicroseconds(xlate(13));
ch7Out.writeMicroseconds(xlate(15));
ch8Out.writeMicroseconds(xlate(17));
if (lcdDiag == 1) {
lcdPrint();
}
}
else {
/* We don't have a valid frame, so roll buffer contents
one location to prepare for next byte from uart. */
for (byte count = 0; count <=19; count++) {
rcv[count] = rcv[count + 1];
}
}
}
}
unsigned int xlate(byte index) {
/* Strip upper nibble from high byte. combine with low byte to get value.
divide by 2 to get pulsewidth in microseconds. */
unsigned int ch = (((rcv[index] & 0x0f) * 0x100) + rcv[index - 1]) / 2;
return ch;
}
void lcdPrint() {
if (clearLCD == 0) { //only clear screen once, reduce flickering
lcd.clear();
clearLCD = 1;
}
if (printFormat == 0) {
// prints raw hex data as received
printChVal(rcv[0], 0, 0);
printChVal(rcv[1], 3, 0);
printChVal(rcv[2], 6, 0);
printChVal(rcv[3], 9, 0);
printChVal(rcv[4], 12, 0);
printChVal(rcv[5], 0, 1);
printChVal(rcv[6], 3, 1);
printChVal(rcv[7], 6, 1);
printChVal(rcv[8], 9, 1);
printChVal(rcv[9], 12, 1);
printChVal(rcv[10], 0, 2);
printChVal(rcv[11], 3, 2);
printChVal(rcv[12], 6, 2);
printChVal(rcv[13], 9, 2);
printChVal(rcv[14], 12, 2);
printChVal(rcv[15], 0, 3);
printChVal(rcv[16], 3, 3);
printChVal(rcv[17], 6, 3);
printChVal(rcv[18], 9, 3);
printChVal(rcv[19], 12, 3);
printChVal(rcv[20], 14, 3);
}
else {
//prints data converted to microseconds
//calculate elapsed time since last valid frame and print on top row at right
lcd.setCursor (10,0);
lcd.print(micros() - elapsedStart, DEC);
lcd.print(" ");
elapsedStart = micros();
printChVal(xlate(3), 0, 0);
printChVal(xlate(5), 5, 0);
printChVal(xlate(7), 0, 1);
printChVal(xlate(9), 5, 1);
printChVal(xlate(11), 0, 2);
printChVal(xlate(13), 5, 2);
printChVal(xlate(15), 0, 3);
printChVal(xlate(17), 5, 3);
lcd.setCursor(10,3);
lcd.print(rcv[18],DEC);
}
}
void printChVal (unsigned int chanVal, byte col, byte row){
lcd.setCursor(col, row);
if (printFormat == 0) {
lcd.setCursor (col,row);
lcd.print(chanVal, HEX);
}
else {
if (chanVal < 1000) { //print a leading space if less than 4 characters
lcd.print(" ");
}
lcd.print(chanVal, DEC);
}
}
Duemilanove transmitter:
//tx emulator
/* two prefix bytes, eight servo words, one unknown byte, two suffix bytes.
all times are 1500uS */
byte tx[] = {0xaa, 0xaa,
0xb8, 0x1b, 0xb8, 0x2b,
0xb8, 0x3b, 0xb8, 0x4b,
0xb8, 0x5b, 0xb8, 0x6b,
0xb8, 0x7b, 0xb8, 0x8b,
0x00, 0xed, 0xed};
void setup() {
Serial.begin(125000); //to conform with device
}
void loop() {
long unsigned mSec; //timing reference
if (millis() - mSec >= 20) { //transmit a frame approx. every 20mS
for (byte txCount = 0; txCount <=20; txCount++){
Serial.write(tx[txCount]);
}
}
mSec = millis(); //renew the timing reference
}
Thanks,
Jon