快速安装热敏打印机驱动:轻松实现打印无忧

admin 技术 2024-01-15 06:00 45

  热敏打印机是一个电子机械单元,一般用于打印小票。从编程的角度看,它主要有两个电控单元,步进电机和热打印头。

步进电机:是用来拖动打印纸走动的,一般我们用步进电机的H桥的驱动即可。 热打印头:热打印头上是很多并排成一条线的加热点,当通电时,该加热点发热,从而使热敏纸显示出颜色。电子驱动部如下图所示:

操作流程是: 通过数据口写入数据 -> 锁存数据 -> STROBE控制为高 ->延迟一段时间 -> STROBE控制为低。 这里的延迟时间就是加热时间。

热敏打印机驱动的要点:

  1. 打印要流畅,速度快,不卡顿,噪音小;
  2. 打出的字颜色要均匀,字体要匀称;
  3. 要有保护措施:缺纸检测,不会出现长时间对一个点的加热,对供电要求低。

难点

一. 防止加热电流过大   由于一行的加热点通常有三四百个,为了打印速度快,每个点的电流都较大,如果这一行的点都要打印加热,会导致电流会很大,所以策略是一行的点要分批次加热打印,函数如下:

/*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;}

以上的代码经过测试,可以基本满足要求。但由于马达步进时间与加热时间不是固定的,而我们的策略是边热,边打印,如何实现加热与马达步进之间的同步,是最大的问题,以上的代码虽然写成固定的,但在实际中的测试结果还能达到我们的要求。

相关推荐
关闭

用微信“扫一扫”