喵喵蓝牙热敏打印机(上)


基于嘉立创开源项目进行开发:点击直达

功能

1.能够模拟作业帮旗下喵喵机的通信协议,通过手机app喵喵机(V6.2.80)进行蓝牙连接打印
2.能够通过图片取模打印图片
3.打印机进行打印时,LED灯快闪提示用户。打印完LED灯1s闪一次,提示用户打印机进入待机状态。
4.能够进行缺纸检测,缺纸时会进行电机微动提示用户。
5.能够进行电量检测并将结果发送给app端,能进行打印头温度检测,过热时自动停止加热并闪灯+电机微动。
6.能够进行按键出纸,按下按键打印机能够自动出纸。


开发环境

VScode + PlatFromIO插件 + ESP32 Dev Module + Arduino 框架

简单说一下开发界面
在这里插入图片描述
注意:由于该打印机上电后,针头会一直加热,为防止针头烧坏,先在工程中加入以下代码初始化针头停止加热,最后在setup中调用。

//6个打印头
#define PIN_STB1 14  
#define PIN_STB2 27  
#define PIN_STB3 26  
#define PIN_STB4 25  
#define PIN_STB5 33  
#define PIN_STB6 32 
//打印头电源升压控制引脚
#define PIN_VHEN 17

void Pin_Stb_Low()
{
	pinMode(PIN_STB1, OUTPUT);
    pinMode(PIN_STB2, OUTPUT);
    pinMode(PIN_STB3, OUTPUT);
    pinMode(PIN_STB4, OUTPUT);
    pinMode(PIN_STB5, OUTPUT);
    pinMode(PIN_STB6, OUTPUT);
    digitalWrite(PIN_STB1, LOW);
    digitalWrite(PIN_STB2, LOW);
    digitalWrite(PIN_STB3, LOW);
    digitalWrite(PIN_STB4, LOW);
    digitalWrite(PIN_STB5, LOW);
    digitalWrite(PIN_STB6, LOW);
}

void Init_Print()
{
    Pin_Stb_Low();
     // 初始化打印电源控制引脚、并关闭电源
    pinMode(PIN_VHEN, OUTPUT);
    digitalWrite(PIN_VHEN, LOW);
}

一、按键控制LED灯

目标:通过按键控制LED灯四种状态的切换。
状态1:亮
状态2:灭
状态3:慢闪
状态4:快闪

1.按键、LED初始化

原理图:
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
电路分析:LED灯为引脚18控制,引脚18输出低电平时亮。按键由引脚5控制,检测到引脚5为低电平时,此时按键按下。
LED和按键的初始化步骤:

// 按键和 LED 的引脚编号
#define LED 18
#define BUTTON 5
#define LED_ON() digitalWrite(LED, LOW)
#define LED_OFF() digitalWrite(LED, HIGH)
// 初始化 LED 和按键
void Led_Config(void)
{
    // 配置 IO 口模式
    pinMode(BUTTON, INPUT);
    pinMode(LED, OUTPUT);
    // 关灯
    LED_OFF();
}

1.定义引脚18为LED,引脚5为BUTTON
2.定义LED_ON()为digitalWrite(LED, LOW),代表此时灯亮,定义LED_OFF()为digitalWrite(LED, HIGH),代表此时灯灭,方便后续操作。
3.配置引脚模式,引脚5连接按键(BUTTON),为了能够检测该引脚的高低电平,将该引脚配置为输入模式。引脚18连接LED灯,为了能够输出高电平控制LED灯的亮灭,将该引脚配置为输出模式。
4.为了保证代码的严谨性,配置完LED后随即将其关掉。
注意:单独写文件时,记得包含#include "Arduino.h"头文件。

2.按键控制LED灯状态

先写一个LED灯的闪烁

//闪烁
void LED_quick(int a)
{
    LED_ON();
    vTaskDelay(a);
    LED_OFF();
    vTaskDelay(a);   
}

该函数通过改变a的值来改变LED灯的闪烁状态(快闪、慢闪)。
使用vTaskDelay主要是为了方便后续使用FreeRTOS整合该项目。

四种状态Switch转换:

/*
    状态0:灯灭
    状态1:灯亮
    状态2:待机慢烁
    状态3:打印快闪
*/
void Led_Status(int a)
{
    switch (a)
    {
    case 0:
        LED_OFF();
        break;
    case 1:
        LED_ON();
        break;
    case 2:
        LED_quick(1000);
        break;
    case 3:
        LED_quick(50);
        break;
    }
}

最后加上一个按键控制,逻辑整合一下就可以实现了。

