第1章:读卡器硬件接口:串口(RS232)通信协议、USB HID模式、USB虚拟串口(CDC)模式对比

做POS机驱动开发,第一个绕不开的问题就是:读卡器到底用哪种接口连到主机?

我刚开始接触这个领域时,也以为随便选一种就行。后来踩了不少坑才明白——接口选错了,后面整个驱动框架都得推倒重来。今天咱们就把这三种主流接口掰开揉碎了讲清楚。

1.1 串口(RS232)通信协议

串口,说白了就是最传统的通信方式。POS机读卡器通过DB9或RJ45接口,用TX、RX、GND三根线就能干活。我最早做的几个项目全是RS232接口,那时候觉得这玩意儿又简单又可靠。

核心特点:

  • 电气特性:RS232用±12V电平,抗干扰能力确实强。但传输距离也就15米左右,再远就不行了。
  • 波特率:常见的是9600、19200、38400。我记得有个项目客户非要115200,结果线长了点就丢数据,最后老老实实降回38400。
  • 数据格式:1位起始位 + 8位数据位 + 1位停止位,无校验。这是最通用的配置。

重要提示:RS232的RTS/CTS流控,很多读卡器其实不用。但如果你遇到数据丢包,先检查流控配置,别急着怀疑硬件。

驱动开发要点:

  • Linux下用termios结构体配置串口参数
  • Windows下用CreateFile打开COM口
  • 数据收发用ReadFile/WriteFile
// Linux串口配置示例(关键部分)
struct termios options;
tcgetattr(fd, &options);
cfsetispeed(&options, B38400);
cfsetospeed(&options, B38400);
options.c_cflag |= (CLOCAL | CREAD);
options.c_cflag &= ~PARENB;  // 无校验
options.c_cflag &= ~CSTOPB;  // 1位停止位
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;      // 8位数据位
tcsetattr(fd, TCSANOW, &options);

个人经验:我习惯在串口初始化后先发一个查询命令,看看读卡器有没有回应。这招能快速判断硬件连接是否正常,省得后面排查半天。

1.2 USB HID模式

USB HID模式,说白了就是把读卡器伪装成一个键盘或鼠标。主机不需要装驱动,插上就能用。你想想看,这对用户来说多方便。

为什么会有这种模式?

早期POS机很多是Windows系统,用户不想装驱动。读卡器厂商就想到:既然系统自带HID驱动,那我把读卡器做成HID设备不就行了?

技术细节:

  • 使用中断传输(Interrupt Transfer),延迟低
  • 报告描述符(Report Descriptor)定义数据格式
  • 数据包最大64字节(全速模式)

注意:HID模式有个坑——数据包大小受限。磁条卡数据如果超过64字节,需要分多次传输。我曾经遇到一个读卡器,三轨数据加起来快200字节,结果驱动里要处理分包和重组,代码写起来比串口麻烦多了。

驱动开发要点:

  • Linux下用libusb或hidraw接口
  • Windows下用HID API(如HidD_GetInputReport)
  • 需要解析报告描述符,找到数据对应的Usage ID
// Linux HID读取示例(使用hidraw)
int fd = open("/dev/hidraw0", O_RDWR);
unsigned char buf[64];
int ret = read(fd, buf, sizeof(buf));
// buf[0]是报告ID,后面才是有效数据

避坑指南:我曾经遇到一个读卡器,HID报告里把磁道数据按ASCII码打包,但卡号是BCD码。结果读出来的数据全是乱码。后来仔细看了厂商的协议文档才发现——嗯,这坑踩得值。

1.3 USB虚拟串口(CDC)模式

USB虚拟串口,说白了就是USB接口模拟成串口。主机上会多出一个COM口(Windows)或ttyACM设备(Linux)。

为什么需要这种模式?

很多老式读卡器原本是RS232接口,但现代电脑没有串口了。厂商就在读卡器里加个USB转串口芯片,比如FT232、CP2102。这样硬件不用大改,驱动也兼容。

技术细节:

  • 使用批量传输(Bulk Transfer),速度快
  • 数据包最大512字节(高速模式)
  • 支持流控(DTR/DSR、RTS/CTS)

重要提示:CDC模式的数据传输效率比HID高,因为批量传输没有HID那种64字节限制。但缺点是需要安装驱动(Windows下),Linux内核通常自带cdc_acm驱动。

驱动开发要点:

  • Linux下设备节点是/dev/ttyACM0
  • Windows下是COM3、COM4等
  • 编程接口和RS232完全一样
// Windows CDC串口打开示例
HANDLE hCom = CreateFile(
    "\\\\.\\COM3",
    GENERIC_READ | GENERIC_WRITE,
    0,
    NULL,
    OPEN_EXISTING,
    0,
    NULL);
// 配置参数和RS232一样

个人经验:我建议优先用CDC模式。原因很简单:代码可以和RS232复用,移植成本低。而且数据吞吐量大,适合高速读卡场景。

1.4 三种接口对比总结

对比项 RS232串口 USB HID USB CDC
物理接口 DB9/RJ45 USB Type-A USB Type-A
驱动需求 需要串口驱动 系统自带 需要CDC驱动
最大数据包 无限制(流式) 64字节 512字节
传输延迟
抗干扰 强(±12V)
开发难度
适用场景 工业环境、长距离 免驱需求 高速、兼容性

最后提醒:选接口时别只看技术参数。我见过一个项目,明明用CDC最合适,但客户非要HID模式,理由是「不用装驱动」。结果数据分包处理搞了两个月,得不偿失。你想想看,有时候「方便用户」和「方便开发」之间得找个平衡点。

好了,这一章就讲到这里。下一章咱们聊聊磁条卡的数据格式——三轨数据到底长什么样,怎么解析。到时候我会拿一个真实的读卡器数据包来拆解,保证你看完就能上手。