热敏打印机工作原理

1、前言

本文章主要讲述热敏打印机的基本工作原理,涉及到更流畅的逻辑功能本文不展示,但可以简单的教明白你热敏打印机的工作流程,完成类似毕业设计,学习科目的小项目算是卓卓有余;写这篇文章主要原因也是因为网上关于热敏打印机的文章,少之又少,工作中如果项目涉及到,又没有开发经验的话,希望这篇文章可以帮助到你。

2、热敏打印机的优势

       打印均匀、运行平稳;机芯具有体积小, 工作电压宽、打印速度快、工作电源宽、打印精度高、寿命长、低耗电、噪音低,独特的立式机构设计,使得机芯具有易装纸,高可靠性等特点,且大大节约了产品空间高效等特点。

3、打印机特性(摘重点)

1、有效打印宽度(毫米):48

2、点密度(点/毫米):8

3、打印点数:384 点/行(市面上还有576 点/行,工作原理一样,只是加热脚多了)

4、打印机工作电压:3.13~8.5V(重要,会影响打印浓度和走纸马达),开机上电,同时给马达和加热,瞬间电流可能有3A以上,需要注意!!!

5、支撑板最大温度:65°C

4、打印机——步进电机

步进电机是一种将电脉冲信号转换成相应角位移或相位移的电动机。每输入一个脉冲信号,转子就转动一个角度或前进一步,其输出的角位移或相位移与输入的脉冲数成正比,转速与脉冲频率成正比。因此,步进电动机又称脉冲电动机。

4.1、驱动方式

步进电机相信很多人在开发项目中都有使用过,热敏打印机的步进电机一般采用“1-2相”或“2-2相”的驱动方式。

4.2、步进电机驱动芯片

打印机的步进电机需要步进电机驱动芯片来驱动马达,我使用的驱动芯片是HR8833,比较常见的一款驱动芯片;HR8833驱动芯片有个特性,芯片需要一个限流电阻(重要!),电阻越大,电流越小,反之,越大;电流越大,马达的走纸的声音就越大,发热也越快;我们要控制好走纸马达的噪声和发热,就绪要我们去将电阻调到一个合理的数值,但是不能太小,电阻太大,电流太小,走纸力度就越小;驱动芯片的限流模式是,加大电阻之后,想达到限流的效果,它是通过PWM的方式实现的,就是电阻越大,PWM的占空比就越小,反之,越大;

波形图:

 

 

4.3、时序图

1-2相:半步

2-2相:全步

4.4、使能驱动

只要主控给出驱动芯片需要的高低电平,驱动芯片就会输出相应的电平给到打印机机芯,就可以转动马达走纸。

4.5、走纸幅度

打印机走一点行需要走的相位。

1-2相的驱动方式走8个相位马达才会转动一圈,但走一点行只需走4个相位。

2-2相的驱动方式走4个相位马达才会转动一圈,但走一点行只需走2个相位。

 4.6、驱动程序

1-2相

void TestMotor(int i)
{
  while(i--)
  {
			PRINTER_MOTOR_A1_ON;     //1
			PRINTER_MOTOR_A2_ON;
			PRINTER_MOTOR_B1_ON;
			PRINTER_MOTOR_B2_OFF;
			udelay(400);
			
			PRINTER_MOTOR_A1_ON;     //2
			PRINTER_MOTOR_A2_OFF;
			PRINTER_MOTOR_B1_ON;
			PRINTER_MOTOR_B2_ON;
			udelay(400);

			PRINTER_MOTOR_A1_ON;     //3
			PRINTER_MOTOR_A2_OFF;
			PRINTER_MOTOR_B1_ON;
			PRINTER_MOTOR_B2_ON;
			udelay(400);

			PRINTER_MOTOR_A1_ON;     //4
			PRINTER_MOTOR_A2_OFF;
			PRINTER_MOTOR_B1_OFF;
			PRINTER_MOTOR_B2_ON;
			udelay(400);
			
			PRINTER_MOTOR_A1_ON;     //5
			PRINTER_MOTOR_A2_ON;
			PRINTER_MOTOR_B1_OFF;
			PRINTER_MOTOR_B2_ON;
			udelay(400);
			
			PRINTER_MOTOR_A1_OFF;     //6
			PRINTER_MOTOR_A2_ON;
			PRINTER_MOTOR_B1_OFF;
			PRINTER_MOTOR_B2_ON;
			udelay(400);
			
			PRINTER_MOTOR_A1_OFF;     //7
			PRINTER_MOTOR_A2_ON;
			PRINTER_MOTOR_B1_ON;
			PRINTER_MOTOR_B2_ON;
			udelay(400);
			
			PRINTER_MOTOR_A1_OFF;     //8
			PRINTER_MOTOR_A2_ON;
			PRINTER_MOTOR_B1_ON;
			PRINTER_MOTOR_B2_OFF;
			udelay(400);
	}
}

2-2相