#include <Arduino.h>
#include "LED.h"
int a;
void setup()
{
  Init_Print();
  Led_Config();
  int a=0;
}
void loop()
{
  if(digitalRead(BUTTON)==0){
    delay(10);
    if(digitalRead(BUTTON)==0){
      a++;
      a%=4;
    }
  }
  Led_Status(a);
}

二、步进电机控制

步进电机规格参数:
在这里插入图片描述
驱动方式:
在这里插入图片描述
驱动时序
在这里插入图片描述

原理图:
在这里插入图片描述
在这里插入图片描述
通过步进电机的说明手册,我们可以得知该步进电机的驱动方式。
其中,比较关键的就是该步进电机的驱动时序,只要按照驱动时序来控制引脚输出高地电平,我们就能驱动该电机。
该电机由TC1508S芯片作为ESP32和 步进电机之间的桥梁进行控制。
引脚输出对应如下:

ESP32TC1508S步进电机
IO23IN1M_A+(A)
IO22IN2M_A-(Ā)
IO21IN3M_B+(B)
IO19IN4M_B-(B̄)

1.电机初始化

由上可知,初始化电机时需配置IN1-IN4四个引脚为输出模式,然后将四个引脚配置为低电平。

// 定义步进电机引脚
#define PIN_MOTOR_AP    23        //M_A+   IN1
#define PIN_MOTOR_AM    22        //M_A-   IN2
#define PIN_MOTOR_BP    21        //M_B+   IN3
#define PIN_MOTOR_BM    19        //M_B-   IN4

void init_motor()
{
    pinMode(PIN_MOTOR_AP, OUTPUT);
    pinMode(PIN_MOTOR_AM, OUTPUT);
    pinMode(PIN_MOTOR_BP, OUTPUT);
    pinMode(PIN_MOTOR_BM, OUTPUT);

    digitalWrite(PIN_MOTOR_AP, 0);
    digitalWrite(PIN_MOTOR_AM, 0);
    digitalWrite(PIN_MOTOR_BP, 0);
    digitalWrite(PIN_MOTOR_BM, 0);
}

2.电机驱动

只需按照时序图控制四个引脚的高低电平输出即可:

//运行8步
void motor_run8(){
    digitalWrite(PIN_MOTOR_AM, 1);
    digitalWrite(PIN_MOTOR_BM, 0);
    digitalWrite(PIN_MOTOR_AP, 0);
    digitalWrite(PIN_MOTOR_BP, 1);
    delay(2); 
    digitalWrite(PIN_MOTOR_AM, 0);
    digitalWrite(PIN_MOTOR_BM, 0);
    digitalWrite(PIN_MOTOR_AP, 0);
    digitalWrite(PIN_MOTOR_BP, 1);
    delay(2);  
    digitalWrite(PIN_MOTOR_AM, 0);
    digitalWrite(PIN_MOTOR_BM, 0);
    digitalWrite(PIN_MOTOR_AP, 1);
    digitalWrite(PIN_MOTOR_BP, 1);
    delay(2);  
    digitalWrite(PIN_MOTOR_AM, 0);
    digitalWrite(PIN_MOTOR_BM, 0);
    digitalWrite(PIN_MOTOR_AP, 1);
    digitalWrite(PIN_MOTOR_BP, 0);
    delay(2);  
    digitalWrite(PIN_MOTOR_AM, 0);
    digitalWrite(PIN_MOTOR_BM, 1);
    digitalWrite(PIN_MOTOR_AP, 1);
    digitalWrite(PIN_MOTOR_BP, 0);
    delay(2); 
    digitalWrite(PIN_MOTOR_AM, 0);
    digitalWrite(PIN_MOTOR_BM, 1);
    digitalWrite(PIN_MOTOR_AP, 0);
    digitalWrite(PIN_MOTOR_BP, 0);
    delay(2); 
    digitalWrite(PIN_MOTOR_AM, 1);
    digitalWrite(PIN_MOTOR_BM, 1);
    digitalWrite(PIN_MOTOR_AP, 0);
    digitalWrite(PIN_MOTOR_BP, 0);
    delay(2);
    digitalWrite(PIN_MOTOR_AM, 1);
    digitalWrite(PIN_MOTOR_BM, 0);
    digitalWrite(PIN_MOTOR_AP, 0);
    digitalWrite(PIN_MOTOR_BP, 0);
    delay(2);  
}

以上是该电机转动一个周期(8步)的示例。
每步中间的延时决定了每个步进的时间间隔,从而影响电机的步进频率。
delay(2) 表示每个步骤之间的间隔是 2 毫秒。这相当于 500 Hz 的频率(因为 1 / 0.002 = 500)。通过调整这个延时,你可以控制电机的转速。

