2012-12-29 76 views
5

我有一些有趣的一个Arduino玩弄(修订版乌诺3)和热敏打印机(这种模式https://www.sparkfun.com/products/10438)。 Arduino每隔10秒向本地机器发出请求(通过以太网屏蔽)并将响应(如果200)存储在SD卡上。然后使用这个库https://github.com/adafruit/Adafruit-Thermal-Printer-Library打印出来。从PHP发送二进制命令的Arduino供电热敏打印机

到目前为止,我有它正确投票,存储并打印基本的文本,但现在我想使用一些更高级的命令(下划线,逆等)。我的最终目标是发送图像并处理服务器上的所有渲染ala http://printer.gofreerange.com/

的问题是我送的命令被输出的文本字符。一些命令可以工作(换行),但其他命令却是乱码。我已经连接了Arduino代码和它所调用的基本PHP脚本。任何帮助?

的Arduino:

#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; 
+0

什么数据是PHP发送打印机损坏? – chugadie

回答

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 

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

F4|boldT32|Thank you for shopping with us\rP6|CenterB3000|...binary data... 
+0

printBitmap只是在后台调用写入。打印粗体等工作正常,所以它必须正确解释作为字节发送的命令(查看PHP的包)。我想我只是有我的图像数据错误。 – Dachande663

+0

您是否确定发送一个字节没有时间问题,然后等待4次,然后发送4个字节,然后一次全部等待? writeBytes(a,b,c,d)可能与writeBytes(a)不完全相同; writeBytes(b)中; writeBytes(C); writeBytes(d);我仍然不会尝试将热库的所有C重新实现到PHP中,这样arduino只是字节的通路 - 它可能工作,但最终可能会遇到计时问题。 我想办法调试它是采取一些Arduino的例子,他们重新写为纯writeBytes(一)调用。如果有效,那么这是一个数据问题。 – chugadie