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

news2024/11/26 16:32:43

目录

  • 前言
  • 一、电量、温度、缺纸检测
    • 1.电量检测
    • 2.针头温度检测
    • 3.缺纸检测
  • 二、蓝牙APP通信打印
    • 1.蓝牙初始化
    • 2.APP通信打印
  • 三、FreeRTOS任务整合


前言

喵喵蓝牙热敏打印机(上)
内容有点多,就分为了上下两篇。


一、电量、温度、缺纸检测

先启动一下串口通信,方便后续操作。

 Serial.begin(115200); 

1.电量检测

原理图:
在这里插入图片描述
在这里插入图片描述
逻辑分析:电池电量检测可以通过检测POWER_ADC的分压值来转换。
这个里的分压值是个模拟变化量,所以我们要用到ADC模数转换。
代码如下:

#include <adc.h>
#define POWER_ADC 34//Arduino IDE中为ESP32 配置的ADC默认环境就能
                    //用,所以直接定义一个引脚即可,不用初始化。

int battery;
int batt_all;

int get_battery_adc()
{
    int data = 0;
    //获取IO口电压值
    data = analogReadMilliVolts(POWER_ADC);//直接通过内置函数获取电压值
    return data;
}

void Deal_battery_adc()
{
   battery = map(get_battery_adc(),1650,2100,0,100);
   for (int i = 0; i < 10; i++)//为了使获取的电压值比较稳定,就先获取10个,然后取平均值。
   {
     batt_all+=battery;
     delay(1000);
   }
   battery_fina=batt_all/10;
   batt_all=0;
   printf("电量:%d\r\n",batt_all/10);
}

在这里插入图片描述

重点解析:map(get_battery_adc(),1650,2100,0,100);
map函数主要就是作为一个映射功能。
由于该硬件使用的是18650电池,该电池满电4.2v,终止电压2.75v。但由于该硬件的步进电机到3.3v就驱动不了了,所以ADC获取的电压模拟量会在1650和2100之间(实际上是3300和4200之间,但两个10k电阻分压一半)。
在这里插入图片描述

2.针头温度检测

在这里插入图片描述
在这里插入图片描述

uint8_t head_temp = 23;                 //打印头温度
uint16_t temp_adc;
void HeatTemp() {
  temp_adc = analogRead(PIN_TEMP);
  Serial.print("打印头温度ADC:"); Serial.println(temp_adc);
  head_temp = 23;
}

直接读即可

3.缺纸检测

在这里插入图片描述
在这里插入图片描述
电路看着很复杂,但其实原理很简单,直接读35引脚,为1就是缺纸,为0就是有纸。

int NO_Paper;
void read_paper_statue()
{
    if(digitalRead(PRINT) == 1){
      Serial.printf("缺纸1111\n");
      NO_Paper=1;
    }else{
      Serial.printf("有纸0000\n");
      NO_Paper=0;
    }
}

二、蓝牙APP通信打印

1.蓝牙初始化

这部分主要就是设置个波特率顺便初始化一下SPI

#include <BluetoothSerial.h>

void init_Blue()
{
  Serial.begin(115200);
    print_Blue_Data = (uint8_t*)malloc(50 * 1024); 
     printerSPI.begin(PIN_CLK, -1, PIN_DI, -1);
  printerSPI.setFrequency(2000000);
  //print_Blue_Data = (uint8_t *)malloc(3 * 1024 * 1024);

}

2.APP通信打印

这一部分就是全力依靠樱猫大佬的代码了
上位机和设备建立链接时需要发送的指令和顺序如下:
1.上位机发送 24 指令,设置 CRC 校验的密钥,固定四字节 crcKey = 0x35769521
2.发送 10 指令获取设备的 SN 码,需要蓝牙返回指定的 SN 码:“P1001705253855”
3.上位机发送 66 指令,设备返回固定字符串信息:”BK3432”,蓝牙设备型号
4.上位机发送 127 指令,设备返回固定信息:{0x76, 0x33, 0x2e, 0x33, 0x38, 0x2e, 0x31, 0x39,
0, 0, 0, 0};
5.上位机发送 25 指令,设定打印机加热时间(热密度)
6.上位机发送 48 指令,请求设备名称,设备返回自己设定的名字
7.上位机发送 16 指令,请求设备电池信息,设备返回当前电压
8.上位机发送 31 指令,请求关机时间,设备返回设定的关机时间默认 3600 分钟
9.上位机发送 4 指令,获取打印机版本信息,默认版本 2.0.1,设备返回{0x01, 0x00, 0x02};
10.上位机发送 44 指令,设定纸张类型,设备纸张固定,不需要修改。
  上述流程中,需要注意设备返回的数据,在开发蓝牙打印机的功能时,需要正确返回数据,否则会导致设备连接失败,并且每条指令在接受完成之后,设备都需要进行回复,回复内容固定为 00,类型根据接收到的类型来定。如果指令没有正确回应,软件会重复发送直至超时。
