Arduino and Windows serial communications issue? - c
I am working on a project that involves some 'c' serial communication implemented in Visual Studio 2010 Proffesional on a Windows 7 32-bit platform connected to an Arduino Mega device (to control some hardware **not relevant to problem). The code for this works 100%; the ONLY problem I'm having is that something very funny is going on with my serial communication.
The Visual C program is as follows.
HANDLE hDevice = CreateFile(L"COM5",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
0); //Open COM handle (create file)
if (hDevice !=INVALID_HANDLE_VALUE) //If COM3 connected
{
printf("Com port opened\n");
DCB lpTest;
GetCommState(hDevice,&lpTest);
lpTest.BaudRate = CBR_9600;
lpTest.ByteSize = 8;
lpTest.Parity = NOPARITY;
lpTest.StopBits = ONESTOPBIT;
SetCommState(hDevice,&lpTest);
DWORD btsIO;
WriteFile(hDevice,c1,strlen(c1),&btsIO,NULL);
CloseHandle(hDevice);
}
The output of this program is a text string, and I'm 100% happy with it (should end in Null, have x characters, etc.).
Typing the result obtained from this program in Serial Communicator, it does not seem to work! Using a COM spy program, I am able to obtain the "handshaking" protocols from the terminal application.
However, it seems that communication with the Arduino board works on HyperTerminal and not on Serial Communicator or any other serial applications (no handshaking, etc. is done on the Arduino board **not relevant).
The following "handshaking" was obtained from HyperTerminal (THIS WORKS!!)
*
COM port is opened
In/out queue size 8192/8192
Baud rate 9600
DTR on
Data bits=8, Stop bits=1, Parity=None
Set chars: Eof=0x00, Error=0x00, Break=0x00, Event=0x00, Xon=0x11, Xoff=0x13
Handflow: ControlHandShake=(DTR_CONTROL, CTS_HANDSHAKE, ERROR_ABORT), FlowReplace= (TRANSMIT_TOGGLE, RTS_HANDSHAKE, XOFF_CONTINUE), XonLimit=80, XoffLimit=200
Set timeouts: ReadInterval=10, ReadTotalTimeoutMultiplier=0, ReadTotalTimeoutConstant=0, WriteTotalTimeoutMultiplier=0, WriteTotalTimeoutConstant=5000
*
And this is from Serial Communicator (it does not work; incorrect and inconsistent numbers):
*
COM port is opened
In/out queue size 2048/2048
Baud rate 9600
RTS off
DTR off
Data bits=8, Stop bits=1, Parity=None
Set chars: Eof=0x00, Error=0x00, Break=0x00, Event=0x00, Xon=0x11, Xoff=0x13
Handflow: ControlHandShake=(), FlowReplace=(), XonLimit=80, XoffLimit=200
Set timeouts: ReadInterval=0, ReadTotalTimeoutMultiplier=0, ReadTotalTimeoutConstant=0, WriteTotalTimeoutMultiplier=0, WriteTotalTimeoutConstant=0
*
I can obviously see the differences but need to know how to make the Arduino board independent of these "handshaking" protocols. (DTR, timing, etc.)
And this is from my Visual Studio program (does not work; incorrect and inconsistent numbers)
*
COM port is opened
Baud rate 9600
RTS off
DTR off
Data bits=8, Stop bits=1, Parity=None
Set chars: Eof=0x00, Error=0x00, Break=0x00, Event=0x00, Xon=0x11, Xoff=0x13
Handflow: ControlHandShake=(), FlowReplace=(), XonLimit=80, XoffLimit=200
*
Thus I would like to get the Arduino board away from DTR and all handshaking, as I want the final implementation to "speak" directly from Visual Studio to the Arduino board.
*****UPDATE*******
Thanks for the advice, the thing is I do not understand is why an open source piece of hardware would require so much handshaking.. That is, why does only the worst serial terminal program work where Serial Communicator, advance serial monitor, terterm, terminal, etc. don't seem to work?
I have updated my code to mirror HyperTerminal exactly (complete all handshaking), but it does not seem to work!
Heres the updated code fragement:
HANDLE hDevice = CreateFile(L"COM5",GENERIC_READ | GENERIC_WRITE,FILE_SHARE_READ | FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,0); //Open COM handle (create file)
if (hDevice !=INVALID_HANDLE_VALUE) //If COM3 connected
{
printf("Com port opened\n"); //Show it's open
DCB lpTest;
// Initialize the DCBlength member.
lpTest.DCBlength = sizeof (DCB);
GetCommState(hDevice,&lpTest); //com state
lpTest.BaudRate = CBR_9600;//load baud
lpTest.ByteSize = 8;// load no. bits
lpTest.Parity = NOPARITY;//parity
lpTest.StopBits = ONESTOPBIT;//stop bits
lpTest.fBinary = FALSE; // Binary mode; no EOF check
lpTest.fOutxCtsFlow = TRUE; // No CTS output flow control
lpTest.fOutxDsrFlow = FALSE; // No DSR output flow control
lpTest.fDtrControl = DTR_CONTROL_ENABLE; // DTR flow control type
lpTest.fDsrSensitivity = FALSE; // DSR sensitivity
lpTest.fTXContinueOnXoff = TRUE; // XOFF continues Tx
lpTest.fOutX = FALSE; // No XON/XOFF out flow control
lpTest.fInX = FALSE; // No XON/XOFF in flow control
lpTest.fErrorChar = FALSE; // Disable error replacement
lpTest.fNull = FALSE; // Disable null stripping
//lpTest.fRtsControl = RTS_CONTROL_ENABLE; //// RTS flow control
lpTest.fAbortOnError = TRUE; // Do not abort reads/writes on error
SetCommState(hDevice,&lpTest);
DWORD btsIO;
//ETC
}
The result is exactly the same as the working result from HyperTerminal except there is no timing conditions. However, I have used a 1 second delay after this code before closing the port.
Is the issue with my write statement?
WriteFile(hDevice,c1,strlen(c1),&btsIO,NULL); //Write string to serial
It seems like there is something fundamentally wrong that I am doing, and I can't find it!
*************UPDATE2***********
I have stumbled across something, how would I configure my program to send each character individually?
Visual Studio does not allow me to remove the Null or send one character in the code:
WriteFile(hDevice,c1,strlen(c1),&btsIO,NULL);//WRITE STRING TO SERIAL
How do I fix this problem? It seems like the Arduino board only accepts one character at a time.
I have edited the character variables to be one char, etc.!
*********UPDATE3********************
This are the results from monitoring the communication from Visual Studio 2010 (or serial communicator) and HyperTerminal. The issue is sending a bit at a time!
HyperTerminal:
Baud rate 9600
DTR on
Data bits=8, Stop bits=1, Parity=None
Set chars: Eof=0x00, Error=0x00, Break=0x00, Event=0x00, Xon=0x11, Xoff=0x13
Handflow: ControlHandShake=(DTR_CONTROL, CTS_HANDSHAKE, ERROR_ABORT), FlowReplace= (TRANSMIT_TOGGLE, RTS_HANDSHAKE, XOFF_CONTINUE), XonLimit=80, XoffLimit=200
Set timeouts: ReadInterval=10, ReadTotalTimeoutMultiplier=0, ReadTotalTimeoutConstant=0, WriteTotalTimeoutMultiplier=0, WriteTotalTimeoutConstant=5000
and Program/serial communication:
Baud rate 9600
DTR on
Data bits=8, Stop bits=1, Parity=None
Set chars: Eof=0x00, Error=0x00, Break=0x00, Event=0x00, Xon=0x11, Xoff=0x13
Handflow: ControlHandShake=(DTR_CONTROL, CTS_HANDSHAKE, ERROR_ABORT), FlowReplace= (TRANSMIT_TOGGLE, RTS_HANDSHAKE, XOFF_CONTINUE), XonLimit=80, XoffLimit=200
An X sec wait in program code.
It's been a long time since I last did serial work -- but it was very clear in those days that your software on the computer had to be configured exactly as the hardware device required. Your non-working example doesn't have DTR or RTS raised, and that's exactly what the board appears to require.
Since software on a full-powered computer is usually far easier to modify than hardware on an embedded board, it'd make sense to look into the configuration options available in your serial software -- any tolerable piece of software will have those settings to fiddle with. If not, I liked both Qmodem and ProComm, though I had friends that were adamant that Telix was the nicer tool. (I had some Trade Wars scripts for Telix that were amazing...)
Just as a suggestion: If you learn some C# and use .net API's it can be so easy to access serial port...
Related
STM32 USB VCP (Virtual Com Port)
I generated a code for "stm32f103c8t6" with CubeMX for USB VCP, when I add "CDC_Transmit_FS" command to send data, the port isn't recognized by windows10! what should I do? Here is the code which is compiled without error: #include "stm32f1xx_hal.h" #include "usb_device.h" #include "usbd_cdc_if.h" int main(void) { uint8_t Text[] = "Hello\r\n"; while (1) { CDC_Transmit_FS(Text,6); /*when commented the port is recognized*/ HAL_Delay(1000); } }
There are three things you need to check in my experience: startup_stm32f405xx.s --> Increase the Heap size. I use heap size 800 and stack size 800 as well. usbd_cdc_if.c --> APP_RX_DATA_SIZE 64 and APP_TX_DATA_SIZE 64 usbd_cdc_if.c --> add below code to the CDC_Control_FS() function Code: case CDC_SET_LINE_CODING: tempbuf[0]=pbuf[0]; tempbuf[1]=pbuf[1]; tempbuf[2]=pbuf[2]; tempbuf[3]=pbuf[3]; tempbuf[4]=pbuf[4]; tempbuf[5]=pbuf[5]; tempbuf[6]=pbuf[6]; break; case CDC_GET_LINE_CODING: pbuf[0]=tempbuf[0]; pbuf[1]=tempbuf[1]; pbuf[2]=tempbuf[2]; pbuf[3]=tempbuf[3]; pbuf[4]=tempbuf[4]; pbuf[5]=tempbuf[5]; pbuf[6]=tempbuf[6]; break; and define the uint8_t tempbuf[7]; in the user private_variables section. Without the increased heap size, Windows does not react at all. Without the point 3, Windows will send the baud rate information and then read the baud rate, expecting to get back the same values. Since you do not return any values, the virtual com port remains as driver-not-loaded. If you do all of that, the Windows 10 out-of-the-box VCP driver can be used. No need to install the very old ST VCP driver on your system. PS: I read somewhere turning on VSense makes problems, too. Don't know, I have not configured it and all works like a charm.
Put delay before CDC_Transmit_FS call - it will wait for the initiatialization. Your code should be like this int main(void) { uint8_t Text[] = "Hello\r\n"; HAL_Delay(1000); while (1) { CDC_Transmit_FS(Text,6); /*when commented the port is recognized*/ HAL_Delay(1000); } }
I had similar issue. I couldn't connect to a port and the port appears as just "virtual com port". I added while loop to wait for USBD_OK from CDC_Transmit_FS. Then it stars work even with out it or a delay after init function. I am not sure what the issue was. while(CDC_Transmit_FS((uint8_t*)txBuf, strlen(txBuf))!=USBD_OK) { }
you may have to install driver to get device recognized as com port you can get it from st site if not installed the device is listed with question or exclamation mark on device manager note that you cannot send until device get connected to host! not sure that CubeMX CDC_Transmit_FS is checking for this also instead of delay to resend you shall check the CDC class data "TXSstate" is 0 mean tx is over.
I know it's a bit late, but I stumbled upon this post and it was extremely helpful. Here is what I needed to do: do the Line-Coding (I think only necessary on Windows-Systems) increase Heap (Stack was left at default 0x200) Here is what wasn't necessary for me (on a STM32F405RGT6 Chip): change APP_RX_DATA_SIZE / APP_TX_DATA_SIZE (left it at 2048) add a delay befor running CDC_Tranmit_FS() Also some things to consider that happened to me in the past: be sure to use a USB-Cable with data lines (most charging-cables don't have them) double check the traces/connections if you use a custom board
Generation of RTE_Components.h
I'm working with MDK-Pro and the File System library. In my application, I require an SPI interface to the SD card. I've managed to setup the project properly, except that in the RTE_Components.h file that Keil generates the line #define RTE_Drivers_MCI0 which subsequently triggers a preprocessor error ("SDIO not configured in RTE_Device.h"). Although I can manually comment out this line in RTE_Components.h, every so often Keil updates this file and I get the above problem. Does anyone know what exactly generates this file, and how I can stop it from adding the SDIO-related definitions into the project?
The RTE_Components.h is not supposed to be modified and will always be automatically generated. That the stack tries to connect via MCI interface is related to your configuration made in the "FS_Config_MC_0.h". // <o>Connect to hardware via Driver_MCI# <0-255> // <i>Select driver control block for hardware interface #define MC0_MCI_DRIVER 0 // <o>Connect to hardware via Driver_SPI# <0-255> // <i>Select driver control block for hardware interface when in SPI mode #define MC0_SPI_DRIVER 0 // <o>Memory Card Interface Mode <0=>Native <1=>SPI // <i>Native uses a SD Bus with up to 8 data lines, CLK, and CMD // <i>SPI uses 2 data lines (MOSI and MISO), SCLK and CS // <i>When using SPI both Driver_SPI# and Driver_MCI# must be specified // <i>since the MCI driver provides the control interface lines. #define MC0_SPI 1
The simplest bridge example won't work - Arduino Yun
I tried to modify the Temperature Web Panel example (found in arduino-1.5.6-rw/libraries/Bridge/examples/TemperatureWebPanel) for a light sensor. Unfortunately it seems even the simplest receive and transmit result over wifi doesn't work! I even commented out the working part to just send back some text to the browser as you can see, but I still see nothing in the browser: #include <Bridge.h> #include <YunServer.h> #include <YunClient.h> // Listen on default port 5555, the webserver on the Yun // will forward there all the HTTP requests for us. YunServer server; String startString; long hits = 0; void setup() { Serial.begin(9600); // For debugging, wait until the serial console is connected. /*delay(4000); while(!Serial); Bridge.begin(); */ // Bridge startup pinMode(13, OUTPUT); Bridge.begin(); digitalWrite(13, HIGH); pinMode(A0, INPUT); // Listen for incoming connection only from localhost // (no one from the external network could connect) server.listenOnLocalhost(); server.begin(); // get the time that this sketch started: Process startTime; startTime.runShellCommand("date"); while (startTime.available()) { char c = startTime.read(); startString += c; } Serial.println("yeah\n"); Serial.println(startTime); } void loop() { // Get clients coming from server Serial.println("a\n"); YunClient client = server.accept(); // There is a new client? if (client) { Serial.println("Client!\n"); // read the command String command = client.readString(); client.print('(This should definitely be sent over bridge)'); /*command.trim(); //kill whitespace Serial.println(command); // is "temperature" command? if (command == "temperature") { // get the time from the server: Process time; time.runShellCommand("date"); String timeString = ""; while (time.available()) { char c = time.read(); timeString += c; } Serial.println(timeString); int sensorValue = analogRead(A0); // convert the reading to millivolts: client.print("Current time on the Yún: "); client.println(timeString); client.print("<br>Current value: "); client.print(sensorValue); client.print("<br>This sketch has been running since "); client.print(startString); client.print("<br>Hits so far: "); client.print(hits); }*/ // Close connection and free resources. client.stop(); hits++; } delay(50); // Poll every 50ms } I see the "a" multiple times in the serial monitor, but never see anything in the arduino.local/arduino/temperature url, just a blank response. Furthurmore, after awhile it seems the Yun was disconnecting from the network, not accessible over http or ssh. How does one debug an issue like this, considering ssh is the main way to communicate with this computer?
After debugging step by step on my own configuration, I found that the code never advanced past Bridge.begin(). Upon further investigation, I found that the default Bridge baud rate of 250000 no longer matched the kernel baud rate of 115200. Changing to: Bridge.begin(115200) ... fixed the issue for me. To determine your kernel speed, run cat /proc/cmdline from a terminal into your Yun See this link for more info: https://groups.google.com/forum/#!msg/linino/-rSmpjX4UOM/Cnjv-uzrlfgJ If this isn't your issue, consider adding debug information (ie.. Serial.print()) in the actual source files for Bridge.cpp, etc. Unfortunately, it appears that Arduino/Linino devs often make breaking changes and do not have the resources to update documentation, examples, etc.
If you are on Windows, don't use 'arduino.local', because Windows has problems to resolve this host. Have you tried with the IP address ? You must televerse your script through wifi, and not through serial (in arduino Ide you must change the port) Have you created the path 'arduino/www/' You need a micro SD card plugged in to your Yún with a folder named “arduino” at the root. Inside the “arduino” folder, there must be a directory called “www”. You need to upload the sketch via WiFi to transfer the contents of the local “www” folder. You cannot transfer files via USB. Once uploaded, you can open your favorite browser and go to http://arduino.local/sd/TemperatureWebPanel. you must open http://YUNS_IP/sd/TemperatureWebPanel
if you are using the Yun Shield u need to comment out the Serial commands or remove all references to serial as the Bridge and the Serial port all share the same hardware serial. I faced the same problem there was no connection.
Replace serial.begin(115...) by Bridge.begin().
Serial COM Port not opening
I am trying to open the serial COM PORT in a Win32 Application. The port is opening correctly but I can send a receive bytes just if I previously opened it using Teraterm or Hyperterminal. If I deactivate and activate the COM port from Device Manager (so the port is freshly unused) I need to simply open the COM port with Teraterm or Putty and afer I closed it and then run my software I can send and receive properly at anytime. I am using Embarcadero X3 with FileMonkey to make the application compatible with MACOSX and Win32 at the same time. FileMonkey does not suuport VCL. The same code is working fine on Builder 6 c++ using VCL but it should not influence it in anyway. My code is really simple. This is a very weird behavior. Seems like I need to INIT the COM (I am using FTDI converter) before I can use it and when the PC restarts or I deactivate and activate back the COM from Device Manager it seems this INIT is vanished and I simply need to open up the COM to revive it using another Serial Software and then use my software. Note: Once the port is INIT I have the full control from my software. I am sure my code is truly opening the COM port because the COM appears busy once the iNIT is done if I try to use it with other softwares. So no flase alarm and more the application is working on the other side so far. I have this problem since long and I now decided to solve it! This is my code: // GLOBAL VARIABLES HANDLE hComm = NULL; COMMTIMEOUTS ctmoNew = {0}, ctmoOld; DCB dcbCommPort; hComm = CreateFile("COM2", GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0); if(hComm == INVALID_HANDLE_VALUE) { Application->Terminate(); } GetCommTimeouts(hComm,&ctmoOld); ctmoNew.ReadTotalTimeoutConstant = 100; ctmoNew.ReadTotalTimeoutMultiplier = 0; ctmoNew.WriteTotalTimeoutMultiplier = 0; ctmoNew.WriteTotalTimeoutConstant = 0; SetCommTimeouts(hComm, &ctmoNew); dcbCommPort.DCBlength = sizeof(DCB); GetCommState(hComm, &dcbCommPort); BuildCommDCB("115200,N,8,1", &dcbCommPort); SetCommState(hComm, &dcbCommPort);
Just a possibility, not certain that this is the problem. But one difference to our typical COM port opening code is that we use SetupCom directly after the CreateFile succeeded and set our buffer sizes, typically 4KB.
Change your settings to: "115200,NOPARITY,8,ONESTOPBIT"
Toggling the CD (RLSD) signal line on a serial port in Windows C
I am trying to set the Carrier Detect (Receive Line Signal Detect) pin on a serial port being controlled by my Windows application. I am already able to set the RTS line high using this function: EscapeCommFunction(handle, SETRTS); and then subsequently clear it by using: EscapeCommFunction(handle, CLRRTS); I want to be able to do this exact same thing with the CD line, but no such SET/CLR flags exist for the EscapeCommFunction.
The PC serial port was designed from the viewpoint of a terminal, not a modem. The CD signal is an output from a modem and an input to a terminal. Even if the port hardware allows you to change the direction (of which I'm skeptical) the standard interface would not be programmed that way.
RS232 devices can be either a DTE (Data Terminal Equipment) or DCE (Data Communications Equipment). Examples of DCEs are modems, multiplexors and some line drivers (technically a modem), everything else including your computer is a DTE. The DCD (RLSD) is an output from a DCE to indicate that has detected the carrier on the comms link i.e. can see the remote modem. I know of no way to convert a DTE into a DCE with a standard serial port.