Despite trying for hours I can't send a simple serial command to arduino with c++. I found the c++ lib, however I blatantly fail to use it. Adopting more or less what I found in this lib I was able to connect to my arduino, but I can't send a command. Here is what I have so far of which only the writefile part doesn't work:
Thanks a lot!
//AML
#include <windows.h>
#include <stdio.h>
int main()
{
HANDLE ArduinoSerial;
DWORD tmp;
COMSTAT status;
DWORD errors;
char *buffer = "L"; //what to write
int nbChar = 1; // how many chars
while(1)
{
if(GetAsyncKeyState(VK_F8)& (1==1)) { // to open serial port to arduino
ArduinoSerial = CreateFile( "COM4",
GENERIC_READ | GENERIC_WRITE,
0,
0,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
0);
if (ArduinoSerial == INVALID_HANDLE_VALUE)
{
MessageBox(NULL, "failed, either wrong device or port is in use", "lc", MB_OK);
}
else
{
//If connected we try to set the comm parameters
DCB dcbSerialParams = {0};
//Define serial connection parameters for the arduino board
dcbSerialParams.BaudRate=CBR_9600;
dcbSerialParams.ByteSize=8;
dcbSerialParams.StopBits=ONESTOPBIT;
dcbSerialParams.Parity=NOPARITY;
//Set the parameters and check for their proper application
if(!SetCommState(ArduinoSerial, &dcbSerialParams))
{
MessageBox(NULL, "Could not set Serial Port parameters", "lc", MB_OK);
}
else
{
MessageBox(NULL, "Successfully connected to Arduino", "lc", MB_OK);
}
}
if(!WriteFile(ArduinoSerial, (void *)buffer, nbChar, &tmp, 0))
{
ClearCommError(
ArduinoSerial, // handle to communications device
&errors, // pointer to variable to receive error codes
&status);
MessageBox(NULL, "error", "lc", MB_OK);
}
else
MessageBox(NULL, "Data sent", "lc", MB_OK);
}
}
}
One annoying thing about the arduino, is that opening the serial-port in software may restart the arduino. You have to allow for the time the arduino would need to reboot after opening the serial port.
You are probably writing the data while the Arduino is still rebooting. To fix this you can physically disable the auto-reset feature of your Arduino or just wait for it to reboot.
Looking at your code, you seem to have other problems. You are using Microsoft specific stuff, so I don't know what exactly those functions do, but you appear to be constantly re-opening the serial-port file, which is a big no-no.
It is too bad that Microsoft seems to not give a damn about serial ports anymore. It's unlikely that MS will ever implement ioctl so that you can go above 115kbaud, and the .Net serial-port stuff leeks memory
With the limitations of normal Windows serial-port programming, you may just want to ditch it. There are two other options:
I tried to add a 10 second delay to my code but it doesn't work either. I won't initialize the serial connection every time in the end, it's merely to test if i am able to send a command over it, which i don't seem to be able to.
The FTDI lib seems promising but can't get it to work either, the FTDI test utility fails too...
If someone would find the mistake in my code or show me with an example in c++ how to send a command through any other method from windows I would be really grateful. As I'm a starting c++ programmer I think an example would be the best way for me to learn. This c++ serial thing is still a bit beyond me.
The Windows interface you are using is C, not C++. How about writing some C code to do what you want. Then once that works you can wrapper with a C++ GUI. That way you can get one piece of code working at a time.
I would suggest separating out the function into a C file and interface so it can be reused by both the command line C and the GUI C++. Here is an example of my serial.h header file.
extern void clearQueue(HANDLE port);
extern void closeSerialPort(HANDLE port);
extern HANDLE openSerialPort(int serialPort, long baudRate, unsigned long timeOut);
extern int readSerialPortBuffer(HANDLE port, unsigned char *buffer, int len);
extern int readSerialPortByte(HANDLE port, int timeout, unsigned char *byte);
extern int setSerialTimeout(HANDLE port, unsigned long timeout);
I was trying to push the Duemilanove's USART/serial to its extremes. This is what I have learned.
The FTDI chip is capable of the following baud-rates:
3000000 baud
2000000 baud
and then pretty much everything between 1000000baud and 300baud.
baud = 24000000/n : where n = 24 or greater
You can not set the FTDI chip to any baud rate between 3Mbaud, 2Mbaud, and 1Mbaud. Pretty much anything under 1Mbaud is possible.
The Arduino/AVR has 4 modes with the following baud rate limits:
async normal
baud = cpu_hz/(16*n) : where n=1 to 4096
for 16Mhz:
1000000 baud
500000 baud
333333.3 baud
etc
async double
baud = cpu_hz/(8*n) : where n=1 to 4096
for 16Mhz:
2000000 baud
1000000 baud
666666.6 baud
etc
sync master
baud = cpu_hz/(2*n) : where n=1 to 4096
for 16Mhz:
8000000 baud
4000000 baud
2666666.6 baud
2000000 baud
etc
the baud rate will be output on the XCK pin(Arduino pin 4). You are supposed to hook this pin to a device in slave-sync mode.
sync slave
You have to provide a clock on the XCK pin(Arduino pin 4) at the baud-rate you want. Any baud can be used, but the recommended maximum is (cpu_hz/4) and probably should be less than (cpu_hz/8).
The primary differences between the Arduino USART modes are:
async-norm samples every incoming bit 16 times
async-double samples every incoming bit 8 times
the sync modes sample every incoming bit 2 times and uses the XCK pin(Arduino pin 4) to synchronize the flow.
The extra sampling is to detect as the baud rates on each side of the connection drift apart. This shouldn't happen when you have the clocks tied together in the sync modes.
I'm not sure how much extra sampling the FTDI chip does, but it says it can deal with up to 3% aliasing of the baud rate, which is similar to normal-mode on the Arduino.
I only have 16Mhz Arduinos and I have tried:
using a 16Mhz Arduino at 3Mbaud in sync-slave mode, but I had a lot of corrupted bytes(~5% were corrupted). This could have been because of something bad in my setup.
using sync-master to do 2Mbaud, but it doesn't have any advantage over async-double at 2Mbaud and a severe disadvantage when sending data to the Arduino. I had no corruption problems though.
using sync-master to do 2.66Mbaud with the FTDI chip at 3Mbaud, and it doesn't work at all.
If you have a 12Mhz Arduino, you could clock the USART at 3Mbaud in sync-master mode and get a LOT more bandwidth. There wouldn't be a disadvantage for sending data to the PC, but you would have problems sending data to the Arduino.
P.S.
The FTDI driver won't throw an error if you try to select a baud-rate that is aliased VERY badly (i.e. select 2.666Mbaud and it aliases to 3Mbaud). It only errors when you select too high or too low a baud rate. The Arduino Serial.begin() doesn't take into account aliasing either; at least as of Arduino-16.