void FirstFeed(int i)
{
	while(i--)
  {
			PRINTER_MOTOR_A1_ON;     //1
			PRINTER_MOTOR_A2_OFF;
			PRINTER_MOTOR_B1_ON;
			PRINTER_MOTOR_B2_OFF;
			udelay(1000);
			
			PRINTER_MOTOR_A1_ON;     //2
			PRINTER_MOTOR_A2_OFF;
			PRINTER_MOTOR_B1_OFF;
			PRINTER_MOTOR_B2_ON;
			udelay(1000);

			PRINTER_MOTOR_A1_OFF;     //3
			PRINTER_MOTOR_A2_ON;
			PRINTER_MOTOR_B1_OFF;
			PRINTER_MOTOR_B2_ON;
			udelay(1000);

			PRINTER_MOTOR_A1_OFF;     //4
			PRINTER_MOTOR_A2_ON;
			PRINTER_MOTOR_B1_ON;
			PRINTER_MOTOR_B2_OFF;
			udelay(1000);
	}
}

5、打印机——通信 

 5.1、SPI介绍

       打印机采用SPI通信,相信大家对SPI通信再熟悉不过了;SPI接口共有4根信号线,分别是:设备选择线、时钟线、串行输出数据线、串行输入数据线。

 

(1)MOSI:主器件数据输出,从器件数据输入
(2)MISO:主器件数据输入,从器件数据输出
(3)SCLK:时钟信号,由主器件产生
(4)/SS:从器件使能信号,由主器件控制

5.2、优缺点

优点:
     1)  支持全双工操作;
     2)  操作简单;
     3)  数据传输速率较高。
缺点:
     1)  需要占用主机较多的口线(每个从机都需要一根片选线);
     2)  只支持单个主机。     
     3) 没有指定的流控制,没有应答机制确认是否接收到数据。

5.3、SPI通信的四种模式

       SPI的四种模式,简单地讲就是设置SCLK时钟信号线的那种信号为有效信号

       SPI通信有4种不同的操作模式,不同的从设备可能在出厂是就是配置为某种模式,这是不能改变的;但我们的通信双方必须是工作在同一模式下,所以我们可以对我们的主设备的SPI模式进行配置,通过CPOL(时钟极性)和CPHA(时钟相位)来
控制我们主设备的通信模式,具体如下:

时钟极性(CPOL)定义了时钟空闲状态电平:

CPOL=0,表示当SCLK=0时处于空闲态,所以有效状态就是SCLK处于高电平时
CPOL=1,表示当SCLK=1时处于空闲态,所以有效状态就是SCLK处于低电平时

时钟相位(CPHA)定义数据的采集时间。

CPHA=0,在时钟的第一个跳变沿(上升沿或下降沿)进行数据采样。,在第2个边沿发送数据
CPHA=1,在时钟的第二个跳变沿(上升沿或下降沿)进行数据采样。,在第1个边沿发送数据

例:

Mode0:CPOL=0,CPHA=0:此时空闲态时,SCLK处于低电平,数据采样是在第1个边沿,也就是SCLK由低电平到高电平的跳变,所以数据采样是在上升沿(准备数据),(发送数据)数据发送是在下降沿。

Mode1:CPOL=0,CPHA=1:此时空闲态时,SCLK处于低电平,数据发送是在第1个边沿,也就是SCLK由低电平到高电平的跳变,所以数据采样是在下降沿,数据发送是在上升沿。

Mode2:CPOL=1,CPHA=0:此时空闲态时,SCLK处于高电平,数据采集是在第1个边沿,也就是SCLK由高电平到低电平的跳变,所以数据采集是在下降沿,数据发送是在上升沿。

Mode3:CPOL=1,CPHA=1:此时空闲态时,SCLK处于高电平,数据发送是在第1个边沿,也就是SCLK由高电平到低电平的跳变,所以数据采集是在上升沿,数据发送是在下降沿。


5.4、时序图分析

 CLK低电平时空闲,CLK下降沿采集数据。

 5.5、程序

程序就不放了,每个芯片的SPI的通信都会有点差别,不过都是大同小异,具体用什么芯片就找对应芯片的参考案列即可。打印机只负责接收,不负责发送,你只需要把你需要打印的数据发送过去就好了。

6、打印机——数据锁存

LATCH:锁存脚,数据发送到打印机,我们需要将数据锁住,然后再进行加热。

空闲的时候,我们把锁存脚置高,当你发送完数据之后,就把锁存脚拉低,延时1us之后,拉高即刻锁存数据;延时的时间其实也不需要1us,最短时间规格书有明确写,如下:

 延时时间100ns即可,但是延时长一点也无所谓的。

7、打印机——加热

加热其实就是一个管脚给出高低电平即可,加热把GPIO拉高,加一定的延时,一般不要太长,不过需要看你的电压,电压越高,加热时间尽量越短,加热完把GPIO管脚拉低;加热的浓度需要看你的需要,加热太长时间,会出现拖影,打印效果不佳!(特别注意加热过度,会烧坏加热值和加热板,延时时间一定要控制好)

8、整体思路流程

while(1)
{
    1、发送数据
    2、锁存数据
    3、加热数据
    4、转动走纸马达,走一点行
}

 9、附简单测试代码