上位机和设备之间传输打印数据发送的指令和数据流程如下:
1.打印时会先发送两次 25 指令用以设置打印热密度,也就是打印加热时间。
2.发送 26(进料线)指令,也就是开始打印指令
3.然后发送 0 指令,开始传输数据,分包发送打印的数据,一包最大 1920
4.数据发送完毕之后,会再次发送 26 指令,收到之后,打印机开始打印数据。

指令定义:

#define PRINT_DATA 0            // 打印数据
#define PRINT_DATA_COMPRESS 1   // 打印数据压缩
#define FIRMWARE_DATA 2         // 固件数据
#define USB_UPDATE_FIRMWARE 3   // USB更新固件
#define GET_VERSION 4           // 获取版本
#define SENT_VERSION 5          // 发送版本
#define GET_MODEL 6             // 获取模式
#define SENT_MODEL 7            // 发送模式
#define GET_BT_MAC 8            // 获取蓝牙MAC
#define SENT_BT_MAC 9           // 发送蓝牙MAC
#define GET_SN 10               // 获取SN码
#define SENT_SN 11              // 发送SN码
#define GET_STATUS 12           // 获取状态
#define SENT_STATUS 13          // 发送状态
#define GET_VOLTAGE 14          // 获取电压
#define SENT_VOLTAGE 15         // 发送电压
#define GET_BAT_STATUS 16       // 获取蓝牙状态
#define SENT_BAT_STATUS 17      // 发送蓝牙状态
#define GET_TEMP 18             // 获取打印头温度
#define SENT_TEMP 19            // 发送打印头温度
#define SET_FACTORY_STATUS 20   // 设置出厂状态
#define GET_FACTORY_STATUS 21   // 获取出厂状态
#define SENT_FACTORY_STATUS 22  // 发送出厂状态
#define SENT_BT_STATUS 23       // 发送蓝牙状态
#define SET_CRC_KEY 24          // 设置CRC密钥
#define SET_HEAT_DENSITY 25     // 设定热密度
#define FEED_LINE 26            // 进料线
#define PRINT_TEST_PAGE 27      // 打印测试页
#define GET_HEAT_DENSITY 28     // 获取热密度
#define SENT_HEAT_DENSITY 29    // 发送热密度
#define SET_POWER_DOWN_TIME 30  // 设定关机时间
#define GET_POWER_DOWN_TIME 31  // 获取断电时间
#define SENT_POWER_DOWN_TIME 32 // 发送断电时间
#define FEED_TO_HEAD_LINE 33    // 送至标题行
#define PRINT_DEFAULT_PARA 34   // 打印默认参数
#define GET_BOARD_VERSION 35    // 获取板子版本
#define SENT_BOARD_VERSION 36   // 发送板子版本
#define GET_HW_INFO 37          // 获取硬件信息
#define SENT_HW_INFO 38         // 发送硬件信息
#define SET_MAX_GAP_LENGTH 39   // 设定最大间隙长度
#define GET_MAX_GAP_LENGTH 40   // 获取最大间隙长度
#define SENT_MAX_GAP_LENGTH 41  // 发送最大间隙长度
#define GET_PAPER_TYPE 42       // 获取纸张类型
#define SENT_PAPER_TYPE 43      // 发送纸张类型
#define SET_PAPER_TYPE 44       // 设置纸张类型
#define GET_COUNTRY_NAME 45     // 获取国家名称
#define SENT_COUNTRY_NAME 46    // 发送国家名称
#define DISCONNECT_BT 47        // 断开蓝牙
#define GET_DEV_NAME 48         // 获取设备名称
#define SENT_DEV_NAME 49        // 发送设备名称
#define CMD_39 57
#define CMD_40 64
#define CMD_41 65
#define CMD_42 66
#define CMD_43 67
#define CMD_7F 127
#define CMD_80 128
#define CMD_81 129
#define CMD_82 130

上述通信需要用到CRC数据校验
crc.c

/**
 * \file
 * Functions and types for CRC checks.
 *
 * Generated on Tue Jan  7 07:33:25 2020
 * by pycrc v0.9.2, https://pycrc.org
 * using the configuration:
 *  - Width         = 32
 *  - Poly          = 0x04c11db7
 *  - XorIn         = 0xffffffff
 *  - ReflectIn     = True
 *  - XorOut        = 0xffffffff
 *  - ReflectOut    = True
 *  - Algorithm     = table-driven
 */
