Pages: [1]   Go Down
Author Topic: Desktop serial read from Arduino in generic C or C++  (Read 1512 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Full Member
***
Karma: 1
Posts: 129
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I use a Code::Blocks IDE for developing Arduino sketches. I wanted to use the same IDE to create a desktop program that reads the USB port to get data sent by the Arduino. Does anyone have a program that works? Even a test program would be great.

I have looked at VBScript that supposedly works, but I don't do VBScript. Needless to say I don't have dotNet or MFC, so ..Wnat else is there?? Win32?

I'm stumped as to how to proceed.

Should the Processing library be used here?
« Last Edit: October 03, 2012, 06:47:49 pm by louarnold » Logged

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 631
Posts: 50180
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

http://arduino.cc/playground/Main/InterfacingWithSoftware
Lots of ways to talk to the serial port.
Logged

Offline Offline
Full Member
***
Karma: 1
Posts: 129
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

http://arduino.cc/playground/Main/InterfacingWithSoftware
Lots of ways to talk to the serial port.
Thank you. There is a great deal there, but if you go through it all, you'll see that there is very little that is for Windows , and is in C++, and is very simple, and uses a small amount of code, and is explained, and does not require Visual Studio. I have already written Arduino resident software that sends ASCII data to a desktop via the USB port. The problem is how to write the desktop resident software.

So here are a few questions:
1) I thought Firmata is out of date. Is that true? Does this library useful in a desktop program communicating over the serial port?
2) The examples seem to have code developed in the Ardunio IDE that execute in the desktop under Windows. Is that true? If so, what do I do to make that work?
3) Is the "Processing" library useful for communications over the serial port?
Logged

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 631
Posts: 50180
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
1) I thought Firmata is out of date. Is that true? Does this library useful in a desktop program communicating over the serial port?
It's not out of date. It's simply not being supported (or visibly supported, I should say) for the Arduino. Anyway, the sending application needs to send data in the Firmata format. Is this something you know how to do?

Code:
2) The examples seem to have code developed in the Ardunio IDE that execute in the desktop under Windows. Is that true? If so, what do I do to make that work?
Which examples are you referring to? Applications developed in the Arduino IDE run on the Arduino, not on the PC.

Quote
3) Is the "Processing" library useful for communications over the serial port?
The Processing application is. It's more than a library.
Logged

Offline Offline
Full Member
***
Karma: 1
Posts: 129
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
1) I thought Firmata is out of date. Is that true? Does this library useful in a desktop program communicating over the serial port?
It's not out of date. It's simply not being supported (or visibly supported, I should say) for the Arduino. Anyway, the sending application needs to send data in the Firmata format. Is this something you know how to do?

Code:
2) The examples seem to have code developed in the Ardunio IDE that execute in the desktop under Windows. Is that true? If so, what do I do to make that work?
Which examples are you referring to? Applications developed in the Arduino IDE run on the Arduino, not on the PC.

Quote
3) Is the "Processing" library useful for communications over the serial port?
The Processing application is. It's more than a library.

I'll leave Firmata for now.
The code that confused me: http://www.arduino.cc/playground/interfacing/processing, see Example. The setup fr that code is very similar to software that is downloaded to the Arduino.
On that page, it talks about libraries, but I didn't see a link to getting the "Processing application" (or IDE?). I assume the "import" statements are for that IDE.

And, at last, here: http://arduino.cc/playground/Interfacing/CPPWindows. This is just a class definition but its supposed to have been tested with Code::Blocks and MINGW. I'll let you know. Well, the class compiles under CodeBlocks and MINGW. Would be nice to have an example of use, but the one given is for VC++ 2008 Express.

There is also a class (Google serial_src_zip), but when I try and compile that, it says it can't find "stdafx.h", and I don't know why that happens or how to fix that. I seem to recall that stdafx is for MFC. Its been too long. Is that not true?
« Last Edit: October 04, 2012, 08:27:49 pm by louarnold » Logged

Offline Offline
Full Member
***
Karma: 1
Posts: 129
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Solved!

