ESC/POS打印机打印二维码后无响应的原因及解决方法
问题描述
使用sendToPrinter函数向ESC/POS打印机发送文本指令时工作正常,但发送二维码指令后打印机无响应,且后续所有打印指令(文本或二维码)均失效,必须重启打印机才能恢复。相关代码如下:
bool Printer::sendToPrinter(const std::string &devicePath, const std::string &text) { std::string qrCodeCommands = "\x1B\x40" "\x1D\x28\x6B\x04\x00\x31\x41\x32\x00" "\x1D\x28\x6B\x03\x00\x31\x43\x03" "\x1D\x28\x6B\x03\x00\x31\x45\x31" "\x1D\x28\x6B\x0F\x00\x31\x50\x30" "Hello world" "\x1D\x28\x6B\x03\x00\x31\x51\x30"; std::string processedText = "\x1B\x40" + qrCodeCommands + "\n\n"; #ifdef _WIN32 HANDLE hPrinter = CreateFile(devicePath.c_str(), GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hPrinter == INVALID_HANDLE_VALUE) { log("Failed to open printer device: " + devicePath); return false; } DWORD bytesWritten = 0; if (!WriteFile(hPrinter, processedText.c_str(), processedText.size(), &bytesWritten, NULL)) { log("Failed to send data to printer."); CloseHandle(hPrinter); return false; } if (bytesWritten != processedText.size()) { log("Mismatch in bytes written to printer."); CloseHandle(hPrinter); return false; } CloseHandle(hPrinter); #else const int fd = open(devicePath.c_str(), O_WRONLY); if (fd < 0) { log("Failed to open printer device: " + devicePath); return false; } ssize_t bytesWritten = write(fd, processedText.c_str(), processedText.size()); if (bytesWritten < 0) { log("Failed to send data to printer."); close(fd); return false; } if (bytesWritten != static_cast<ssize_t>(processedText.size())) { log("Mismatch in bytes written to printer."); close(fd); return false; } close(fd); #endif log("Data successfully sent to printer: " + text); return true; }
问题原因
- 重复发送打印机初始化指令:
qrCodeCommands中已经包含\x1B\x40(打印机初始化指令),但processedText又重复添加了一次该指令。重复初始化会打乱打印机的状态机,导致后续指令无法正常解析。 - QR码数据指令的长度参数错误:QR码数据指令
\x1D\x28\x6B\x0F\x00\x31\x50\x30中的0F\x00是后续数据的长度(pL=15,pH=0),但实际后续的31\x50\x30+Hello world总长度为14字节,长度不匹配会导致打印机进入异常解析状态,直接卡死。 - 缺少缓冲区刷新指令:发送完QR码指令后,没有发送强制打印/刷新缓冲区的指令,打印机可能一直等待后续数据,无法完成当前打印任务,进而阻塞后续指令。
解决方法
1. 移除重复的初始化指令
删除processedText开头的\x1B\x40,避免重复初始化。
2. 修正QR码数据指令的长度参数
计算正确的数据长度:31\x50\x30(3字节)+Hello world(11字节)=14字节,因此长度参数应为0E\x00,对应指令修改为\x1D\x28\x6B\x0E\x00\x31\x50\x30。
3. 添加缓冲区刷新与走纸指令
在QR码打印指令后添加\x0D\x0A\x0D\x0A(换行走纸)或\x1D\x50\x00(打印并走纸),确保打印机执行完当前任务并刷新缓冲区。
修正后的完整指令示例
std::string qrCodeCommands = "\x1B\x40" // 初始化打印机 "\x1D\x28\x6B\x04\x00\x31\x41\x32\x00" // 设置QR码版本为2 "\x1D\x28\x6B\x03\x00\x31\x43\x03" // 设置QR码模块大小为3 "\x1D\x28\x6B\x03\x00\x31\x45\x31" // 设置纠错级别为M "\x1D\x28\x6B\x0E\x00\x31\x50\x30" // 开始QR码数据传输(长度14) "Hello world" // QR码内容 "\x1D\x28\x6B\x03\x00\x31\x51\x30" // 打印QR码 "\x0D\x0A\x0D\x0A"; // 换行走纸,刷新缓冲区 std::string processedText = qrCodeCommands;
额外建议
- 发送指令前,确保打印机处于就绪状态,避免在异常状态下发指令。
- 可以添加指令校验逻辑,确保每个ESC/POS指令的长度参数与实际数据长度匹配。
内容的提问来源于stack exchange,提问作者Stefan Zindović
相关产品推荐
相关产品推荐