#include "crc.h"     /* include the header file generated with pycrc */
#include <stdlib.h>
#include <stdint.h>



/**
 * Static table used for the table_driven implementation.
 */
static const crc_t crc_table[256] = {
    0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
    0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
    0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
    0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
    0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
    0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
    0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
    0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
    0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
    0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
    0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
    0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
    0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
    0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
    0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
    0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
    0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
    0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
    0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
    0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
    0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
    0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
    0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
    0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
    0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
    0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
    0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
    0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
    0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
    0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
    0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
    0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};


crc_t crc_update(crc_t crc, const void *data, size_t data_len)
{
    const unsigned char *d = (const unsigned char *)data;
    unsigned int tbl_idx;

    while (data_len--) {
        tbl_idx = (crc ^ *d) & 0xff;
        crc = (crc_table[tbl_idx] ^ (crc >> 8)) & 0xffffffff;
        d++;
    }
    return crc & 0xffffffff;
}

crc.h

/**
 * \file
 * Functions and types for CRC checks.
 *
 * Generated on Tue Jan  7 07:33:20 2020
 * by pycrc v0.9.2, https://pycrc.org
 * using the configuration:
 *  - Width         = 32
 *  - Poly          = 0x04c11db7
 *  - XorIn         = 0xffffffff
 *  - ReflectIn     = True
 *  - XorOut        = 0xffffffff
 *  - ReflectOut    = True
 *  - Algorithm     = table-driven
 *
 * This file defines the functions crc_init(), crc_update() and crc_finalize().
 *
 * The crc_init() function returns the initial \c crc value and must be called
 * before the first call to crc_update().
 * Similarly, the crc_finalize() function must be called after the last call
 * to crc_update(), before the \c crc is being used.
 * is being used.
 *
 * The crc_update() function can be called any number of times (including zero
 * times) in between the crc_init() and crc_finalize() calls.
 *
 * This pseudo-code shows an example usage of the API:
 * \code{.c}
 * crc_t crc;
 * unsigned char data[MAX_DATA_LEN];
 * size_t data_len;
 *
 * crc = crc_init();
 * while ((data_len = read_data(data, MAX_DATA_LEN)) > 0) {
 *     crc = crc_update(crc, data, data_len);
 * }
 * crc = crc_finalize(crc);
 * \endcode
 */
#ifndef CRC_H
#define CRC_H

#include <stdlib.h>
#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif


/**
 * The definition of the used algorithm.
 *
 * This is not used anywhere in the generated code, but it may be used by the
 * application code to call algorithm-specific code, if desired.
 */
#define CRC_ALGO_TABLE_DRIVEN 1


/**
 * The type of the CRC values.
 *
 * This type must be big enough to contain at least 32 bits.
 */
typedef uint32_t crc_t;


/**
 * Calculate the initial crc value.
 *
 * \return     The initial crc value.
 */
static inline crc_t crc_init(void)
{
    return 0xffffffff;
}


/**
 * Update the crc value with new data.
 *
 * \param[in] crc      The current crc value.
 * \param[in] data     Pointer to a buffer of \a data_len bytes.
 * \param[in] data_len Number of bytes in the \a data buffer.
 * \return             The updated crc value.
 */
crc_t crc_update(crc_t crc, const void *data, size_t data_len);


/**
 * Calculate the final crc value.
 *
 * \param[in] crc  The current crc value.
 * \return     The final crc value.
 */
static inline crc_t crc_finalize(crc_t crc)
{
    return crc ^ 0xffffffff;
}


#ifdef __cplusplus
}           /* closing brace for extern "C" */
#endif

#endif      /* CRC_H */

Arduino_CRC32.c

/*
  Copyright (c) 2020 Arduino.  All rights reserved.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  See the GNU Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

/**************************************************************************************
 * INCLUDE
 **************************************************************************************/

#include "Arduino_CRC32.h"

/**************************************************************************************
 * PUBLIC MEMBER FUNCTIONS
 **************************************************************************************/

void Arduino_CRC32::init(uint32_t start)
{
  crc32_start = start;
}

uint32_t Arduino_CRC32::calc(uint8_t const data[], uint32_t const len)
{
  crc_t crc32;
  crc32 = crc_update(crc32_start, data, len);
  crc32 = crc_finalize(crc32);
  return crc32;
}

Arduino_CRC32.h

/*
  Copyright (c) 2020 Arduino.  All rights reserved.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  See the GNU Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#ifndef ARDUINO_CRC32_H_
#define ARDUINO_CRC32_H_

/**************************************************************************************
 * INCLUDE
 **************************************************************************************/