学明白了以上代码和原理我们就可以优化代码并写点花的。
将电机的时序放在数组里

 //步进电机节拍
uint8_t motor_table[8][4] = { //JX 系列
 {1, 0, 0, 0},
 {1, 0, 1, 0},
 {0, 0, 1, 0},
 {0, 1, 1, 0},
 {0, 1, 0, 0},
 {0, 1, 0, 1},
 {0, 0, 0, 1},
 {1, 0, 0, 1}
};

走一个周期

void motor_run()
{
    digitalWrite(PIN_MOTOR_AP, motor_table[motor_pos][0]);
    digitalWrite(PIN_MOTOR_AM, motor_table[motor_pos][1]);
    digitalWrite(PIN_MOTOR_BP, motor_table[motor_pos][2]);
    digitalWrite(PIN_MOTOR_BM, motor_table[motor_pos][3]);
    motor_pos++;
    if (motor_pos >= 8)
    {
        motor_pos = 0;
    }
}

按指定步数走

//指定步数运行
void motor_run_step(uint32_t steps)
{
    while (steps)
    {
        digitalWrite(PIN_MOTOR_AP, motor_table[motor_pos][0]);
        digitalWrite(PIN_MOTOR_AM, motor_table[motor_pos][1]);
        digitalWrite(PIN_MOTOR_BP, motor_table[motor_pos][2]);
        digitalWrite(PIN_MOTOR_BM, motor_table[motor_pos][3]);
        motor_pos++;
        if (motor_pos >= 8)
        {
            motor_pos = 0;
        }
        delay(2);
        steps--;
    }
}

3.按键走纸

按键走纸实际上就是按下按键,步进电机开始转动,如下所示:

//按键走纸
void ButtonRun(){
  if(digitalRead(BUTTON)==0){
    delay(10);
    if(digitalRead(BUTTON)==0){
     motor_run_step(4);
    }
  }
}

三、图片取模打印图片

打印头原理
在这里插入图片描述
在这里插入图片描述
时序:
在这里插入图片描述
在这里插入图片描述

1.打印头初始化

由上图可知,该打印模块是由6个加热针头控制的。
每个针头控制8位,相当于每行传输48个数据,共384位。
数据的获取是靠SPI传输的,PIN_SCK(CLK )作为SPI 时钟线,PIN_SDA(DI)作为数据传输。因为是打印且仅有一个打印模块所以主机输入和片选线均无。

打印流程
1.VH电源置为高电平。
2.SPI传输需要打印的数据。
3.LAT从低拉高1us锁存数据。
4.STB1~6开始按照数据逐个开启加热,加热时间越长,打印颜色越深。
5.加热完成后,就相当于打印了 一行,此时控制电机移动4步(该硬件设置的是移动4步相当于打印行高)。
6. 之后就是重复上面的打印步骤,重新开始下一行的SPI数据传输,锁存器锁存打印,直到所有数据打印完毕。

初始化spi

#include <myspi.h>
#include <spi.h>
#define PIN_SCK 15
#define PIN_SDA 13

SPIClass printerSPI = SPIClass(HSPI)
SPISettings print_SPI_Set = SPISettings(1000000, SPI_MSBFIRST, SPI_MODE0);
void init_spi()
{
    myspi.begin(PIN_SCK, -1, PIN_SDA, -1);
    myspi.setFrequency(2000000);
}

1.选总线,此处配置的为HSPI总线。
在 ESP32 上,HSPI 和 VSPI 是两个硬件 SPI 总线接口。每个总线接口都有不同的默认引脚:
HSPI(High-Speed SPI):通常使用 GPIO 14 (SCK), GPIO 12 (MISO), GPIO 13 (MOSI), 和 GPIO 15 (SS)。
VSPI(Very-Speed SPI):通常使用 GPIO 18 (SCK), GPIO 19 (MISO), GPIO 23 (MOSI), 和 GPIO 5 (SS)。
2.配SPI
创建一个 SPISettings 对象 print_SPI_Set,用于设置 SPI 配置:
1000000:SPI 的时钟频率设置为 1 MHz(1,000,000 Hz)。
SPI_MSBFIRST:指定数据传输时的字节顺序为最高位优先(MSB First)。
SPI_MODE0:指定 SPI 模式为 0(CPOL = 0, CPHA = 0),表示时钟极性和相位都为 0。
2.初始化参数
mySPI.begin() 用于初始化 SPI 总线。 SPI 时钟引脚 (SCK)、SPI 从输入引脚 (MISO)、SPI 主输出引脚 (MOSI)、和 SPI 片选引脚 (SS)。
PIN_SCK 和 PIN_SDA 是 SCK 和 MOSI 指定的引脚。-1 表示使用默认引脚,不指定 MISO 和 SS 引脚的情况。
setFrequency() 用于设置 SPI 总线的频率。这里设置为 2 MHz。
频率决定了数据传输的速度。2MHz 意味着 SPI 总线每秒可以传输 2,000,000 个时钟周期的数据。