9.1、主程序

	while(1)
	{
		if(!PRINTER_GPIO_KEY_READ)          //按按键出发
		{
			mdelay(50);
			if(!PRINTER_GPIO_KEY_READ)
				{
					PRINTER_POWER_ON;       //打开打印机电源
					mdelay(1000);           //适当延时
				    TestPrinterGoOn();
					PRINTER_POWER_OFF;      //关闭打印机电源
				}
		}
	}	

9.2、打印测试函数

u8 const MOTOR_CTRL_BYTE_TABLE_2_2[5][4] =
{
	{1,0,1,0},
	{1,0,0,1},
	{0,1,0,1},
	{0,1,1,0},
	{0,0,0,0},
};

#define PRN_MOT_OUT_2_2(x)      do{if(MOTOR_CTRL_BYTE_TABLE_2_2[x][0])GPIO_SetBits(GPIOC,     
         GPIO_Pin_6);else GPIO_ResetBits(GPIOC, GPIO_Pin_6);\																 
         if(MOTOR_CTRL_BYTE_TABLE_2_2[x][1])GPIO_SetBits(GPIOC, GPIO_Pin_7);else 
         GPIO_ResetBits(GPIOC, GPIO_Pin_7);\															 
         if(MOTOR_CTRL_BYTE_TABLE_2_2[x][2])GPIO_SetBits(GPIOC, GPIO_Pin_8);else 
         GPIO_ResetBits(GPIOC, GPIO_Pin_8);\																 
         if(MOTOR_CTRL_BYTE_TABLE_2_2[x][3])GPIO_SetBits(GPIOC, GPIO_Pin_9);else 
         GPIO_ResetBits(GPIOC, GPIO_Pin_9);\}while(0)              //转动马达 直接写寄存器

static const char *mystr[]={
    "     VERY GOOD BOY                             ",
    "VB B B B B B B B B B B B B B B B B B B B B B B ",
    "M C C C C C C C C C C C C C C C C C C C C C C C",
    "U D D D D D D D D D D D D D D D D D D D D D D D",
    "TE E E E E E E E E E E E E E E E E E E E E E E ",
    "GFF  FF  FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
    "MGG GGGGG GGGGGG XGGGGG ZGGGGG YGGGGG WGGG GGGG",
};

static int extract_32X32(uint8_t *str,uint8_t *otmep,uint8_t *outbuf,int *olen)
{
    uint8_t  *ptr = str;
    uint8_t  *cp = str;
    uint8_t ch;
    int k = 0;
    for (int j = 0; j < PRINTER_LINE_LEN; j++) 
	  {  				//一行有多少个字符	 
        ptr = str + k;   				//一行中的第几个字  
        if (*ptr < 0x80) { //英文
            if (*ptr < 0x21) 
						{
                j++;      //一个字节占两个字节
                k++;
                //continue;
            } 
						else 
						{					
                cp = (uint8_t *)&ASCII16x32[((*ptr) - 0x21) * 64];
                memcpy(otmep, cp,64);
                for(int i = 0; i < 32; i++) 
							  {
                    memcpy(&outbuf[i*PRINTER_LINE_LEN+ j],&otmep[i * 2], 2);						
                }
                j++;
                k++;
            } 
            
        }
    }
}

void TestPrinterGoOn(void)
{
        static int pos = 0;         //解析字符数据行数
        int i = 0; 
        int nlines = 32;
        u32 g_motor_phase = 0;
		uint8_t *bux = malloc(48 * 48);
		uint8_t *tmx = malloc(48 * 48);
		int strlen = sizeof(mystr)/sizeof(mystr[0]);
		memset(bux,0,48 * 48);
		memset(tmx,0,48 * 48);
	    FirstFeed(20);
		while(pos < 7)
		{
            //mystr数组有七行,将每一行字符分解为32行的数据放到bux里面。
			extract_32X32((uint8_t *)mystr[pos%strlen],tmx,bux,NULL);
            mdelay(10); 
			while(nlines)
			{
				PRN_MOT_OUT_2_2(g_motor_phase);
				udelay(400);                            //换一次相需要停一下,太快
		        g_motor_phase = (g_motor_phase + 1) & 0x03;
				if ((g_motor_phase % 2) == 0)           //走两个相就发一次数据
				{
					prtdrv_hspi_write(bux + i,48);		//一行发送48个数据
					PRN_LATCH_PLUS;
					PRINTER_STB_ON;
					udelay(1500);
					PRINTER_STB_OFF;
					i += 48;
					nlines--;             //发送一次减一行,总共32行
				}
			}
			TestMotor(5);
			pos++;
			nlines = 32;
			i = 0;
		}
		TestMotor(100);
		pos = 0;
		printf("print end\r\n");
}

9.3、

ASCII16x32这个字符库的头文件我扔到网盘上,调试的话自行去下载:
链接:https://pan.baidu.com/s/1qjDiM7MXQDMW9aK3vjVUFA 
提取码:i038 

10、总结

      热敏打印机其实玩起来也是蛮有意思的,有兴趣的可以自己买一个开发玩玩,也不是很难,市面很多设备都有应用到打印机,最多的就是付款的时候用到,都是用这种热敏打印机;做毕业的话用热敏打印机杠杠的完爆身边同学的流水灯。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值