在了解完热敏打印机的基础知识并成功将热敏打印机的步进电机驱动后,我们就可以开始考虑发送数据并打印了。
控制时序
我们首先再来回顾一下热敏打印机的控制时序及系统结构图。
从控制时序中可以看出,数据传输采用类似spi通讯的方式,经过384个CLK周期后,将一行384个点的数据移入移位寄存器中。之后需要拉低锁存端(LAT)一段时间,将移位寄存器中的数据锁存到锁存器中。之后通过置高STB一段时间进行控制选通加热。这样就完成了一行内容的打印。
总共有6个选通控制器,每个控制器控制64个点的加热,即每行总共384个点。按每个字符有8bit位计算,即每行需要48个字符。
代码
下面不多说,直接上代码。
具体ESP-IDF的SPI使用介绍可以参考之前写的ESP-IDF 外设SPI驱动
- 相关结构体及数据定义
spi_device_handle_t spi2_handle;
spi_transaction_t transaction_config;
uint8_t temp_tx[48]={0};\\spi发送缓存区
uint8_t temp_rx[48]={0};\\spi接收缓存区
- STB及LAT引脚初始化
void Heat_Gpio_Init(void)
{
//zero-initialize the config structure.
gpio_config_t io_conf = {};
//disable interrupt
io_conf.intr_type = GPIO_INTR_DISABLE;
//set as output mode
io_conf.mode = GPIO_MODE_OUTPUT;
//bit mask of the pins that you want to set,e.g.GPIO18/19
io_conf.pin_bit_mask = GPIO_STB_PIN_SEL;
//disable pull-down mode
io_conf.pull_down_en = 0;
//disable pull-up mode
io_conf.pull_up_en = 0;
//configure GPIO with the given settings
gpio_config(&io_conf);
io_conf.pin_bit_mask = GPIO_DATA_PIN_SEL;
gpio_config(&io_conf);
gpio_set_level(GPIO_STB1, 0);
gpio_set_level(GPIO_STB2, 0);
gpio_set_level(GPIO_STB3, 0);
gpio_set_level(GPIO_STB4, 0);
gpio_set_level(GPIO_STB5, 0);
gpio_set_level(GPIO_STB6, 0);
gpio_set_level(PIN_NUM_LAT, 1);
// gpio_set_level(PIN_NUM_SCLK, 0);
// gpio_set_level(PIN_NUM_DO, 0);
}
首先我们对STB脚及LAT脚进行初始化,配置为输出模式。并且STB脚需要全部拉低,LAT脚默认拉高。
- SPI初始化
void SPI_Init(void)
{
spi_bus_config_t buscfg={ //总线配置结构体
// .miso_io_num = -1, //gpio12->miso
.mosi_io_num = PIN_NUM_DO, //gpio13->mosi
.sclk_io_num = PIN_NUM_SCLK, //gpio14-> sclk
.flags = SPICOMMON_BUSFLAG_MASTER
};
spi_device_interface_config_t interface_config={ //设备配置结构体
.address_bits = 0,
.command_bits = 0,
.clock_speed_hz = 3 *1000 * 1000,
.mode = 0, //设置SPI通讯的相位特性和采样边沿。包括了mode0-3四种。要看从设备能够使用哪种模式
// interface_config.spics_io_num = 25; //配置片选线
.duty_cycle_pos = 0,
.queue_size = 6 //传输队列的长度,表示可以在通讯的时候挂起多少个spi通讯。在中断通讯模式的时候会把当前spi通讯进程挂起到队列中
};
ESP_ERROR_CHECK(spi_bus_initialize(PRINTER_HOST, &buscfg, SPI_DMA_CH_AUTO));
memset(&spi2_handle, 0, sizeof(spi2_handle)); //为数据结构体分配内存
ESP_ERROR_CHECK(spi_bus_add_device(PRINTER_HOST, &interface_config, &spi2_handle));
memset(&transaction_config, 0, sizeof(transaction_config)); //为数据结构体分配内存
transaction_config.length = 48 * 8; //要发送或者接收的数据的长度,不算前面的cmd/address/dummy的长度
transaction_config.tx_buffer =temp_tx; //发送没有指定内部空间,使用的是外部区域,因此要自己指定
transaction_config.rx_buffer = temp_rx; //接收定义了SPI_TRANS_USE_RXDATA,使用的是内部空间。
// transaction_config.flags = SPI_TRANS_USE_RXDATA;
}
由于我们并没有用到MISO和CS引脚,因此在SPI初始化的时候,我们不针对这两个引脚进行设置。并且在前文的分析中,我们知道每发送一行的数据,就是要发送48个字符大小的数据,因此我们将缓冲区的大小设置位48个字符,每次发送的数据位48*8个比特,及384个点的数据。
- 发送数据
void Printer_Send_Data(uint8_t *data, uint8_t len)
{
memcpy(temp_tx,data,len);
spi_device_acquire_bus(spi2_handle, portMAX_DELAY);
spi_device_polling_transmit(spi2_handle, &transaction_config);
spi_device_polling_start(spi2_handle, &transaction_config, portMAX_DELAY);
spi_device_polling_end(spi2_handle, portMAX_DELAY);
spi_device_release_bus(spi2_handle);
vTaskDelay(5 / portTICK_PERIOD_MS);
gpio_set_level(PIN_NUM_LAT, 0);
vTaskDelay(1 / portTICK_PERIOD_MS);
gpio_set_level(PIN_NUM_LAT, 1);
memset(temp_tx, 0, sizeof(temp_tx));
}
在初始化完SPI后,我们就能使用SPI发送数据了,我们这里采用的是spi_device_polling_transmit函数进行数据的发送。在384个比特的数据发送完成后,需要将LAT引脚拉低一段时间,将数据锁存到锁存器中。
- 加热控制
void Heat_Enable(uint8_t stb_num, uint16_t heat_time)
{
gpio_set_level(stb_num, 1);
vTaskDelay(heat_time / portTICK_PERIOD_MS);
gpio_set_level(stb_num, 0);
}
数据发送完成后,就能够通过拉高STB引脚进行加热了。这里stb_num指的是STB引脚序号,heat_time是加热的时间。
注意
- 加热时间不可过长,否则加热的点中心会发白,呈现出小圆圈状。
- STB在不用的时候需要拉低。一共有6个STB,若电源供电能力不足,可以依次单独拉高进行打印;若供电能力充足,可以几组一起进行打印。
详细代码可以参考我的GitHub:thermal_printer
Bilibili:通信电子小白
微信公众号:
下面是我创建的QQ群,欢迎大家进群交流呀!
QQ群:752236617