最终初始化函数:

void init_printer()
{
    // 初始化电机IO
    init_motor();
    // 初始化数据引脚、通道引脚
    pinMode(PIN_LAT, OUTPUT);
    pinMode(PIN_SCK, OUTPUT);
    pinMode(PIN_SDA, OUTPUT);
    // 加热通道全部关闭
	Init_Print();
    // 初始化打印电源控制引脚、并关闭电源
    pinMode(PIN_VHEN, OUTPUT);
    digitalWrite(PIN_VHEN, LOW);
    // 初始化SPI
    init_spi();
}

2.图片取模

在这里插入图片描述
 该蓝牙打印机只能支持黑白两种颜色,所以我们需要先准备一个单色的图片,可以借助电脑上的取模软件PCtoLCD2002实现。

先找到想要打印的图片,用电脑画图软件打开,属性修改如下所示。
在这里插入图片描述
最后另存为BMP文件,保存好之后,通过取模软件打开,需要先选择取模软件的模式为图形模式,然后打开自己的文件。
在这里插入图片描述
文件正常打开之后还需要在配置中,对取模方式进行是的那个修改,点击齿轮图标进入设置模式,然后按照下图红框所示内容进行修改,修改完成之后点击保存。
在这里插入图片描述
最后将取模后的数组单独保存在文件中,总共是9600个数组。
在这里插入图片描述
在这里插入图片描述

3.图片打印

主要函数

void Print_Img()
{
    uint8_t print_data[48];
    uint32_t print_len = 48;
    for (uint8_t i = 0; i < 200; i++)
    {
        set_img_Data(print_data, i + 1);
        // 发数据
        Send_Run(print_data, print_len);
        motor_run_step(4);
    }
   printf("图片打印完成!");
}

逻辑:每行打印48个数据,所以每次传输48个数据,总共9600个数据,所以循环200次。每次打印完一行后,步进电机跑4步,相当于一行。循环往复最终就能将照片打印出来了。

其中包含的其他函数:

void start_send_data(uint8_t *data, uint32_t len)
{
    uint32_t offset = 0;
    uint8_t *ptr = data;
    while (1)
    {
        if (len > offset)
        {
            // 发送一行数据 48byte*8=384bit
            send_one_line_data(ptr);
            // 每次偏移48
            offset += 48;
            ptr += 48;
        }
       run_stb(0);
       run_stb(1);
       run_stb(2);
       run_stb(3);
       run_stb(4);
       run_stb(5);
        break;
    }
}
static void set_img_Data(uint8_t *print_data, uint8_t a)
{
    for (uint32_t index = 0; index < 48; ++index)
    {
        print_data[index] = img_data[index + 48 * a];
    }
}
static void send_one_line_data(uint8_t *data)
{
    spiCommand(data, 48);
    digitalWrite(PIN_LAT, LOW);
    delayMicroseconds(LAT_TIME);
    digitalWrite(PIN_LAT, HIGH);
}

void spiCommand(uint8_t *data_buffer, uint8_t data_len)
{
    myspi.beginTransaction(print_SPI_Set);
    myspi.transfer(data_buffer, data_len);
    myspi.endTransaction();
}

