TJC 通信协议文档


1. 协议概述

  • 基于STM32HAL实现
  • 本协议用于 TJC/Nextion HMI 触摸屏 与 STM32 之间的串口通信。
  • 所有数据全部以字符串形式传输(方便 HMI 显示和 MCU 解析)。
  • 帧格式固定:0x55 开头 + 页码 + 命令码 + 字符串数据 + 0xFF 0xFF 0xFF 结尾
  • 支持多页面,通过页码自动分发到不同处理函数。

2. 帧格式

位置 内容 说明
0 0x55 帧头(固定)
1 页码 0x01=第1页,0x02=第2页……
2 命令码 见下文说明
3~N 数据区 纯字符串(多个数据用逗号 , 分隔)
N+1~N+3 0xFF 0xFF 0xFF 帧尾(TJC 标准)

3. 命令码规则

  • 高半字节(高4位):表示本次携带的数据个数
    • 0x0x(高位为0):纯按键,不带数据
    • 0x1x:携带 1 个 数据
    • 0x2x:携带 2 个 数据(逗号分隔)
    • 0x3x:携带 3 个 数据……以此类推
  • 低半字节(低4位):具体功能编号(自己定义)

4. 实际使用实例

完整代码如下

#include "app_main.h"
#include <stdlib.h>
#include <string.h>

float fre = 1000.0f;
float vol = 1000.0f;

void TJC_Receive(void);
void TJC_Page1_Handler(uint8_t cmd, char *str);
void TJC_Page2_Handler(uint8_t cmd, char *str);
void TJC_Page3_Handler(uint8_t cmd, char *str);

void app_init(void)
{
  HMI_Init();
}

void app_main(void)
{
  TJC_Receive();
}

// 全局变量记录当前页面
uint8_t current_page = 1;  // 默认第1页

void TJC_Receive(void)
{
  while (HMI_Get_Count(&tjc_rb, tjc_huart) >= 5)
  {
      if (HMI_Peek(&tjc_rb, 0) != 0x55)
      {
          HMI_Delete(&tjc_rb, 1);
          continue;
      }

      // 找帧尾
      uint8_t len = 0;
      uint8_t cnt = HMI_Get_Count(&tjc_rb, tjc_huart);

      for (uint8_t i = 1; i <= cnt - 3; i++)
      {
          if (HMI_Peek(&tjc_rb, i) == 0xFF &&
              HMI_Peek(&tjc_rb, i+1) == 0xFF &&
              HMI_Peek(&tjc_rb, i+2) == 0xFF)
          {
              len = i + 3;
              break;
          }
      }

      if (!len) break;

      // 解析:第1字节帧头,第2字节页码,第3字节命令码
      uint8_t page = HMI_Peek(&tjc_rb, 1);
      uint8_t cmd  = HMI_Peek(&tjc_rb, 2);

      // 提取文本(从索引3开始)
      uint8_t text_len = len - 5;
      char str[32];

      for (uint8_t i = 0; i < text_len && i < 31; i++)
      {
          str[i] = HMI_Peek(&tjc_rb, 3 + i);
      }
      str[text_len < 31 ? text_len : 31] = '\0';

      // 根据页码分发到不同的处理函数
      switch (page)
      {
          case 0x01:  // 第1页
              TJC_Page1_Handler(cmd, str);
              current_page =1;
              break;
          case 0x02:  // 第2页
              current_page =2;
              TJC_Page2_Handler(cmd, str);
              break;
          case 0x03:  // 第3页
              current_page =3;
              TJC_Page3_Handler(cmd, str);
              break;
          default:
              // 未知页面,丢弃
              break;
      }

      HMI_Delete(&tjc_rb, len);
  }
}

// 各页面的处理函数
void TJC_Page1_Handler(uint8_t cmd, char *str)
{
  if (cmd == 0x01)        // 频率+100
  {
      fre += 100.0f;
      HMI_Printf(tjc_huart, "t0.txt=\"%.2f\"", fre);
  }
  else if (cmd == 0x02)   // 频率-100
  {
      if (fre > 100) fre -= 100.0f;
      HMI_Printf(tjc_huart, "t0.txt=\"%.2f\"", fre);
  }
  else if (cmd == 0x03)   // 电压+100
  {
      vol += 100.0f;
      HMI_Printf(tjc_huart, "t1.txt=\"%.2f\"", vol);
  }
  else if (cmd == 0x04)   // 电压-100
  {
      if (vol > 100) vol -= 100.0f;
      HMI_Printf(tjc_huart, "t1.txt=\"%.2f\"", vol);
  }
  else if (cmd == 0x11)   // 设置频率
  {
      fre = atof(str);
      HMI_Printf(tjc_huart, "t0.txt=\"%.2f\"", fre);
  }
  else if (cmd == 0x12)   // 设置电压
  {
      vol = atof(str);
      HMI_Printf(tjc_huart, "t1.txt=\"%.2f\"", vol);
  }
  else if (cmd == 0x21)   // 设置频率+电压
  {
      char *p = str;
      fre = atof(p); //第一个参数
      p = strchr(p, ','); if (p) { vol = atof(++p); } //第二个
      //p = strchr(p, ','); if (p) { a = atof(++p); } //第三个
      //p = strchr(p, ','); if (p) { b = atof(++p); }
      HMI_Printf(tjc_huart, "t0.txt=\"%.2f\"", fre);
      HMI_Printf(tjc_huart, "t1.txt=\"%.2f\"", vol);
  }
}

void TJC_Page2_Handler(uint8_t cmd, char *str)
{
  // 第2页的指令处理
}

void TJC_Page3_Handler(uint8_t cmd, char *str)
{
  // 第3页的指令处理
}

第1页(page=0x01) 的处理函数 TJC_Page1_Handler(cmd, str) 示例如下:

  • 0x01(纯按键):频率 +100

    fre += 100.0f;
    HMI_Printf(tjc_huart, "t0.txt=\"%.2f\"", fre);
    
  • 0x02(纯按键):频率 -100

    if (fre > 100) fre -= 100.0f;
    HMI_Printf(tjc_huart, "t0.txt=\"%.2f\"", fre);
    
  • 0x03(纯按键):电压 +100

  • 0x04(纯按键):电压 -100

  • 0x11(1个数据):设置频率

    fre = atof(str);                    // str 来自 HMI 输入框
    HMI_Printf(tjc_huart, "t0.txt=\"%.2f\"", fre);
    
  • 0x12(1个数据):设置电压

    vol = atof(str);
    HMI_Printf(tjc_huart, "t1.txt=\"%.2f\"", vol);
    
  • 0x21(2个数据):同时设置频率+电压

    fre = atof(p); //第一个参数
    p = strchr(p, ','); if (p) { vol = atof(++p); } //第二个
    //p = strchr(p, ','); if (p) { a = atof(++p); } //第三个
    //p = strchr(p, ','); if (p) { b = atof(++p); }
    HMI_Printf(tjc_huart, "t0.txt=\"%.2f\"", fre);
    HMI_Printf(tjc_huart, "t1.txt=\"%.2f\"", vol);
    

解析流程

  1. 找到 0x55 开头
  2. 提取页码(位置1)和命令码(位置2)
  3. 提取后面字符串数据
  4. 根据页码调用对应 TJC_PageX_Handler(cmd, str)
  5. 处理完后 HMI_Delete 整帧

其他页面(第2页、第3页)只需修改 TJC_Page2_HandlerTJC_Page3_Handler 即可扩展。


posted @ 2026-03-29 19:56  基米不语  阅读(4)  评论(0)    收藏  举报