5

我在玩 Arduino(Uno rev 3)和热敏打印机(此型号https://www.sparkfun.com/products/10438)时玩得很开心。Arduino 每 10 秒向我的本地机器(通过以太网屏蔽)发出一个请求,并将响应(如果 200)存储在 SD 卡上。然后它使用这个库https://github.com/adafruit/Adafruit-Thermal-Printer-Library打印出来。

到目前为止,我已经正确地轮询、存储和打印基本文本,但现在我正在尝试使用一些更高级的命令(下划线、反向等)。我的最终目标是发送图像并在服务器 ala http://printer.gofreerange.com/上处理所有渲染。

问题是我发送的命令被输出为文本字符。一些命令有效(换行),但其他命令是乱码。我已经附上了 Arduino 代码和它调用的基本 PHP 脚本。有什么帮助吗?

阿杜诺:

#include <SPI.h>
#include <Ethernet.h>
#include <SD.h>
#include <SoftwareSerial.h>
#include "Adafruit_Thermal.h"

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
const char host[] = "192.168.1.100";
char cacheFilename[] = "TMP";

const byte printer_RX_Pin = 8; // this is the green wire
const byte printer_TX_Pin = 9; // this is the yellow wire
const byte SD_Pin = 4;         // the SD Card SPI pin

bool downloadWaiting = false;
bool statusOk = false;
unsigned long content_length = 0;

EthernetClient client;
Adafruit_Thermal printer(printer_RX_Pin, printer_TX_Pin);


void die(unsigned int times) {
  while(true);
}


void checkForDownload() {

  Serial.println("checkForDownload");

  content_length = 0;
  statusOk = false;
  unsigned long length = 0;

  if (SD.exists(cacheFilename)) {
    if (!SD.remove(cacheFilename)) {
      die(4);
    }
  }
  File cache = SD.open(cacheFilename, FILE_WRITE);

  if(client.connect(host, 80)) {

    client.println("GET /printer.php HTTP/1.1");
    client.print("Host: "); client.println(host);
    client.println("User-Agent: arduino-ethernet");
    client.println("Connection: close");
    client.println();

    bool parsingHeader = true;

    while(client.connected()) {
      while(client.available()) {

        if (parsingHeader) {

          client.find((char*)"HTTP/1.1 ");
          char statusCode[] = "000";
          client.readBytes(statusCode, 3);
          statusOk = (strcmp(statusCode, "200") == 0);

          client.find((char*)"Content-Length: ");
          char c;
          while (isdigit(c = client.read())) {
            content_length = (content_length * 10) + (c - '0');
          }

          client.find((char*)"\n\r\n");
          parsingHeader = false;

        } else {
          if(length < content_length) {
            cache.write((byte)client.read());
            length++;
          } else {
              client.read();
          }
        }

      }
    }

    client.stop();
    cache.seek(0);

    if (statusOk && content_length > 0 && (content_length == length) && (content_length == cache.size())) {
      downloadWaiting = true;
    }

  } else {
    client.stop();
  }

  cache.close();

}


void printFromDownload() {

  Serial.println("printFromDownload");

  File cache = SD.open(cacheFilename);
  byte b;

  while (content_length--) {
    printer.write((byte)cache.read());
  }

  printer.feed();

  cache.close();
  downloadWaiting = false;

}


void setup(){

  pinMode(SD_Pin, OUTPUT);
  if (!SD.begin(SD_Pin)) {
    die(2);
  }

  if (Ethernet.begin(mac) == 0) {
    die(3);
  }

  Serial.begin(9600);
  printer.begin(255);

  delay(1000);

}


void loop() {
  if (downloadWaiting) {
    printFromDownload();
    delay(5000);
  } else {
    checkForDownload();
    if (!downloadWaiting) {
      delay(10000);
    }
  }
}

PHP:

<?php

ob_start();


// Turn on Inverse mode
// Doesn't work
echo pack('S', 29);
echo pack('S', 66);
echo pack('S', 1);

$string = 'Testing 1, 2, 3';

foreach(str_split($string) as $char) {
  echo pack('S', ord($char)); // works
}

// Turn off Inverse mode
echo pack('S', 29);
echo pack('S', 66);
echo pack('S', 0);

// Line feed
echo pack('S', 10); // works

$content = ob_get_clean();
$length = strlen($content);
header("Content-Length: $length");

echo $content;
4

1 回答 1

0

看来不能直接用printer.write() 打印位图数据。如您在 printBitmap() 方法中所见,打印机需要一些特殊字节来打开位图打印模式。(writeBytes(18, 42, chunkHeight, rowBytesClipped))

void Adafruit_Thermal::printBitmap(
 int w, int h, const uint8_t *bitmap, bool fromProgMem) {
  int rowBytes, rowBytesClipped, rowStart, chunkHeight, x, y, i;

  rowBytes        = (w + 7) / 8; // Round up to next byte boundary
  rowBytesClipped = (rowBytes >= 48) ? 48 : rowBytes; // 384 pixels max width

  for(i=rowStart=0; rowStart < h; rowStart += 255) {
    // Issue up to 255 rows at a time:
    chunkHeight = h - rowStart;
    if(chunkHeight > 255) chunkHeight = 255;

    writeBytes(18, 42, chunkHeight, rowBytesClipped);

    for(y=0; y < chunkHeight; y++) {
      for(x=0; x < rowBytesClipped; x++, i++) {
        PRINTER_PRINT(fromProgMem ? pgm_read_byte(bitmap + i) : *(bitmap+i));
      }
      i += rowBytes - rowBytesClipped;
    }
    timeoutSet(chunkHeight * dotPrintTime);
  }
  prevByte = '\n';
}

您的草图需要了解来自 PHP 的数据,并知道何时使用printer.write() 将单个字符作为字节发送,何时使用printer.printBitmap() 将字节作为图像发送。通过这种方式,打印机正在接收正确的命令来准备打印相应的数据。您需要围绕要在 PHP 中打印的内容构建一些元数据并将其发送到 Arduino。JSON 格式可能如下所示:

{"reciept": [
  {
    "type": "text",
    "style": "bold",
    "value": "Thank you for your purchase"
  },
  {
    "type": "bitmap",
    "pos": "center",
    "value": ".... binary data ..."
  }
]}

现在您的 Arduino 草图将了解何时以文本形式单独发送字节以及何时以位图形式发送大量数据。

更紧凑的格式可能会使用换行符作为段之间的中断:

F|bold
T|Thank you for shopping with us\r
P|Center
B|...binary data (with \r escaped)... \r

或者,您可以发送每个段的数据量,以避免转义二进制数据,就像 HTTP 的 Content-Length 标头一样

F4|boldT32|Thank you for shopping with us\rP6|CenterB3000|...binary data...
于 2013-01-12T23:32:52.343 回答