void run_stb(uint8_t stb_num)
{
    switch (stb_num)
    {
    case 0:
        digitalWrite(PIN_STB1, 1);
        delayMicroseconds(5500);
        digitalWrite(PIN_STB1, 0);
        delayMicroseconds(PRINT_END_TIME);
        break;
    case 1:
        digitalWrite(PIN_STB2, 1);
        delayMicroseconds(PRINT_TIME);
        digitalWrite(PIN_STB2, 0);
        delayMicroseconds(PRINT_END_TIME);
        break;
    case 2:
        digitalWrite(PIN_STB3, 1);
        delayMicroseconds(PRINT_TIME);
        digitalWrite(PIN_STB3, 0);
        delayMicroseconds(PRINT_END_TIME);
        break;
    case 3:
        digitalWrite(PIN_STB4, 1);
        delayMicroseconds(PRINT_TIME);
        digitalWrite(PIN_STB4, 0);
        delayMicroseconds(PRINT_END_TIME);
        break;
    case 4:
        digitalWrite(PIN_STB5, 1);
        delayMicroseconds(PRINT_TIME);
        digitalWrite(PIN_STB5, 0);
        delayMicroseconds(PRINT_END_TIME);
        break;
    case 5:
        digitalWrite(PIN_STB6, 1);
        delayMicroseconds(PRINT_TIME);
        digitalWrite(PIN_STB6, 0);
        delayMicroseconds(PRINT_END_TIME);
        break;
    }
}

  • 15
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: supersearch超级搜索系统是一个集成了最先进搜索技术的高效搜索引擎。它通过强大的算法和智能化的数据分析,能够迅速准确地提供用户所需的信息。无论是文档、图片、视频,还是网页链接,supersearch都能在几秒钟内轻松检索到最相关的内容。 这个系统的特点之一是全面的搜索范围。它不仅能搜索全球范围的网页和社交媒体,还能搜索特定领域的专业数据库和论坛。用户可以根据自己的需求选择不同的搜索源,以获得更精确的结果。 另一个特点是多样的搜索方式。supersearch提供了关键词搜索、短语搜索、图片搜索、音频搜索等多种搜索方式,以满足不同用户的需求。此外,它还支持高级搜索策略,如排除特定词语、限定搜索范围等,帮助用户精确地找到所需信息。 supersearch还具备智能推荐功能。它根据用户搜索的内容和历史记录,可以智能推荐相关的信息和内容,使用户能够更加便捷地获取所需知识。 总之,supersearch超级搜索系统是一个功能强大、搜索范围广泛、搜索方式多样的高效搜索引擎。它能够帮助用户快速准确地获取所需信息,提升用户搜索体验的效果,并满足用户不同的搜索需求。 ### 回答2: supersearch超级搜索系统是一款以猫咪为主题的搜索引擎。它拥有强大的搜索功能,可以帮助用户快速准确地找到所需的信息。 首先,supersearch的界面非常可爱,充满了猫咪元素,给人一种温馨愉悦的感觉。用户一打开网页,就仿佛置身于一个猫咪的世界中。 其次,supersearch的搜索结果十分全面和准确。它利用先进的搜索算法,能够迅速从互联网上检索到与用户查询相关的网页、图片、视频、新闻等内容,并以列表方式呈现给用户,方便用户快速了解内容。 此外,supersearch还具备快捷搜索的功能。用户只需输入简短的关键词,系统就会根据用户的搜索历史和互联网趋势智能推荐相关的信息,节省用户的时间和精力。 此外,supersearch还注重用户的个性化需求。用户可以根据自己的兴趣和偏好进行设置,例如选择搜索结果的排序方式、过滤掉某些内容或网站等。这样一来,每位用户都能得到最符合自己需求的搜索结果。 总之,supersearch超级搜索系统不仅仅是一个普通的搜索引擎,它以猫咪为主题,给用户提供了一个可爱、温馨的搜索体验。它的强大搜索功能、全面准确的搜索结果以及个性化需求的满足,使它成为用户寻找信息时的得力助手。supersearch超级搜索系统,让我们的搜索体验更加愉快和高效! ### 回答3: SuperSearch超级搜索系统是一款前沿的搜索引擎系统,为用户提供高效、精确和全面的搜索体验。 首先,SuperSearch系统采用先进的搜索算法,能够准确理解用户的搜索意图。无论是查询具体的问题,还是寻找相关的资讯,系统能够通过语义分析和深度学习技术,帮助用户快速找到满足需求的答案。 其次,该系统还具备强大的搜索能力。它能够在海量的网络数据中快速检索,并给予用户最相关的搜索结果。无论是文字、图片、视频等多种类型的内容,SuperSearch系统都能够准确匹配用户的搜索需求,为用户节省了宝贵的时间和精力。 此外,SuperSearch超级搜索系统还支持个性化定制。用户可以根据自己的兴趣和偏好,设置搜索过滤器,排除掉一些不需要的结果,提高搜索结果的准确性和个性化程度。这使得每个用户都能根据自己的需求进行定制化搜索,从而更好地满足个人需求。 综上所述,SuperSearch超级搜索系统以其高效、精确和全面的搜索能力,为用户提供了便捷、智能的搜索服务。无论是日常生活中的问题解答,还是学习和工作中的资料查询,该系统都能够快速地满足用户需求,为用户节省了时间和精力,提供更好的使用体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值