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);
解析流程:
- 找到 0x55 开头
- 提取页码(位置1)和命令码(位置2)
- 提取后面字符串数据
- 根据页码调用对应
TJC_PageX_Handler(cmd, str) - 处理完后
HMI_Delete整帧
其他页面(第2页、第3页)只需修改 TJC_Page2_Handler、TJC_Page3_Handler 即可扩展。

浙公网安备 33010602011771号