万万没想到,串口的故事

周末在家进行实验,打算写个VS2008串口发送数据的小程序。结果万万没想到麻烦一大堆。

目标:用VS2008发送串口数据。

为了实现这个目标,需要有能发送和接受串口数据的设备,我有一只USB转串口线,又找到了一个USB转串口的小板子。

20140705984

下面的这个小卡在之前的《使用 Arduino 打造一个硬件的Watchdog》出场过。

20140705985

问题是这两个哥们连不上啊~当然对于每个都分别测试过 loop back.唯独连在一起的时候工作不正常。

20140705981

串口公头定义如下

c2cec3fdfc039245937957298794a4c27c1ed21b0ff405fb

4 数据终端准备好(DTR)
5 信号地线(SG)
6 数据准备好(DSR)
7 请求发送(RTS)
8 清除发送(CTS)
9 振铃指示(RI)

插上之后发现两个都是 ch341A:

dv1

他们之间无法正常通信(当然 TXD TXD GND 已经连接好),乱码,严重的乱码,发送 01 接收到的是 7F,尝试使用Putty和WCH自己的工具都是不行的,波特率之类的设定经过一遍一遍的检查,确定都已经设置为相同了。真是万万没想到啊!

本打算放弃了,忽然想起来前一段买了一个 USB转IIC的小卡,可以当作串口用,也是CH340系列的芯片。再找出我珍藏多年的25米串口线,连在一起。

20140705986

测试他和我那个USB转串口线,通过Putty可以通讯,一切正常。

dv2

终于开始调试程序,发现程序运行时出现错误,GetLastError = 2 意思是“ERROR_FILE_NOT_FOUND 2 (0x2) The system cannot find the file specified.” 【参考2】,但是实验 COM6是可以的。搜索资料,找到【参考3】,原来是我用的下面这样的形式,只给COM1-9来用.......

hComm = CreateFile( "com6", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );

要想打开COM10及其以后的必须使用\\\\.\\COM27这样的形式。

CreateFile(
"\\\\.\\COM27", // address of name of the communications device
fdwAccess, // access (read-write) mode
0, // share mode
NULL, // address of security descriptor
OPEN_EXISTING, // how to create
0, // file attributes
NULL // handle of file with attributes to copy
);

万万没想到啊,还有这样的限制。继续下面的调试。

继续测试发现我的程序这边发送,那边可以收到了,但是只能收到前面几个字节。我的程序端显示发送的字符串数量是正确的,但是接收到的字数却是少了一截。

xx

实验发现如果升高波特率比如使用 9600反倒没问题。于是怀疑这个问题和超时相关,查看COMMTIMEOUTS相关的资料。

// COMMTIMEOUTS对象

COMMTIMEOUTS comTimeOut;
// 接收时,两字符间最大的时延
comTimeOut.ReadIntervalTimeout = 0;
// 读取每字节的超时
comTimeOut.ReadTotalTimeoutMultiplier = 0;
// 读串口数据的固定超时
// 总超时= ReadTotalTimeoutMultiplier * 字节数+ ReadTotalTimeoutConstant
comTimeOut.ReadTotalTimeoutConstant = 0;
// 写每字节的超时
comTimeOut.WriteTotalTimeoutMultiplier = 0;
// 写串口数据的固定超时
comTimeOut.WriteTotalTimeoutConstant = 0;
// 将超时参数写入设备控制
SetCommTimeouts(hCom,&comTimeOut);

上面写为0表示会无限等待下去。但是仍然不好用。

调试又发现如果在WriteFile的时候断点调试,是可以收到的。但是我在他前面加入一个 sheep之后仍然现象相同。

最终,万万没想到,真相只有一个:我在最后设定了关闭串口 CloseHandle(hCom) ,但是如果这个时候没有完成发送就被截断(按道理,应该是同步操作,但是不知道为什么,这里不会等待完全发送)。对于我程序来说解决方法就是把关闭串口放在 pause 的后面………

// ComPortSend.cpp : main project file.
//http://forums.codeguru.com/showthread.php?442634-Serial-port-program-in-c-language
#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include <conio.h>


int main(int argc, char *argv[])
{
   DCB dcb;
   HANDLE hCom;
   BOOL fSuccess;
   TCHAR SPort[]=L"\\\\.\\COM27";
   char txchar[]="This is a test from www.lab-z.com!";
   DWORD iBytesWritten;

   hCom = CreateFile(SPort,
                    GENERIC_WRITE,
                    0,    // must be opened with exclusive-access
                    NULL, // no security attributes
                    OPEN_EXISTING, // must use OPEN_EXISTING
                    0,    // not overlapped I/O
                    NULL  // hTemplate must be NULL for comm devices
                    );

   if (hCom == INVALID_HANDLE_VALUE) 
   {
       // Handle the error.
       printf ("CreateFile failed with error %d.\n", GetLastError());
       return (1);
   }

   SetupComm(hCom, 32, 32);//输入输出缓冲区大小都是1024个字节


   // Build on the current configuration, and skip setting the size
   // of the input and output buffers with SetupComm.

   fSuccess = GetCommState(hCom, &dcb);

   if (!fSuccess) 
   {
      // Handle the error.
      printf ("GetCommState failed with error %d.\n", GetLastError());
      return (2);
   }

   // Fill in DCB: 300 bps, 8 data bits, no parity, and 1 stop bit.

   dcb.BaudRate = CBR_300;     // set the baud rate
   dcb.ByteSize = 8;             // data size, xmit, and rcv
   dcb.Parity = NOPARITY;        // no parity bit
   dcb.StopBits = ONESTOPBIT;    // one stop bit

   fSuccess = SetCommState(hCom, &dcb);

   if (!fSuccess) 
   {
      // Handle the error.
      printf ("SetCommState failed with error %d.\n", GetLastError());
      return (3);
   }

   WriteFile(hCom, &txchar, strlen(txchar), &iBytesWritten,NULL);
   printf ("Serial port %s successfully reconfigured. \n", "COM27");

   system("PAUSE");

   CloseHandle(hCom);

   return (0);
}

 

终于我的Putty在另外一端能够接收到完整的数据了。

代码下载 ComPortSend

后记:从我目前的认知来看,USB转串口质量最好的是 FT232 ,然后是 PL2xx(严重的问题是它没有 Win8的驱动) ,CH34x系列只能排在最后。如果成本压力不是很大,有机会应该优先考虑Ft232。

参考:
1. http://www.elecfans.com/yuanqijian/jiekou/200801247510.html
2. http://msdn.microsoft.com/en-us/library/windows/desktop/ms681382(v=vs.85).aspx System Error Codes (0-499)
3. http://bbs.csdn.net/topics/80130516 用CreateFile打开串口设备,出现问题?
4. http://www.lab-z.com/%E4%BD%BF%E7%94%A8-arduino-%E6%89%93%E9%80%A0%E4%B8%80%E4%B8%AA%E7%A1%AC%E4%BB%B6%E7%9A%84watchdog/ 使用 Arduino 打造一个硬件的Watchdog

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注