c语言设置一个8位缓存区程序,单片机 并口 控制爱普生打印机开发流程记录

最近做一个项目,需求是通过昆仑通态的组态触摸屏作为上位机监测数据,然后将数据整合最后打印报表输出。昆仑通态以前可以直接将预览页的所有数据都打印出来,包括整屏未显示完全的。但是现在昆仑通态将WIN平台换为Linux了(据说是因为版权授权问题),于是就没有这个功能了。因为需求量不够,也不能获得厂家的直接支持,于是只能想办法通过自己下位机去驱动打印机,直接完成数据的打印输出。

市面上目前主要是惠普与爱普生打印机用得比较多,都有USB与并口两种接口,因为通过USB控制需要单独协议,对电路的外围设计与程序编写都麻烦许多,于是打算用并口。其实并口好像是专门为打印机而生的,爱普生的针式打印机还保留并口。

最后选用了爱普生的LQ-630II,查询资料,其使用的是ESC语言。

问题1:单片机如何与打印机通过并口连接起来?

答:打印机的并口线分为两端,一端连接打印机36针,一端连接PC或者单片机等控制端25针,这里作为控制端操作我们就只关心25针接口。

a212ee3d983d4c72623989701c33de29.png

25针控制端接线说明如下:

6a7dec9e74a49df649b14e79d49a9b40.png

PCB电路设计接线说明:

e366f519dabbc26d19dadf094fba7727.png

问题一总结:

1.25针接线并没有完全用到,

引脚18~25:8根引脚都是GND。

引脚1:STB,作为数据选通,也就是当STB从高电平变化为低电平时,数据引脚的数据才会被打印机读取,也就是告诉打印机数据已经准备完成,可以读取。

引脚14:FEED,自动进纸与否,控制端控制打印机状态。

引脚15:ERROR,打印机出错与否,控制端读取打印机状态。

引脚16:INIT,硬件上重启打印机,大于50us的低电平就将重启打印机,回到初始状态,比如清除打印机缓存区。

引脚11:BUSY,打印机忙标志位,高电平表示打印机正在处理数据,不能接收新的数据,直到变为低电平为止。

引脚10:ACK,我暂时没用到。

引脚2~9:共8位作为并口数据传输位,也就是一次传输8位数据(1byte)。

注意:

1.也就是说其实我们只需要 STB、BUSY、DATA 几组引脚就可以控制打印机了。

2.各个引脚上拉电阻不能少!

问题2:控制端的数据是如何到达打印机的?

答:

1.并口8根数据线赋值需要发送的数据,比如0x80。

2.判断BUSY引脚状态,是否空闲,若忙则等待。

3.空闲状态时,STB从低电平到高电平脉冲,告诉 打印机可以读取数据了。

4.打印机获取数据存于打印缓冲区,遇到换行或者回车数据,或者缓存区满则自动打印数据。

问题3:一个8位数据如何发送给打印机?

答:

1.其实就是前面问题2的解读过程,具体代码我在测试阶段使用了死循环while来等待BUSY空闲,这样保证数据不丢失,每个字节都要等待打印机接收到。

void printByte(unsigned char ch)

{

while(P_BUSY);

P_DATA = ch;

printDelay(500);

P_STB = 0;

printDelay(1000);//延时保证 STB > 1um

P_STB = 1;

printDelay(1000);

}

2.其实很明显,上面的死循环在操作系统使用多线程还可以,如果是纯单片机那就是完全不能用的,所以后来改进了一下,采用轮训方式,发送成功返回1下次发送下一个数据,失败返回0并且下次继续发送该数据。

unsigned char printByte(unsigned char ch)

{

if(0 == P_BUSY)

{

P_DATA = ch;

printDelay(500);

P_STB = 0;

printDelay(1000);//延时保证 STB > 1um

P_STB = 1;

printDelay(1000);

return 1;

}

return 0;

}

问题4:一次发送多个数据是如何操作的?需要注意些什么?

答:

1.首先是前面提到的数据到达打印机过程,也就是先解决了发送一个字节数据的问题(见问题3过程)。

2.其实多个字节发送的实质也是一个个字节发送的,第一个字节发送完成,判断忙状态,空闲则继续发送下一个字节。

3.为了保证每一个数据都到达打印机,不存在控制端发送了,不管打印机是否正确接收。我想的方法是:用一个本地BUF将我这次需要发送的N个字节数据一次存入其中,给一个从0开始的BUF下标计数值,采用轮训去发送该BUF,每次发送成功则下标加1,即发送下一个数据,否则下标保持不变,继续发送该数据。

#define _PRINT_BUF_NUM_ 250

unsigned int Print_Sign = 0;

unsigned char Print_Buf[_PRINT_BUF_NUM_]; //

//将指定一字节数据存入Print_Buf中,其存入数据个数与下标对应

void PrintDataToBuf(unsigned int *dataAddr, unsigned char byte)

{

if((*dataAddr) < _PRINT_BUF_NUM_)

Print_Buf[(*dataAddr)++] = byte;

}

//将指定字符串存入Print_Buf中,注意不能包含0x00,字符串会自动切断

void PrintDataToBufs(unsigned int *dataAddr, unsigned char mydata[])

{

unsigned int i = 0;

for(i = 0;i < strlen(mydata);i++)

{

if((*dataAddr) < _PRINT_BUF_NUM_)

{

Print_Buf[(*dataAddr)++] = mydata[i];

}

}

}

问题5:这两个函数怎么使用的?

答:

1.主函数中对命令等数据操作都是一个一个存入BUF中的,而对于字符串则使用第二个函数一次存入。

#define _GJJLBB_ "打印测试内容\r\n"

Print_Sign = 0;//每次存入前复位下标,表示从0开始

//设置左边界

PrintDataToBuf(&Print_Sign, 0x1B);

PrintDataToBuf(&Print_Sign, 0x6C);

PrintDataToBuf(&Print_Sign, 0x01);

//设置下划线

PrintDataToBuf(&Print_Sign, 0x1C);

PrintDataToBuf(&Print_Sign, 0x2D);

PrintDataToBuf(&Print_Sign, 1);

PrintDataToBufs(&Print_Sign, _GJJLBB_); //真实打印数据

//取消下划线

PrintDataToBuf(&Print_Sign, 0x1C);

PrintDataToBuf(&Print_Sign, 0x2D);

PrintDataToBuf(&Print_Sign, 0);

PrintDataToBufs(&Print_Sign, "\r\n"); //打印机遇到回车换行才回去马上打印出来

RowDataCombinationOK = 1;//本次数据组合完成,需要开始打印标志

2.到这里有没有发现,我本次需要打印的数据都存在Print_Buf中,从下标0开始,一共存入了多少数据呢?其实就是Print_Sign的值,因为传入的指针,所以每次存数据后其值也会对应改变。

问题6:数据已经存入BUF中,个数也已经知道,如何轮训发送给打印机呢?

答:

1.关键步骤如下,具体在哪里轮训需要根据你自己的程序需求。

//PrintDataReadAddr 是从0 开始的读取BUF数据的下标地址

//Print_Sign代表本次BUF中一个有多少数据

if(PrintDataReadAddr < Print_Sign)

{

//BUF中读取数据下标地址与其当前读取成功的个数相等,也就是读取地址==打印机获取个数,则代表读取后已经写入打印机,下次可以读取下一个数据。

if(PrintWriteNum == PrintDataReadAddr)

{

PrintWriteNum++;

readPrintBufData = Print_Buf[PrintDataReadAddr];

}

//将读取值发送给打印机,成功才累加读取地址

if(printByte(readPrintBufData))

{

PrintDataReadAddr++;

}

}

//本次一行数据写入完成

else

{

PrintRowOK = 1; //该标志位用于允许新的数据写入BUF中,本次读取完全才能重新写入新的数据,从0地址开始。

}

问题7:上位机有很多数据需要发送给打印机打印,怎能操作呢?

答:

1.打印机是接收到一行数据(若该行数据中包含回车换行则自动立即打印),否则需要等待打印机的缓存区满才自动打印。

2.LQ-630II打印机缓存区 32K。

3.为了保证打印机每次完整打印一行数据后再去打印下一行,我们使用的是应答方式,也就是下位机作为直接驱动打印机的控制端,在打印机完成一行打印后主动请求下一行数据,上位机收到新的数据请求后将数据发送给下位机。这中间最重要的是通讯协议中需要定义行标志,上下统一,从而保证请求与接收数据的唯一性。

总结:下位机需要打印第一行,则向上位机发送1,上位机收到1则将第一行数据按照特定格式与编号1一起发送给下位机,下位机收到1与自己请求编号1相同,则获取该消息后的数据包,解析数据,打印出来。接着将请求编号设置为2,去请求第二行数据,依次类推。

目前已经完成所有打印需求,文档更新不够详细,很多具体细节有需要的可以留言讨论。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值