#include <stdint.h>
#include "crc.h"
/**************************************************************************************
 * CLASS DECLARATION
 **************************************************************************************/

class Arduino_CRC32
{

public:
  crc_t crc32_start;
  void init(uint32_t start);
  uint32_t calc(uint8_t const data[], uint32_t const len);

};

#endif /* ARDUINO_CRC32_H_ */

蓝牙通信打印主要函数


struct
{
  uint8_t packType;
  uint8_t packIndex;
  uint16_t dataLen;
} packHeader;
uint8_t gotStartByte = 0;
uint8_t c;
uint16_t readpos = 0;
uint8_t dataPack_read[2048];

void paperang_app()
{
  uint16_t i = 0;
  // 重新设置class of device
  SerialBT.begin("MaoPaperang");
  esp_bt_cod_t cod;
  cod.major = 6;                            // 主设备类型
  cod.minor = 0b100000;                     // 次设备类型
  cod.service = 0b00000100000;              // 服务类型
  esp_bt_gap_set_cod(cod, ESP_BT_INIT_COD); // 设置蓝牙设备的class of device
  crc_t crc32_key = 0x35769521; // 初始化 CRC32 计算器
  packHeader.dataLen = 0;       // 初始化数据包头部的数据长度为 0

  while (1)
  {
    ButtonRun();   // 执行按钮操作的函数
    Pin_Stb_Low(); // 关闭STAPower的函数
    // 监听蓝牙串口输入
    if (SerialBT.available())
    {
      c = SerialBT.read(); // 读取一个字节的数据
      //  如果读取到起始字节并且之前未找到起始字节
      if (c == START_BYTE && gotStartByte == 0)
      {
        gotStartByte = 1;
        readpos = 0;
      }
      else if (readpos == 1)
      {
        // 读取数据包类型、索引和数据长度
        packHeader.packType = c;
        packHeader.packIndex = SerialBT.read();
        packHeader.dataLen = SerialBT.read();
        packHeader.dataLen += SerialBT.read() << 8;
      }
      else if (readpos == 2 && packHeader.dataLen != 0 && packHeader.dataLen < 2048)
      {
        // 读取数据包内容
        i = packHeader.dataLen - 1;
        if (packHeader.packType == PRINT_DATA)
        {
          // 如果是打印数据包类型,则读取打印数据
          print_Blue_Data[printDataCount++] = c;
          while (i)
          {
            while (SerialBT.available() == 0)
              ;
            print_Blue_Data[printDataCount++] = SerialBT.read();
            --i;
          }
        }
        else
        {
          // 否则,读取一般数据包
          dataPack_read[dataPack_read_pos++] = c;
          while (i)
          {
            dataPack_read[dataPack_read_pos++] = SerialBT.read();
            --i;
          }
        }
      }
      else if (readpos < 7)
      {
        // 如果读取位置小于7,则暂时不做处理
        ;
      }
      else if (c == END_BYTE && readpos == 7)
      {
        // 如果读取到结束字节且读取位置为7,则处理数据
        paperang_process_data(); // 处理数据的函数
        gotStartByte = 0;
        dataPack_read_pos = 0;
        readpos = 0;
        packHeader.dataLen = 0;
      }
      else
      {
        // 出现错误情况
        Serial.println("ERROR");
        gotStartByte = 0;
        dataPack_read_pos = 0;
        readpos = 0;
        packHeader.dataLen = 0;
      }

      if (gotStartByte == 1)
        ++readpos; // 如果找到起始字节,则增加读取位置
    }
    else

    {
      vTaskDelay(1);
      digitalWrite(PIN_VHEN, 1);
    }
  }
}

收到数据的处理函数

