热敏打印机找不到驱动(热敏打印机驱动)
热敏打印机找不到驱动(热敏打印机驱动)typedef struct _Printer_Work_t { uint8_t work; //打印机是否开始工作, 系统上电 uint32_t step; //步进电机 电机停止后,从0开始 uint32_t speed; //电机当前速度 } Printer_Work_t; Printer_Work_t prt_work; //printer data buffer, 参数我的文章circle buffer的实现 CBuff_t prt_buff; //初始化 int Printer_Init(void) { static uint8_t buff[24000]; CBuff_Init(&prt_buff buff sizeof(buff)); //硬件初始化 Printer_HwInit();
热敏打印机是一个电子机械单元,一般用于打印小票。从编程的角度看,它主要有两个电控单元,步进电机和热打印头。
步进电机:是用来拖动打印纸走动的,一般我们用步进电机的H桥的驱动即可。 热打印头:热打印头上是很多并排成一条线的加热点,当通电时,该加热点发热,从而使热敏纸显示出颜色。电子驱动部如下图所示:
操作流程是: 通过数据口写入数据 -> 锁存数据 -> STROBE控制为高 ->延迟一段时间 -> STROBE控制为低。 这里的延迟时间就是加热时间。
热敏打印机驱动的要点:
- 打印要流畅,速度快,不卡顿,噪音小;
- 打出的字颜色要均匀,字体要匀称;
- 要有保护措施:缺纸检测,不会出现长时间对一个点的加热,对供电要求低。
难点
一. 防止加热电流过大 由于一行的加热点通常有三四百个,为了打印速度快,每个点的电流都较大,如果这一行的点都要打印加热,会导致电流会很大,所以策略是一行的点要分批次加热打印,函数如下:
/*
brief: 函数功能:data_buff为要打印的数据,从中可以顺序取出打印的数据,并统计出数据中累计bit ‘1’的个数,即是加热的点数,当点数累计到一定数量后,即停止取出数据,这些数据则为本次可以加热打印的数据。
return: 打印数据的个数
pdot_num 打印数据的总点数;
*/
int Printer_GetData(uint8_t *data_buff int buff_len uint32_t *pdot_num) {
int len;
int dot_num;
//0 ~ 255 每个数据中 ‘1’ 的个数,如 0x03 中有2个‘1’
const unsigned char bit_num_table[256] ={
0 1 1 2 1 2 2 3 1 2 2 3 2 3 3 4 1 2 2 3 2 3 3 4 2 3 3 4 3 4 4 5
1 2 2 3 2 3 3 4 2 3 3 4 3 4 4 5 2 3 3 4 3 4 4 5 3 4 4 5 4 5 5 6
1 2 2 3 2 3 3 4 2 3 3 4 3 4 4 5 2 3 3 4 3 4 4 5 3 4 4 5 4 5 5 6
2 3 3 4 3 4 4 5 3 4 4 5 4 5 5 6 3 4 4 5 4 5 5 6 4 5 5 6 5 6 6 7
1 2 2 3 2 3 3 4 2 3 3 4 3 4 4 5 2 3 3 4 3 4 4 5 3 4 4 5 4 5 5 6
2 3 3 4 3 4 4 5 3 4 4 5 4 5 5 6 3 4 4 5 4 5 5 6 4 5 5 6 5 6 6 7
2 3 3 4 3 4 4 5 3 4 4 5 4 5 5 6 3 4 4 5 4 5 5 6 4 5 5 6 5 6 6 7
3 4 4 5 4 5 5 6 4 5 5 6 5 6 6 7 4 5 5 6 5 6 6 7 5 6 6 7 6 7 7 8
};
len = 0;
dot_num = 0;
while(dot_num < PRT_HEAT_MAX_POINT){
dot_num = bit_num_table[data_buff[len]];
len ;
if(len >= buff_len){
break;
}
}
*pdot_num = dot_num;
return len;
}
二. 马达的速度控制 为了加快打印速度,我们都希望马达以最高的速度运转,但是由于惯性原因,如果一上来就是最大的速度,这会导致步进马达失步,从而影响打印效果,所以控制马达需要有一个加速的过程。
//马达加速表
//由于惯性原因,马达一上来,不可能就达到最大速度,需要一个加速过程
//加速表由打印机厂商提供
const uint32_t add_speed_table[] = {
4300 2600 2500 2420 2270 2140 2030 1940
1860 1780 1720 1660 1610 1560 1510 1470
1439 1402 1372 1342 1313 1287 1261 1238
1213 1194 1174 1155 1136 1119 1102 1086
1071 1056 1042 1029 1012 1003 991 979
968 957 947 936 927 917 908
};
//para: speed 当前马达速度,
//return: 返回下一步马达的速度
uint32_t Printer_MotorSpeed(uint32_t speed) {
uint32_t next_speed;
uint32_t max_speed;
int i;
next_speed = add_speed_table[0];
//最小速度
if((speed == 0) || (speed > add_speed_table[0])){
next_speed = add_speed_table[0];
goto Label;
}
//最大速度
max_speed = add_speed_table[sizeof(add_speed_table) / 4 - 1];
if(speed <= max_speed) {
next_speed = max_speed;
goto Label;
}
//表中查下一个速度
for(i = 0; i < sizeof(add_speed_table) / 4 - 1; i ) {
if((speed <= add_speed_table[i]) && (speed > add_speed_table[i 1])) {
next_speed = add_speed_table[i 1];
}
}
Label:
return next_speed;
}
整个程序控制流程:
typedef struct _Printer_Work_t {
uint8_t work; //打印机是否开始工作, 系统上电
uint32_t step; //步进电机 电机停止后,从0开始
uint32_t speed; //电机当前速度
} Printer_Work_t;
Printer_Work_t prt_work;
//printer data buffer, 参数我的文章circle buffer的实现
CBuff_t prt_buff;
//初始化
int Printer_Init(void) {
static uint8_t buff[24000];
CBuff_Init(&prt_buff buff sizeof(buff));
//硬件初始化
Printer_HwInit();
Printer_PowerOn(0);
Printer_Strobe(0);
Printer_MotorStop();
return 0;
}
int Printer_Task(void *arg) {
int ret;
uint8_t data_buff[PRT_LINE_BYTES_MAX];
static uint32_t s_time = 0;
int len;
uint32_t heat_time;
if(prt_work.work == 1) {
//一段时间没开始工作,断电, 停止工作
//由于需要打印的数据,是连续下发下来的
if(IS_TIME_OUT(s_time 1200)) {
//停止
CBuff_Clean(&prt_buff);
prt_work.work = 0;
Printer_PowerOn(0);
Printer_Strobe(0);
Printer_MotorStop();
prt_work.step = 0; //马达位置
prt_work.speed = 0; //马达速度为 0
}
}
//是否有数据
if(Printer_HasData() < 0){
return 0;
}
//收到数据,开始打印
if(prt_work.work == 0){
Printer_PowerOn(1); //开电源
Timer_DelayMs(50); //保证电源稳定下来
prt_work.work = 1;
}
//检测纸张
if(Printer_PaperDetect(0) == 0) {
CBuff_Clean(&prt_buff);
return -1;
}
s_time = Timer_Ticks();
//加热时间
heat_time = Printer_HeatTime(0 0);
while(Printer_HasData() > 0){
uint32_t point;
uint32_t dot_num;
uint32_t motor_start_time;
uint32_t heat_start_time;
uint8_t *pdata;
//读出一行数据
ret = CBuff_Read(&prt_buff data_buff PRT_LINE_BYTES_MAX);
if(ret != PRT_LINE_BYTES_MAX){
break;
}
//打印一行
point = 0;
Printer_Strobe(1);
while(point < PRT_LINE_BYTES_MAX){
//取数据
len = Printer_GetData(&data_buff[point] PRT_LINE_BYTES_MAX - point &dot_num);
if(len <= 0){
break;
}
//写数据
ret = Printer_WriteDot(point &data_buff[point] len);
if(ret < 0){
break;
}
point = len;
if(dot_num > 0) {
//有点,加热
Timer_DelayUs(heat_time);
}
}
//马达 4步一行点阵?
prt_work.speed = Printer_MotorSpeed(prt_work.speed heat_time);
prt_work.step = Printer_MotorStep(prt_work.step);
Timer_DelayUs(prt_work.speed);
prt_work.speed = Printer_MotorSpeed(prt_work.speed heat_time);
prt_work.step = Printer_MotorStep(prt_work.step);
Timer_DelayUs(prt_work.speed);
Printer_Strobe(0);
prt_work.speed = Printer_MotorSpeed(prt_work.speed heat_time);
prt_work.step = Printer_MotorStep(prt_work.step);
Timer_DelayUs(prt_work.speed);
prt_work.speed = Printer_MotorSpeed(prt_work.speed heat_time);
prt_work.step = Printer_MotorStep(prt_work.step);
Timer_DelayUs(prt_work.speed);
}
//Printer_PowerOn(0);
//prt_work.work = 0; //防止电源来回并关
Printer_Strobe(0); //停止加热
//Printer_MotorStop(); //马达停止
return 0;
}
以上的代码经过测试,可以基本满足要求。但由于马达步进时间与加热时间不是固定的,而我们的策略是边热,边打印,如何实现加热与马达步进之间的同步,是最大的问题,以上的代码虽然写成固定的,但在实际中的测试结果还能达到我们的要求。