NerdKits - electronics education for a digital generation

You are not logged in. [log in]

NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.

Project Help and Ideas » Communicating with nerdkit via USB to serial on a mac

May 27, 2009
by andy_b1986
andy_b1986's Avatar

hello,

I am trying to open a port to communicate with the nerdkit using xcode on my mac in c++.I can communicate with the kit using terminal by typing;

ls /dev

.... to get a list of all devices and find the device number. i got the number needed (PL2303 .....)

so communicating with the device is,

screen /dev/tty.PL2303-0000101D 115200

or

screen /dev/cu.PL2303-0000101D 115200

... where i think 115200 refers to the baud rate. These two lines communicate with the kit.

The next step for me is to discard terminal completely and have the project file (running the software i need to use (in this case its face tracking software)) communicating with the nerdkit. The nerdkits staff have been putting up with my questions for the best part of six months so i thought i would give them a break on explaining the detail of this process. They told me that i could open the port by treating PL2303 ..... as a file that i open and right the data to.

This can be done by using some part of stty, [-f] i think. However i have no idea how to implement this and the code I have written comes back with errors. i know it is completely wrong but here it is anyway

{
open();
stty[-f /dev/tty.PL2303-0000101D 115200]
}

I get build errors because stty, f, dev, and tty are not declared and an invlaid suffix on the integer constant. I think i need to include some sort of a header file at the beginning;

#include "stty.h" maybe?

.... and define stty, f, dev and tty

I havent tried it yet as im at work and forgot my laptop with the project on dammit!.

I am a total noob so try not to be too harsh lol!!

January 07, 2010
by N3Roaster
N3Roaster's Avatar

This post shows up pretty high in a Google search for doing this and since it isn't answered yet and I needed to figure out how to do something like this for my own project, here's the answer I came up with. On the AVR side, we'll have a program that reads a line of text from the serial port and sends it to the LCD. The hardware should be wired up as in the guide with both the USB cable and the LCD attached. You'll need the usual set of headers before this.

int main() {
    // The usual boilerplate initialization.
    lcd_init();
    FILE lcd_stream = FDEV_SETUP_STREAM(lcd_putchar, 0, _FDEV_SETUP_WRITE);
    uart_init();
    FILE uart_stream = FDEV_SETUP_STREAM(uart_putchar, uart_getchar, _FDEV_SETUP_RW);
    stdin = stdout = &uart_stream;
    // Clear out anything that's waiting.
    while(uart_char_is_waiting()) {
        uart_read();
    }
    // Create a buffer for our string...
    char command[20];
    // and how many characters have been written to it.
    uint8_t index = 0;
    while(1) {
        // See if we've gotten any data.
        if(uart_char_is_waiting()) {
            while(uart_char_is_waiting()) {
                // Read the character and check for a newline.
                char character = uart_read();
                if(character != '\n') {
                    // Insert the character at the current position in the buffer.
                    command[index] = character;
                    // For debugging purposes, write it on the fourth line of the LCD.
                    lcd_goto_position(3,index);
                    lcd_write_data(character);
                    index++;
                    // Make sure we aren't writing more than fits in the buffer.
                    if(index == 20) {
                        lcd_line_three();
                        lcd_write_string(PSTR("Buffer overload.    "));
                        index = 0;
                    }
                }
                else {
                    // We have received a newline character.
                    // Clear the fourth line.
                    lcd_line_four();
                    lcd_write_string(PSTR("                    "));
                    lcd_line_three();
                    int i;
                    // Write the string we've received.
                    for(i = 0; i < index; i++) {
                        lcd_write_data(command[i]);
                    }
                    // Reset the index.
                    index = 0;
                }
            }
        }
    }
    // We never get here.
    return 0;
}

You can fire up screen as usual and start typing into that to verify that the characters you type show up on the fourth line.

On the Mac side, we have a C program. The code should work fine in your C++ program and XCode shouldn't have any trouble with it, but I'm skipping over setting this up in XCode as it's needlessly complex for this example. This program will open the device file, set the baud rate to match the kit, and write "Hello, World!". Drop the following into a file such as main.c

#include <stdio.h>
#include <termios.h>
#include <fcntl.h>
#include <string.h>

int main(int argc, char **argv)
{
int fd;

// Open the device file. Change this to match your device.
printf("open /dev/cu.PL2303-0000103D\n");
fd = open("/dev/cu.PL2303-0000103D", O_RDWR);
if(fd < 0)
{
    printf("Error opening port.\n");
    return 1;
}
printf("Port opened.\n");
// Change the baud rate of the tty device.
struct termios term;
tcgetattr(fd, &term);
cfsetispeed(&term, B115200);
cfsetospeed(&term, B115200);
tcsetattr(fd, TCSANOW, &term);
// Here's the string we'll send.
char *command = "Hello, World!\n";
int i;
for(i = 0; i < strlen(command); i++)
{
    write(fd, &command[i], 1);
    // If we don't wait, characters get lost.
    usleep(40000);
}
close(fd);
return 0;
}

On the command line, navigate to the directory where you've saved main.c and type:

gcc main.c

This will create a program called a.out which you can run by typing:

./a.out

Connect the kit to your computer and if it's not being powered by the USB port, connect the power. Then run the program. You should see the characters appearing one at a time on line four and then the message should move up to line three.

There is ample room to improve this example, but it should get you going in the right direction.

Note that there's really nothing Mac specific about this other than the name of the device file. The program should work the same under Linux (though I have not tested that).

January 08, 2010
by mrobbins
(NerdKits Staff)

mrobbins's Avatar

Hi N3Roaster,

Welcome to the forums, and thanks for the informative post!

The straightforward way of reading characters and sending them to the LCD works fine, but as you mention in your PC-side code, you may need to manually insert a delay because it takes a bit of time to communicate with the LCD. If you're up for a challenge, I will mention that it's possible to implement your serial port handling in an interrupt handler, and implement a data structure so that the LCD communication runs in the main loop "in the background". That's more complicated, but a great learning experience to fight your way through :-)

Mike

January 08, 2010
by N3Roaster
N3Roaster's Avatar

Yes, that's one of those opportunities to improve the above code. I've already written an ISR to handle the ADC interrupt and have looked at the datasheet for details on doing the same with serial communications. It looks fairly straightforward. In that case I'm thinking the way to go would involve two character buffers, one for the string being sent, another with a finished string ready for processing in the main routine, just swapping the pointers and setting a flag when new strings are accepted. The particulars would depend on how frequently the computer would be sending a new string and how long whatever processing is being done would take. Another way to take this would be to not just send the text directly to the LCD, but interpret simple commands and (for example) drive pins high or low in response. The PC side code can also be made more sophisticated, for example, by listening for data from the kit which could be used for flow control, status information, &c. It could also be made interactive.

May 04, 2010
by Ralphxyz
Ralphxyz's Avatar

If anyone is still watching this thread why do I get:

 ||Hello,  World!

Where do the bangs come from?

Ralph

Post a Reply

Please log in to post a reply.

Did you know that interrupts can cause problems if you're not careful about timing and memory access? Learn more...