void paperang_process_data()
{
  uint32_t tmp32;
  switch (packHeader.packType)
  {
  case PRINT_DATA:
    return;
  // 设置CRC密钥
  case SET_CRC_KEY:
  {
    tmp32 = dataPack_read[0] << 24 + dataPack_read[1] << 16 + dataPack_read[2] << 8 + dataPack_read[3];
    // crc32.init(tmp32);
    crc_t crc32_key = tmp32;
    break;
  }
  // 获取版本信息并发送
  case GET_VERSION:
    paperang_send_msg(SENT_VERSION, PRINTER_VERSION, 3);
    break;
  // 获取设备名称并发送
  case GET_DEV_NAME:
    paperang_send_msg(SENT_DEV_NAME, (uint8_t *)PRINTER_NAME, 2);
    break;
  // 获取SN码并发送
  case GET_SN:
    paperang_send_msg(SENT_SN, (uint8_t *)PRINTER_SN, strlen((char *)PRINTER_SN));
  // 获取电池电量并发送
  case GET_BAT_STATUS:
    // BatteryPower();
    PRINTER_BATTERY = get_battery_adc();
    paperang_send_msg(SENT_BAT_STATUS, &PRINTER_BATTERY, 1);
    break;
  // 获取国家名称并发送
  case GET_COUNTRY_NAME:
    paperang_send_msg(SENT_COUNTRY_NAME, (uint8_t *)COUNTRY_NAME, 2);
    break;
  case CMD_42:
    paperang_send_msg(CMD_43, (uint8_t *)CMD_42_DATA, strlen(CMD_42_DATA));
    break;
  case CMD_7F:
    paperang_send_msg(CMD_80, CMD_7F_DATA, 12);
    break;
  case CMD_81:
    paperang_send_msg(CMD_82, CMD_81_DATA, 16);
    break;
  case CMD_40:
    paperang_send_msg(CMD_41, CMD_40_DATA, 1);
    break;
  // 设置打印密度
  case SET_HEAT_DENSITY:
    heat_density = dataPack_read[0];
    break;
  // 获取打印密度并发送
  case GET_HEAT_DENSITY:
    paperang_send_msg(SENT_HEAT_DENSITY, &heat_density, 1);
    break;
  // 获取打印头温度
  case GET_TEMP:
    head_temp = get_adc_temperatrue();
    paperang_send_msg(SENT_TEMP, &head_temp, 1);
    break;
  // 进料线
  case FEED_LINE:
   flag_data.printing_flag=1;
    if (printDataCount / 48 != 0)
    {
      startPrint();
      motor_run_step(300); // 打印完毕出纸长度,单位:点,8点/mm。    
    }
    flag_data.printing_flag=0;
    printDataCount = 0;
    break;
  default:
    break;
  }
  paperang_send_ack(packHeader.packType);
}

数据发送接收函数

void paperang_send(void)
{
  SerialBT.write(dataPack, dataPack_len);
}
// 蓝牙回复指令
void paperang_send_ack(uint8_t type)
{
  uint8_t ackcrc = 0;
  dataPack[0] = START_BYTE;
  dataPack[1] = type;
  dataPack[2] = 0x00;
  dataPack[3] = 0x01;
  dataPack[4] = 0x00;
  dataPack[5] = 0x00;
  // crc32_result = crc32.calc(&ackcrc, 1);
  // 初始化 CRC32 计算
  crc_t crc32_result = 0xFFFFFFFF;
  crc32_result = crc_update(crc32_result, &ackcrc, 1);
  crc32_result ^= 0xFFFFFFFF;
  memcpy(dataPack + 6, (uint8_t *)&crc32_result, 4);
  dataPack[10] = END_BYTE;
  dataPack_len = 11;
  paperang_send();
}

// 蓝牙回复信息
void paperang_send_msg(uint8_t type, const uint8_t *dat, uint16_t len)
{
  dataPack[0] = START_BYTE;
  dataPack[1] = type;
  dataPack[2] = 0x00;
  memcpy(dataPack + 3, (uint8_t *)&len, 2);
  memcpy(dataPack + 5, dat, len);
  dataPack_len = 5 + len;
  //   crc32_result = crc32.calc(dat, len);
  crc_t crc32_result = 0xFFFFFFFF;
  crc32_result = crc_update(crc32_result, dat, len);
  crc32_result ^= 0xFFFFFFFF;
  memcpy(dataPack + dataPack_len, (uint8_t *)&crc32_result, 4);
  dataPack[dataPack_len + 4] = END_BYTE;
  dataPack_len += 5;
  paperang_send();
}

打印函数


char *CMD_42_DATA PROGMEM = "BK3432";
uint8_t CMD_7F_DATA[] PROGMEM = {0x76, 0x33, 0x2e, 0x33, 0x38, 0x2e, 0x31, 0x39, 0, 0, 0, 0};
uint8_t CMD_81_DATA[] PROGMEM = {0x48, 0x4d, 0x45, 0x32, 0x33, 0x30, 0x5f, 0x50, 0x32, 0, 0, 0, 0, 0, 0, 0};
uint8_t PRINTER_VERSION[] PROGMEM = {0x01, 0x00, 0x02}; // 打印机版本2.0.1
uint8_t *CMD_40_DATA PROGMEM = {0x00};
uint8_t heat_density = 64; // 热密度
void startPrint()
{
  int pinnumber;
  int i;
  int cache; // 分批打印标志,避免同时开启所有打印头
  // onprint = 1;
  onprint = 1;
  
  PowerONTime = millis();
  read_paper_statue();
   if (NO_Paper == 0) {
  static unsigned char motor_add = 0;
  Serial.println("[INFO]正在打印...");
  Serial.printf("[INFO]共%u行\n", printDataCount / 48);
  digitalWrite(PIN_VHEN, 1);
  cache = -1;
  for (uint32_t pointer = 0; pointer < printDataCount; pointer += 48)
  {
    cache = -1;
    while (cache != 0)
    { // 分批加热打印头
      if (cache == -1)
      {
        cache = 0;
      }
      pinnumber = 0;
      for (i = cache; i < 48; i++)
      {
        pinnumber = pinnumber +   shuzu16to2jingzhi[print_Blue_Data[pointer + i]]; // 这里用了excel公式做了个数组来统计0-255转换成二进制后1的个数(懒得写算法)输出当前行打印点数
        if (pinnumber <= printpin)
        { // 判断打印的数据中要加热的点数是否超过规定最大值,如果超过了就先加热指定的点
          printDatacache[i] = print_Blue_Data[pointer + i];
          if (i == 47)
          {
            cache = 0;
          }
        }
        else
        {
          cache = i;
          break;
        }
      }
      send_Blue_Data(printDatacache);
      // 控制各个STB引脚
      for (int j = 0; j < 48; j++)
      {
        printDatacache[j] = 0;
      }
      if (pinnumber != 0)
      {
        run_stb(0);
        run_stb(1);
        run_stb(2);
        run_stb(3);
        run_stb(4);
        run_stb(5);
      }
    }
    motor_run_step(4);  
  }
    motor_stop();
    Pin_Stb_Low();
    clearData();
    printDataCount = 0;
    Serial.println("[INFO]打印完成");
    digitalWrite(PIN_VHEN, 0);
    PowerONTime = millis();
    onprint = 0;
   }
   else
   {
      startBeep();
      delay(500);
      stopBeep();
      delay(500);
      startBeep();
      delay(500);
      stopBeep();
   }
}

三、FreeRTOS任务整合

在 Arduino IDE 的 ESP32 环境里有内置的FreeRTOS系统,直接使用即可。
使用说明详见STM32第十九课:FreeRTOS移植和使用
我这里使用了两个任务,一个用来执行主要任务蓝牙通信打印,一个用来实时监测报警提示用户。

#include <Arduino.h>
#include <BluetoothSerial.h>
#include <SPI.h> 
#include <LED.h>
#include <motor.h>
#include <adc.h>
#include <print.h>
#include <img.h>
#include <bmiao.h>


void task_print(void *pvParameters)//打印任务
{
    for (;;) 
    {
         paperang_app();
    }
}

void task_LED(void *pvParameters)//温度,打印检测
{
   for (;;) 
   {
    read_paper_statue();
    //vTaskDelay(500);
    if(flag_data.printing_flag==0)
    {
      Led_Status(2);
    }
    if(flag_data.printing_flag==1)
    {
      Led_Status(3);
    }
    if(NO_Paper == 1)
    {
      digitalWrite(PIN_VHEN, 0);
      //电机警告
      startBeep();
      vTaskDelay(500);
      stopBeep();
      vTaskDelay(500);
      startBeep();
      vTaskDelay(500);
      stopBeep();
    }else
    {stopBeep();
      digitalWrite(PIN_VHEN, 1);
   }
   }
   
}
void init_task()//初始化任务
{
  BaseType_t task = NULL;
    task = xTaskCreate(
        task_print,  // 任务函数
        "task_print", // 任务名
        1024*6,      // 任务栈
        NULL,         // 任务参数
        1,            // 任务优先级
        NULL          // 任务句柄
    );
  if(task == NULL)
  {
     Serial.printf("printf err\n");

  }
    task = xTaskCreate(
        task_LED,  // 任务函数
        "task_LED", // 任务名
        1024*4,         // 任务栈
        NULL,         // 任务参数
        2,            // 任务优先级
        NULL          // 任务句柄
    );
    if(task == NULL)
    {
       Serial.printf("led err\n");
    }
}


void setup()
{
  init_Blue();
  Led_Config();     //初始化LED
  init_motor();     //初始化电机
  Init_Print();     //初始化打印头
  init_printer();
  pinMode(PIN_VHEN, OUTPUT);
  digitalWrite(PIN_VHEN, LOW);

  //缺纸IO初始化
  pinMode(PRINT, INPUT);
  pinMode(PIN_VHEN, OUTPUT);
  digitalWrite(PIN_VHEN, LOW);
  analogReadResolution(TEMPERATRUE_ADC_BIT);
  init_task();//启动任务
  Serial.print("init_task OK\r\n");
}
void loop()
{
}

