Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Write byte to Arduino from Ruby over serial

I'm trying to send an integer over the serial port to my Ardunio. The chip is then going to display the number in binary on the LED's. However I'm having lots of trouble trying to send the data as a byte over the serial port, as far as I can debug the following code sends it as the ASC char values.

Can anyone point me in the right direction or spot the mistake? I'd really appreciate it. I've been pulling my hair out over this for a long time.

Ruby

require 'rubygems'  
require 'serialport' # use Kernel::require on windows, works better.  

#params for serial port  
port_str = "/dev/tty.usbserial-A700dZt3"  #may be different for you  
baud_rate = 9600  
data_bits = 8  
stop_bits = 1  
parity = SerialPort::NONE  

sp = SerialPort.new(port_str, baud_rate, data_bits, stop_bits, parity)  

i = 15

#just write forever  
while true do  
  sp.write(i.to_s(2))
  sleep 10
end

Arduino

int ledPin = 10;
int ledPin1 = 11;
int ledPin2 = 12;
int ledPin3 = 13;

byte incomingByte;  // for incoming serial data

void setup() {
  pinMode(ledPin, OUTPUT);  // initialize the LED pin as an output:
  pinMode(ledPin1, OUTPUT); // initialize the LED pin as an output:
  pinMode(ledPin2, OUTPUT); // initialize the LED pin as an output:
  pinMode(ledPin3, OUTPUT); // initialize the LED pin as an output:
  Serial.begin(9600);   
  Serial.println("I am online"); 
}

void loop() {
 // send data only when you receive data:
if (Serial.available() > 0) {
    incomingByte = Serial.read();
            Serial.println(incomingByte, DEC);

   int value = (incomingByte, DEC) % 16;
   digitalWrite(ledPin, (value >> 0) % 2);
   digitalWrite(ledPin1, (value >> 1) % 2);
   digitalWrite(ledPin2, (value >> 2) % 2);
   digitalWrite(ledPin3, (value >> 3) % 2); // MSB

}

}
like image 811
Karl Entwistle Avatar asked Nov 06 '10 16:11

Karl Entwistle


2 Answers

I'm guessing you are trying to write the value 15 in order to light all the LEDs at once. However, 15.to_s(2) is "1111". The ASCII value of the character '1' is 49, so instead of writing 15 once you are writing 49 four times in rapid succession.

The write command you are looking for is therefore probably sp.putc(i). This writes only one character with the given binary value (= machine-readable for Arduino) instead of an ASCII string representation of the value expressed in binary (= human-readable for you).

So keeping everything else the same, replace the while loop in your Ruby code with:

loop do
  sp.putc(i)
  puts 'Wrote: %d = %bb' % [ i, i ]
  i = (i == 15) ? 0 : (i + 1)
  sleep(10)
end

If you wish to read the responses from Arduino, you can use e.g. sp.gets to get one line of text, e.g. try placing puts 'Arduino replied: ' + sp.gets in the loop before sleep (and one puts sp.gets before the loop to read the "I am online" sent when the connection is first established).

Edit: I just spotted another problem in your code, on the Arduino side: value = (incomingByte, DEC) % 16; always results in the value 10 because (incomingByte, DEC) has the value DEC (which is 10). You should use value = incomingByte % 16; instead. Or do away with value altogether and modify incomingByte itself, e.g. incomingByte %= 16;.

like image 119
Arkku Avatar answered Nov 15 '22 09:11

Arkku


Your problems may be caused by buffering. To disable buffering, you can do one of the following:

  • Set sp to unbuffered after creating it (before writing): sp.sync = true
  • Call flush after the write
  • Use the unbuffered syswrite instead of write
like image 31
Peter G. Avatar answered Nov 15 '22 09:11

Peter G.