The CPP for Windows class and header code is here: (http://arduino.cc/playground/Interfacing/CPPWindows). I have compiled this with Code::Blocks using MINGW. I also have the Arduino IDE code. I used a rev 3 UNO with v1.0.1 of the IDE.
Because the Arduino code outputs a PWM waveform (variable width pulse) to pin 9 on the Arduino, I used a scope. You can try a resistor in series with an LED (a 1K usually works for a red LED) to ground. It should vary with the value that you send the Arduino.

Here is the Arduino IDE code:
Code:
//LEDBrightSerialread.ino
const int ledPin = 9; // the pin that the LED is attached to
byte brightness, digit, decval;

void setup()
{
  // initialize the serial communication:
  Serial.begin(9600);
  // initialize the ledPin as an output:
  pinMode(ledPin, OUTPUT);
}

void loop() {
  if (Serial.available())
  {
    // read the most recent byte (which will be from 0 to 255):
    digit = Serial.read();
    decval=digit-48;
    if ((decval>=0) && (decval<=9))
    {
      brightness=brightness*10+decval;
    }
    else if (digit=13)
    {
      // set the brightness of the LED:
      Serial.println(brightness);
      analogWrite(ledPin, brightness);
      brightness=0;
    }
  }
}//End loop()
By the way, there is an ASCII table here: http://www.asciitable.com.

The code reads an ASCII digit (digit = Serial.read()smiley-wink, and then converts it to a decimal value (decval=digit-48;). If the value is between zero and nine, it is added to the end of the brightness value. So when it receives ASCII 1 2 3, the brightness value becomes 123. Receiving an ASCII 13 (carriage return) ends the accumulation and outputs the brightness value to pin 9 as well as to the serial port (to the Windows' Hyper Terminal (HT) program if you have it running and connected to the port.

For the PC side, I am running Windows XP Pro SP3. I used Code::Blocks(CB) 10.05. I had MINGW already installed, but you can simply install a CB version that includes MINGW. Once CB is installed, simply create a console project. I created a folder "CPPWinCodeBlocks" in that project folder and put the SerialClass.cpp and SerialClass.h into it.

In the CB project bring in the two SerialClass files by right-clicking the project name and selecting Add files. Select both files in the Open dialog window. CB will place them in the project structure at the far left. Then modify the main.cpp as follows:
Code:
//Main.cpp
#include <iostream>

#include "H:\CB10_05\CPPWinCodeBlocks\serialclass.h"
using namespace std;
void Test()
{
char numb1[4]={49, 50, 57,13}; //"127";
char numb2[4]={50, 53, 53,13}; //"255";
char numb3[3]={ 49, 49,13}; //"11";
char numb4[2]={ 48, 13}; //"0";
char pn[5]="COM4"; //port name
Serial* sp4= new Serial(pn);
BOOL xx;
int numb1size=sizeof(numb1);
int numb2size=sizeof(numb2);
int numb3size=sizeof(numb3);
int numb4size=sizeof(numb4);
xx=sp4->IsConnected();
if (xx)
{
xx=sp4->WriteData(numb1, numb1size);
Sleep(2000);
xx=sp4->WriteData(numb2, numb2size);
Sleep(2000);
xx=sp4->WriteData(numb3, numb3size);
Sleep(2000);
xx=sp4->WriteData(numb4, numb4size);
}
}
int main()
{
    cout << "Hello world!" << endl;
    Test();
    return 0;
}
The code just writes out ASCII digits to com port 4 (COM4) followed by a 13 (carriage return), and then delays for 2 seconds. Four sequences are written in total. The LED should be dark at the start and then go half=bright (127), then full bright (255), and then darker (11), and then completely dark (0).

Keep in mind that on the PC, you can only have one program using the port at a time. You must stop executing your PC program in order to change and upload your Arduino-resident program. If you use Hyper Terminal, you can "hang up" the connection to the port and yet still keep HT running, then reconnect using the icons in the toolbar. You will have to hang-up to run your PC program.

This is pretty simple, but you should, of course, cut main.cpp to a bare minimum to see how it works. Good luck.

If this post belongs in a wiki somewhere, pls let me know, although I really don't know how to do that.
« Last Edit: October 04, 2012, 11:41:33 pm by louarnold » Logged

France
Offline Offline
Sr. Member
****
Karma: 2
Posts: 380
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I used CodeBlock to do things with Serial through Usb and Arduino.

I give you a piece of code that contains the main tools to do it. It will not compiles but it's easy to understand and to use it.

Code:
HANDLE SerialInit(char *ComPortName, int BaudRate)
{
    HANDLE hCom;
    DCB dcb;
    BOOL bPortReady;

    hCom = CreateFile(ComPortName,
                      GENERIC_READ | GENERIC_WRITE,
                      0, // exclusive access
                      NULL, // no security
                      OPEN_EXISTING,
                      0, // no overlapped I/O
                      NULL); // null template

    bPortReady = SetupComm(hCom, 2, 128);
    bPortReady = GetCommState(hCom, &dcb);
    dcb.BaudRate = BaudRate;
    dcb.ByteSize = 8;
    dcb.Parity = NOPARITY;
    dcb.StopBits = ONESTOPBIT;
    dcb.fAbortOnError = TRUE;
    dcb.fOutX = FALSE;
    dcb.fInX = FALSE;
    dcb.fOutxCtsFlow = FALSE;
    dcb.fRtsControl = FALSE;
    dcb.fOutxDsrFlow = FALSE;
    dcb.fDtrControl = DTR_CONTROL_DISABLE;
    bPortReady = SetCommState(hCom, &dcb);

    return hCom;
}

uint8 SerialGetc()
{
    char toDisp[128];

    while(1)
    {
        static char rxchar;
        static DWORD iBytesRead;

        char buffer[128];
        static byte cpt=0;
        static byte cmdOk=0;


        ReadFile(*ptr, &rxchar, 1, &iBytesRead, NULL);

        if (iBytesRead!=0)
        {
            switch(rxchar)
            {
            case '#':
                cpt = 0;
                cmdOk=0;
                break;

            case '!':
                buffer[cpt]='\x0';
                cmdOk=1;
                break;

            default:
                cmdOk=0;
                buffer[cpt++]=rxchar;
            }

            if (cmdOk)
            {
               // Do some stuff here because you get a new command from arduino !
           
            }
        }
    }
    return 0;
}


void SerialPutc(char txchar)
{
    DWORD iBytesWritten;
    BOOL res;

    res = WriteFile(*ptr, &txchar, 1, &iBytesWritten,NULL);
}

void SerialPutString(char *txchar)
{
    DWORD iBytesWritten;
    BOOL res;
    DWORD length;

    iBytesWritten = 0;

    length = strlen(txchar);

    res = WriteFile(*ptr, txchar, strlen(txchar), &iBytesWritten,NULL);

    FlushFileBuffers(ptr);
    /*
        sprintf(disp, "%ld", iBytesWritten);
        window->label(strdup(disp));
    */
}

void check(void *)
{
    SerialGetc();
}


int main(int argc, char *argv[])
{
  HANDLE my=SerialInit((char *)"com8",115200);
   _beginthread( check, 0L, (void *)0L);
 
}

This code initialize the com port from arduino ie the number you use to upload a program to arduino and set the speed at 115200 bauds (you can use a lower one as 9600, 38400, 57600).

Then this code start an thread to will 'ear' to the serial port.

The way I used to comunicate with arduino was a very simple protocol :

Arduino transmit command with a ascii (string) format like :

#CMDXXVAL1YYVAL2ZZ!

# is the marker that begin a command
CMDXX is the number of the command (get value, set value, .... everything as you want)
VAL1YY set or return YY to VAL1
VAL222 set or return ZZ to VAL2
! is the end of the command.

So from :

Every time you get the '#' character you start a new command
As each readed character is not the '!' you store them into a buffer of chars.
When you get the '!' the command is complete, you can also decode it and do stuff you want.

I also added to this code the 2 fonctions that will allow you to send a string to the arduino.

If you need more help, I can do things for you.

Best regards


Logged

Offline Offline
Full Member
***
Karma: 1
Posts: 129
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

To Grag38:
Thanks for your code. Its not difficult to understand, and its in straight C. But I think there are pieces missing, like #include statements and perhaps header files. Some of us can guess what's needed, but many cannot. This is the problem with many examples. If you use CodeBlocks then it helps to have ALL the code, organized so people can copy and drop the code into CodeBlocks. That little extra is often the key to success for many people.

The other end if this is the code that is written in the Arduino IDE and "uploaded" to the mcu - the code that receives and executes the commands. Can you provide that?
Logged

Offline Offline
Full Member
***
Karma: 1
Posts: 129
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I hope no one kills me, but I never thought about this obvious fact until now:  We probably should be programming the desktop reads and writes in Java. Makes everything portable so we don't have to re-invent the methods for another language or IDE.
Logged

Pages: [1]   Go Up
Jump to: