Serial port in C in windows works only after using terminal program - Page 1
Forum section: electronics / projects

author: jmaja
author_rank: Frequent Contributor
timestamp: May 05, 2017, 06:29:22 am
content: There is something strange I can't figure out. Maybe someone can point the obvious mistake I'm making. I'm trying to read lines of serial data (100-110 bytes/line ASCII at 10 Hz at 115200) from my SAMD21 board via USB virtual port in Windows 7. It works just fine, IF I first open the port in e.g. Tera Term (even with wrong baud rate etc.) and then in my program. But if I don't use Tera Term after pluging the USB, I get no characters reading the COM port. No errors either.So what does Tera Term do that I'm not doing to enable the data flow?Here is how I open the port:Code:unsigned char open_port(HANDLE *hSerial, unsigned char port){DCB dcbSerialParams = {0};COMMTIMEOUTS timeouts={0};char com_port_name;sprintf(com_port_name, "\\\\.\\COM%d", port);*hSerial = CreateFile(com_port_name,GENERIC_READ | GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);if(*hSerial==INVALID_HANDLE_VALUE){if(GetLastError()==ERROR_FILE_NOT_FOUND)printf("Port %s not found\n", com_port_name);elseprintf("Error opening port\n");return 0;}dcbSerialParams.DCBlength=sizeof(dcbSerialParams);if (!GetCommState(*hSerial, &dcbSerialParams))printf("Unable to get state\n");printf("Rate %ld\n",dcbSerialParams.BaudRate);dcbSerialParams.BaudRate=CBR_115200;dcbSerialParams.ByteSize=8;dcbSerialParams.StopBits=ONESTOPBIT;dcbSerialParams.Parity=NOPARITY;if(!SetCommState(*hSerial, &dcbSerialParams))printf("Unable to set state\n");if (!GetCommState(*hSerial, &dcbSerialParams))printf("Unable to get state\n");printf("Rate %ld\n",dcbSerialParams.BaudRate);timeouts.ReadIntervalTimeout=2;timeouts.ReadTotalTimeoutConstant=10;timeouts.ReadTotalTimeoutMultiplier=0;timeouts.WriteTotalTimeoutConstant=0;timeouts.WriteTotalTimeoutMultiplier=0;if(!SetCommTimeouts(*hSerial, &timeouts))printf("Unable to get state\n");return 1;}Here is how I read it:Code:double read_angle(HANDLE hSerial, DWORD *PZ){int i=0;double angle=-100.0, angle_new;DWORD dwBytesRead = 0, PZ_new;char szBuff;*PZ=0;if(!ReadFile(hSerial, szBuff, 200, &dwBytesRead, NULL)){printf("Unable to read\n");return -100;}while(i<dwBytesRead){printf("%c", szBuff);if(szBuff=='Z' && ((i+5)< dwBytesRead) && (szBuff[i+1]==':')){if(sscanf(&szBuff[i+2],"%ld",&PZ_new)==1){*PZ=PZ_new;}}if(szBuff=='e' && ((i+5)< dwBytesRead)){if(sscanf(&szBuff[i+3],"%lf",&angle_new)==1){angle=angle_new;}}i++;}return angle;}

author: KE5FX
author_rank: Super Contributor
timestamp: May 05, 2017, 06:34:08 am
content: Maybe they turn on the DTR and/or DSR lines? Some devices want that, some don't.

author: Macman
author_rank: Regular Contributor
timestamp: May 05, 2017, 06:42:56 am
content: You need to set the flow control fields in the DCB and possibly also the RTS and CTS states if you are not using hardware flow control.

author: jmaja
author_rank: Frequent Contributor
timestamp: May 05, 2017, 06:51:09 am
content: Thanks!This was all I needed to add:Code:if(EscapeCommFunction(*hSerial, SETDTR)==0)printf("Error Setting DTR\n");

author: abyrvalg
author_rank: Frequent Contributor
timestamp: May 05, 2017, 09:42:17 am
content: This fix doesn´t cover all cases. You are still depending on some previously set parameters (i.e. enabled Xon/Xoff flow control can produce weird effects after receiving some specific bytes). For a full coverage don't do GetCommState() but fill entire DCB structure, setting all unused modes to FALSE/DISABLED:https://msdn.microsoft.com/es-es/library/windows/desktop/aa363214(v=vs.85).aspx