其中电机警告是使用电机微动来实现的,通过电机的的微动来发声。

void startBeep(void)//微动
{
  // 设定总的转动时间为 1 秒(1000000 微秒)
    unsigned long totalTime = 1000000; 
    unsigned long stepTime = 100;     // 每步延时 2000 微秒
    unsigned long steps = totalTime / stepTime;

    for (unsigned long i = 0; i < steps; ++i) {
        goFront1(stepTime);
    }
}
void stopBeep(void)//停止
{
   digitalWrite(PIN_MOTOR_AP,LOW);
   digitalWrite(PIN_MOTOR_AM,LOW);
   digitalWrite(PIN_MOTOR_BP,LOW);
   digitalWrite(PIN_MOTOR_BM,LOW);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2045200.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Codigger视频会议(Meeting):科技行业软件开发团队的协作革新

在数字化时代&#xff0c;软件开发团队的协作方式正在经历一场革命。远程工作已成为新常态&#xff0c;而Codigger视频会议&#xff08;Meeting&#xff09;作为这场变革的催化剂&#xff0c;正在帮助科技行业的团队突破地理限制&#xff0c;实现无缝协作。 随着科技行业的快速…

Adobe Audition AU 2023-23.6.6.1 解锁版下载和安装教程(专业的音频处理工具)

前言 Audition是Adobe旗下一款非常好用的音频处理工具&#xff0c;软件为用户们提供了功能强大的音频编辑功能和一个相对完善的工作流程&#xff0c;用户们无论是录制音乐、无线电广播还是视频配音&#xff0c;多音频合成&#xff0c;这款软件都能够给你足够的创作动力。audit…

MR400D工业级带网口4G DTU:RS232/RS485 TO LTE深度测评

在物联网技术日新月异的今天&#xff0c;数据传输的效率和稳定性成为了各行各业关注的焦点。作为一款集先进性与实用性于一身的物联网设备&#xff0c;工业级带网口的4G DTU&#xff08;数据传输单元&#xff09;以其强大的功能特性和广泛的应用场景&#xff0c;赢得了市场的广…

整合nacos遇到的小问题

1.nacos创建配置中心文件时&#xff0c;创建不了&#xff0c;原因是新版本nacos数据表有字段加了安全校验 2.bootStrap.yaml文件创建时。需注意文件名称和后缀

simulink种deadzone死区模块的理解和使用,使用simulink开发pid的时候经常添加deadzone(重要)

Dead Zone模块产生指定范围&#xff08;称为截止区&#xff09;内的零输出。输入输出的关系如下&#xff1a; 1、输入落入截止区&#xff0c;输出0 2、输入大于上限值&#xff0c;输出上限值 3、输入小于等于下限值&#xff0c;输出下限值 使用simulink开发pid的时候经常添…

人工智能在子宫内膜癌领域的研究进展|顶刊速递·24-08-12

小罗碎碎念 本期推文主题&#xff1a;人工智能在子宫内膜癌领域中的研究进展 昨天的推文主要介绍的是卵巢癌&#xff0c;有一小部分涉及到了子宫内膜癌&#xff0c;按照最新的规划&#xff0c;今天的推文是与子宫内膜癌相关的。 从事妇科肿瘤研究的老师/同学&#xff0c;可以好…

探索数字媒体产业园区的未来之路

随着科技的飞速发展和数字经济的崛起&#xff0c;数字媒体产业园区正迎来前所未有的机遇和挑战。未来&#xff0c;数字媒体产业园区的发展将主要体现在以下几个方面&#xff1a; 1. 技术驱动的创新 数字媒体产业园区将继续受到前沿技术的推动。人工智能、大数据、虚拟现实和增…

中小企业文档管理最佳方案:7个热门工具

本文将分享7大优质中小企业文档管理工具&#xff1a;PingCode&#xff1b;2. Worktile&#xff1b;3. 飞书文档&#xff1b;4. 语雀&#xff1b;5. 有道云笔记&#xff1b;6. 石墨文档&#xff1b;7. DocuWare。 在管理中小企业时&#xff0c;文档混乱和信息难以追踪是一个常见…

熬汤煮酱锅 全自动可倾式夹层锅的优势:

1. 省时省能 夹层锅的底部加装了隔热层&#xff0c;加热速度更快&#xff0c;热源均匀&#xff0c;可以让食物快速煮熟&#xff0c;大大缩短烹饪时间。同时&#xff0c;其隔热层还可以使锅底局部温度升高&#xff0c;达到减少热量损失、减少能源浪费的效果。 2. 防烫手 夹层锅…

【单片机】51单片机入门教程(一):深入理解普通IO口与外部中断

51单片机入门教程:深入理解普通IO口与外部中断 前言 51单片机是嵌入式系统开发中的经典之作,也是学习嵌入式开发的理想起点。虽然51单片机的基础结构由Intel公司最早推出,但如今市面上有许多厂商都推出了自己的51单片机型号,如STC的STC89C52RC等。这些型号虽然品牌不同,但…

C语言提高(1)

在C语言中&#xff0c;_CRT_SECURE_NO_WARNINGS 是一个宏定义&#xff0c;它通常与Microsoft Visual Studio&#xff08;MSVC&#xff09;编译器一起使用&#xff0c;用于禁用一些与安全相关的警告。这些警告通常与C标准库中的某些函数的安全性问题相关&#xff0c;特别是在处理…

Java -泛型

认识泛型 定义类&#xff0c;接口&#xff0c;方法时&#xff0c;同时声明了一个或者多个类型变量&#xff08;如&#xff1a;<E>) 称为泛型类&#xff0c;泛型接口&#xff0c;泛型方法&#xff0c;他们统称为泛型。 public class ArrayList<E>{..... } 作用&…

嵌入式软件--数电基础 DAY 3

一、二进制 &#xff08;1&#xff09;文字表述 二进制数只能取0&#xff0c;1两个数字&#xff0c;逢二进一。 通过二进制表达文字。如战争时代的电报。 通过电灯泡的亮灭传递出信息。可以对灯亮和灯灭富裕一些含义&#xff0c;就能传达出想要的消息。 这就是编码和解码两…

[uview3]Popup 弹出层

项目场景&#xff1a;展会管理系统&#xff0c;通过弹出层的方式切换展会项目&#xff0c;效果如下&#xff1a; 弹出部分代码&#xff1a; 注意点&#xff1a;层级要设高一点&#xff0c;可能会其他元素遮挡出不来 <view style"z-index: 999"><up-popup …

轻度自闭症的温柔启航:星启帆的康复之旅

在儿童成长的道路上&#xff0c;自闭症作为一种复杂的神经发展障碍&#xff0c;给许多家庭带来了挑战与困扰。轻度自闭症&#xff0c;作为自闭症谱系中的一个类型&#xff0c;其症状表现相对较轻&#xff0c;但同样需要我们的关注与科学的干预。星启帆自闭症儿童康复机构&#…

叉车AI防撞预警系统 主动防撞 司机危险行为报警

叉车作为物料搬运设备中的主力军&#xff0c;叉车在港口、车站、机场、货场、工厂车间、仓库、流通中心和配送中心等场所大显身手&#xff0c;替代人工作业大大提高搬运效率。但其工作环境通常比较复杂&#xff0c;有时处于人车混杂的同一空间&#xff0c;作业安全高度依赖驾驶…

千元护眼台灯大PK,书客、爱德华医生和柏曼护眼台灯哪个好?

在当今社会&#xff0c;孩子们面临着越来越大的学习压力大&#xff0c;在追求学业成就的同时&#xff0c;我们也应关注学习环境对视力健康的影响。说到护眼&#xff0c;多在户外运动当然是很多人觉得的最佳选项&#xff0c;但很多时候&#xff0c;因为条件限制&#xff0c;学生…

充电宝是有线的好还是无线的好?适合大学生平价充电宝有哪些?

平价的充电宝推荐我当然是首选无线磁吸的啦&#xff0c;因为我自己也是有三十多款充电宝的测评经验了&#xff0c;之前总是用着有线的充电宝&#xff0c;就是会有各种麻烦&#xff0c;比如上下班通勤的时候&#xff0c;数据线总是给路边各种东西钩住&#xff0c;路过的电动车什…

数据结构——排序(3):交换排序(续)

目录 一、快速排序 (1)hoare版本 ①思路 ②过程图示 ③思考 ④代码实现 ⑤代码解释 &#xff08;2&#xff09;挖坑法 ①思路 ②过程图示 ③思考 ④代码实现 ⑤代码解释 &#xff08;3&#xff09;lomuto前后指针 ①思路 ②过程图示 ③思考 ④代码实现 ⑤代…

在写PWM风扇驱动之前:如何透过FG信号,获取风扇转速?

文章目录 一、前言二、风扇规格2.1 线序2.2 FG 信号说明 三、FG公式推导四、软件算法解析4.1 HZ 的概念4.2 算法 五、篇尾 一、前言 PWM风扇也是日常SOC智能设备开发中常见的外围小设备&#xff0c;而对于驱动工程师而言&#xff0c;主要工作就是实现风扇的控制驱动&#xff0…