自定义串口通讯协议

2023-05-16

通信协议

1.读操作

主机发送设备地址0x0A、读命令字、数据长度(数据长度不包括CRC),当主机接收完数据和CRC后,需要进行数据校验,并和从机返回的CRC进行对比。数据校验方式为CRC8。CRC8会从主机发送的地址开始校验,包括地址(0x0A)、读命令字、读取的数据长度N、以及从机返回的N字节数据,校验多项式为X8 +X2 +X+1。

2.写操作

主机发送设备地址0x0A | 0x01、写命令字、数据长度(数据长度不包括CRC)、N字节数据、CRC;从机接收完数据和CRC后,需要进行数据校验,结果OK则返回ACK,否则返回NACK。数据校验方式为CRC8CRC8会从主机发送的地址开始校验,包括地址(0x0A|0x01)、写命令字、写的数据长度NN字节数据,校验多项式为X8 +X2 +X+1

下位机代码实现过程

使用串口发送和接收中断发送和接收数据,接收到的数据可以存放在一个buf数组中,要发送的数据也是一样。可在接收中断中解析命令也可在while(1)死循环中解析,根据不同的命令执行不同的操作即可。

/***********************************************************************************************************************
* Function Name: uart2_interrupt_receive
* @brief  UART2 Receive interrupt service routine
* @param  None
* @return None
***********************************************************************************************************************/
void uart2_interrupt_receive(void)
{
    volatile uint8_t rx_data;
    volatile uint8_t err_type;

    err_type = (uint8_t)(SCI1->SSR11 & 0x0007U);
    SCI1->SIR11 = (uint16_t)err_type;

    if (err_type != 0U)
    {
        uart2_callback_error(err_type);
    }
    
    rx_data = SCI1->RXD2;
	InterruptUartAppRx(rx_data);
    INTC_ClearPendingIRQ(SR2_IRQn);     /* clear INTSR2 interrupt flag */
}
/***********************************************************************************************************************
* Function Name: uart2_interrupt_send
* @brief  UART2 Send interrupt service routine
* @param  None
* @return None
***********************************************************************************************************************/
void uart2_interrupt_send(void)
{
    INTC_ClearPendingIRQ(ST2_IRQn);
	InterruptUartAppTx();
    INTC_ClearPendingIRQ(ST2_IRQn);     /* clear INTST2 interrupt flag */
}

/*************************************************************************************************
* 函数名: InterruptUartAppRx
* 参  数: RxData:Uart接收的数据,从SBUF获取
* 返回值: 无
* 描  述: UART接收中断服务程序接口,中断处理函数会调用该函数
ucUartBuf[0]--Slave Addr
ucUartBuf[1]--CMD No.
ucUartBuf[2]--Data Length
ucUartBuf[3...]--Data
*************************************************************************************************/
void InterruptUartAppRx(U8 RxData)
{
	ucUartBuf[ucUartBufPT] = RxData;

	ucUartBufPT++;

	if(ucUartBufPT >= 140)
	{
		ucUartBufPT = 0;
	}
	if(ucUartBufPT == 1)//根据第一个字节来判断是读操作还是写操作
	{ 
			if((ucUartBuf[UART_SLAVE_ADDR]&0x01)==0)     //bit7是R/W标志;0--R, 1--W
			{
				bUartReadFlg = 1;
                bUartWriteFlg = 0;
			}
			else
			{
				bUartWriteFlg = 1;
                bUartReadFlg = 0;
			}       
	}
	
	if(bUartReadFlg)
	{
		if(ucUartBufPT==3)
		{
			UartRdCmdProcess();                       //Read the command process			
		}
	}
	else if(bUartWriteFlg)
	{
		if(ucUartBufPT > (ucUartBuf[UART_LENGTH]+3))
		{
			UartWrCmdProcess();                //Write the command peocess
			bUartWriteFlg = 0;                 //PC write MCU communiaction over
			ucUartBufPT = 0;
		}
	}
}
/*************************************************************************************************
* 函数名: UartRdCmdProcess
* 参  数: 无
* 返回值: 无
* 描  述: 处理各种读操作的命令,可自己定义
*************************************************************************************************/
void UartRdCmdProcess(void)
{
	switch(ucUartBuf[UART_CMD_NO])
	{
		case CELL1:
		case CELL2:
		case CELL3:
		case CELL4:
		case CELL5:
		case CELL6:
		case CELL7:
			UartReadInfo((U8  *)&Info.uiVCell[ucUartBuf[UART_CMD_NO]-1]);
			break;

		case TOTAL_VOLTAGE:
			UartReadInfo((U8  *)&Info.ulVoltage);
			break;

		case ADC_CURRENT:
			UartReadInfo((U8  *)&Info.slCurr);
			break;
		
		case ADC_CURRENT2:
			UartReadInfo((U8  *)&Info.slCurr2);
			break;
		
		case EXT_TEMP:
            UartReadInfo((U8  *)&Info.uiTS);
			break;
        		
		case FULL_CHG_CAP:
			UartReadInfo((U8  *)&Info.ulFCC);
			break;

		case REMAIN_CAP:
			UartReadInfo((U8  *)&Info.ulRC);
			break;

		case R_SOC:
			UartReadInfo((U8  *)&Info.uiRSOC);
			break;

		case CYCLE_COUNT:
			UartReadInfo((U8  *)&Info.uiCycleCount);
			break;

		case PACK_STATUS:
			UartReadInfo((U8  *)&Info.uiPackStatus);
			break;

		case BATTERY_STATUS:
			UartReadInfo((U8  *)&Info.uiBatStatus);
			break;

		case PACK_CONFIG:
			UartReadInfo((U8  *)&Info.uiPackConfig);
			break;

		case MANUFACTURE_COMMAND:
			UartReadInfo((U8  *)&Info.uiManuCommand);
			break;

		default:   
			break;
	}
}
/*************************************************************************************************
* 函数名: UartWrCmdProcess
* 参  数: 无
* 返回值: 无
* 描  述: 处理各种写操作的命令,可自己定义
*************************************************************************************************/
void UartWrCmdProcess(void)
{
    switch(ucUartBuf[UART_CMD_NO])
    {
        case MANUFACTURE_COMMAND:			
            WriteManufacture();
			break;
		
        case DATA_FLASH_COMMAND:  
            ReadSubClassID();               //accept command is dataflashcommand 0x77
			break;
	
        default:
			break;
    }
}
/*************************************************************************************************
* 函数名: UartReadInfo
* 参  数: ptr:数据需要读出的起始地址
* 返回值: 无
* 描  述: UART读数据
*************************************************************************************************/
void UartReadInfo(U8  *ptr)
{
	U8 i;

	if(ucUartBuf[UART_LENGTH] > 140)
	{
		ucUartBuf[UART_LENGTH] = 0;
	}
    
	for(i=0; i<ucUartBuf[UART_LENGTH]; i++)
	{
		ucUartBuf[ucUartBuf[UART_LENGTH]+2-i] =  *ptr;
		ptr++;
		
	}
	
	ucUartBuf[3+ucUartBuf[UART_LENGTH]] = 
    CRC8cal(&ucUartBuf[0],ucUartBuf[UART_LENGTH]+3);
	UART2_Send_Byte(ucUartBuf[ucUartBufPT]);
}
/*************************************************************************************************
* 函数名: CRC8cal
* 参  数: *p:数据指针;counter:所需计算的长度
* 返回值: 无
* 描  述: CRC8计算
*************************************************************************************************/
U8 CRC8cal(U8 *p, U8 counter)
{
	U8 i;
	U8 crc=0;
    
	while(counter-- != 0)
	{
		for(i=0x80; i!=0; i/=2)
		{
			if((crc & 0x80) != 0)
			{
				crc *= 2;
				crc ^= 0x107;
			}
			else
            {
				crc *= 2;
            }

			if((*p & i)!=0)
            {
				crc ^= 0x107;
            }
		}
		p++;
	}
	return(crc);
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

自定义串口通讯协议 的相关文章

  • 推荐几本学uc/os-II的书

    1 xff08 比较难买 xff09 嵌入式实时操作系统uc os II教程 西安电子科技大学出版 这本书对UCOS的源代码分析的非常清楚 比作者原著 在某种程度上要好 xff0c 这本书对关键的代码都给出了流程图 xff01 2 xff0
  • Python os.path.join(a, b) a,b 包含根Linux路径时合并根路径

    文章目录 1 代码 1 代码 span class token operator gt gt span span class token operator gt span a span class token operator 61 spa
  • 1 Mac安装minconda 与 Pytorch

    文章目录 1 miniconda 安装2 配置清华镜像3 下载Pytorch参考 1 miniconda 安装 使用清华镜像 xff1a https mirrors tuna tsinghua edu cn anaconda minicon
  • python:invalid literal for int() with base

    文章目录 1 出现原因2 出现的情景3 解决字符串类型的数据转化 1 出现原因 使用了int 函数且int 转化的对象为非数字型字符串或者浮点型数字字符串 2 出现的情景 数字型字符串无法转化 span class token builti
  • JavaWeb

    JavaWeb Java web 1 基本概念 1 1 前言 web开发 xff1a web xff1a 网页的意思 www baidu com 静态web html Css提供给所有人看的数据始终不会发生变化 xff01 动态web 淘宝
  • 将Windows复制的文字或文件粘贴到VMware

    如果想将Windows中的文件复制到VMware的Linux虚拟机中 xff0c 或者将Windows中复制的命令粘贴到VMware中 xff0c 该怎么办呢 xff1f 需要安装 VMware Tools 安装VMware Tools最简
  • 硬实时RTLinux?为Linux打实时preempt_rt补丁

    开发环境为vm ware创建的ubuntu 20 04虚拟机 xff0c 4G内存 xff0c 80G硬盘 xff0c 4核处理器 一 准备工作 1 内核与补丁下载 xff1a 下载与Linux系统相近版本的内核源码 xff08 Linux
  • 为树莓派打实时preempt_rt补丁

    开发环境 xff1a 树莓派4B xff0c 树莓派系统为Raspberry Pi OS Lite 64bit 本地进行 xff0c windows系统 43 PuTTY 即可 非 4B 或 64bit 版本 xff0c 可能有些许差别 x
  • Linux命令行访问U盘内容

    如果只是用命令行怎么去访问U盘内容呢 xff1f 比如说使用 PuTTY 访问树莓派的时候 插入U盘之后 xff0c 输入以下命令 xff0c 查看U盘的信息 sudo su fdisk l 最下面一行就是U盘的信息 xff0c 可以根据U
  • Shell学习--Shell变量与Shell数组

    一 普通变量 1 定义变量时直接赋值 xff0c 不需要 等特殊符号 name 61 34 Tom 34 注 xff1a 变量名和等号之间不能有空格 2 使用一个定义过的变量 xff0c 只要在变量名前面加 符号即可 花括号是为了帮助解释器
  • Shell学习--传递参数

    我们可以在执行 Shell 脚本时 xff0c 向脚本传递参数 xff0c 脚本内获取参数的格式为 xff1a n n 代表一个数字 xff0c 1 为执行脚本的第一个参数 xff0c 2 为执行脚本的第二个参数 xff0c 以此类推 实例
  • Docker Dockerfile

    镜像的生成途径 xff1a Dockerfile基于容器制作 本篇介绍Dockerfile 文件说明 Dockerfile是一个包含用于组合映像的命令的文本文档 Docker通过读取Dockerfile中的指令自动生成镜像 基本结构 基本格
  • Shell学习--基本运算符与test命令

    原生bash不支持简单的数学运算 xff0c 但是可以通过其他命令来实现 xff0c 例如 awk 和 expr xff0c expr 最常用 expr 是一款表达式计算工具 xff0c 使用它能完成表达式的求值操作 例如 xff0c 两个
  • Shell学习--echo命令

    echo 用于字符串的输出 xff0c 命令格式如下 xff1a echo string 1 显示普通字符串 echo 34 It is a test 34 二者效果一致 echo It is a test 2 显示转义字符 xff0c 双
  • Shell学习--printf命令

    printf 命令模仿 C 程序库 xff08 library xff09 里的 printf 程序 xff0c 使用 printf 的脚本比使用 echo 移植性好 printf 使用引用文本或空格分隔的参数 xff0c 外面可以在 pr
  • Shell学习--流程控制

    一 if else 1 if 语法格式 if condition then command1 command2 commandN fi 也可以写成一行 if ps ef grep c 34 ssh 34 gt 1 then echo 34
  • Shell学习--Shell函数

    linux shell 可以用户定义函数 xff0c 然后在shell脚本中可以随便调用 一 简单的函数定义 1 shell中函数的定义格式如下 xff1a function funname action return int 说明 xff
  • Shell学习--Shell 输入/输出重定向

    大多数 UNIX 系统命令从你的终端接受输入并将所产生的输出发送回 到您的终端 一个命令通常从一个叫标准输入的地方读取输入 xff0c 默认情况下 xff0c 这恰好是你的终端 同样 xff0c 一个命令通常将其输出写入到标准输出 xff0

随机推荐

  • Shell学习--Shell 文件包含

    和其他语言一样 xff0c Shell 也可以包含外部脚本 这样可以很方便的封装一些公用的代码作为一个独立的文件 Shell 文件包含的语法格式如下 xff1a filename 注意点号 和文件名中间有一空格 或 source filen
  • 向Github上传文件或项目

    准备工作 xff1a 具有 Github 账号 xff0c 电脑已安装 Git Bash 一 在 Github 上创建新的仓库 1 登录到 Github 主页创建一个新的仓库 xff08 两种方法都可以 xff09 2 配置新建仓库的属性
  • Github分支创建、管理、下载与上传

    当我们想进行文件备份 文件分类 版本更新 分工合作等工作时 xff0c 对github仓库进行分支就变得非常重要 一 创建分支 在Github仓库创建时会生成默认的主分支 xff0c 一般名称为 main xff0c 我们可以以主分支为基础
  • 删除Github仓库中的指定的文件或文件夹

    在Github 仓库中是无法通过鼠标操作直接删除文件和文件夹的 xff0c 那只能通过 git 命令来执行删除操作 xff0c 当我们想删除 First 分支中的 folder 文件夹及其内部的文件 和 file c 文件 时 一 获取当前
  • 如何判断栈、堆的增长方向?

    如何判断栈的增长方向 xff1f 对于一个用惯了i386系列机器的人来说 xff0c 这似乎是一个无聊的问题 xff0c 因为栈就是从高地址向低地址增长 不过 xff0c 显然这不是这个问题的目的 xff0c 既然把这个问题拿出来 xff0
  • 向文件最后一行添加字符串

    当我们想向某个文件中添加指定的字符串时 xff0c 可以使用相关的指令 一 echo指令 使用echo追加重定向可以直接向文件中添加一行字符串 echo 34 add string 34 gt gt test txt 可以看到echo会在文
  • KernelShark分析内核任务执行过程

    一 KernelShark简介 KernelShark是一个非常实用的工具 xff0c 其可以搭配 trace cmd 使用 xff0c 将内核的任务执行过程以直观的形式展现出来 下面的文档中详细的介绍了KernelShark的使用方法和功
  • 关于Linux中断的相关查询

    1 linux 内核 proc interrupts 在 proc interrupts 文件中记录了 Linux 内核的中断信息 xff0c 我们可以通过命令查看 sudo cat proc interrupts 文件中以表格的形式列举出
  • Latex中编译IEEE sensors journal 模板中遇到的种种问题

    总的来说 xff0c 这个期刊的模板跟之前那个TIE的模板不太一样 xff0c 因为目前只接触了这两个 xff08 本人水平比较菜 xff09 1 编译左上角的Logo xff0c 一直在报错 xff0c 并没有显示成功 xff0c 一直显
  • python笔记:argparse模块

    用途 python用于解析命令行参数和选项的标准模块 xff0c 内置于python xff0c 不需要安装 使用步骤 引入模块 span class token keyword import span argparse 创建一个解析器 使
  • Hadoop伪分布部署

    Hadoop伪分布部署 一 任务描述二 任务目标三 任务环境四 任务分析五 任务实施步骤1 解压Hadoop压缩包步骤2 配置Hadoop文件 六 任务测试 原创申明 xff1a 未经许可 xff0c 禁止以任何形式转载 xff0c 若要引
  • ubuntu下共存多个python版本,切换python版本

    ubuntu下切换默认python版本 知乎 zhihu com 1 以 root 身份登录 xff0c 首先罗列出所有可用的python 替代版本信息 update alternatives list python 这一步可能会报错upd
  • Deformable DETR进行目标检测,解决size mismatch问题

    问题描述 xff1a strict 61 False 但还是size mismatch for copying a param with shape from checkpoint the shape in cur 接着 6条消息 Defo
  • CubeMX 配置PWM使用DMA,生成Dshot600的协议

    看到电调支持Dshot125 600的协议 xff0c 想自己做一个支持Dshot协议的驱动 xff0c 所以研究了一下 xff0c 如何利用精确的PWM产生Dshot协议 先看结果 xff01 图中为油门值为1500的时候的输出的Dsho
  • Linux驱动开发——串口设备驱动

    Linux驱动开发 串口设备驱动 一 串口简介 串口全称叫做串行接口 xff0c 通常也叫做 COM 接口 xff0c 串行接口指的是数据一个一个的顺序传输 xff0c 通信线路简单 使用两条线即可实现双向通信 xff0c 一条用于发送 x
  • 1.开始在leetCode中刷题的一些感受

    最近项目上没有什么事情 xff0c 鉴于自己的基础比较差 xff0c 正好最近也开始学习了Python xff0c 就想在leetCode中使用Python语言刷刷题 xff0c 加强一下自己的算法的能力 下面就来谈谈最近刷题的一些感受 x
  • mathtype公式经常闪现,然后公式删除变成了字母c

    解决方案 百度 关闭金山词霸中的 划译 功能就OK啦 xff0c 具体情况具体分析 xff0c 大家可以试一下这种方法 个人经历 上一次是 Ctrl 43 C Ctrl 43 V 无法正常使用 xff0c 最后关闭有道的划译功能就完美解决了
  • RT-Thread学习入门之RT-Thread Studio的使用

    本科生因做比赛需要 xff0c 使用RT Thread Studio进行stm32f407ZGT6的程序开发 xff0c 文章仅以用来记录过程 系列文章目录 第一篇 RT Thread学习入门之RT Thread Studio的使用 第二篇
  • 【CSDN三周年纪念日】我的创作纪念日

    2019年09 月 17 日 xff0c 一个看似平凡的一天 在这么平凡的一天里 xff0c 我发表了第一篇博客 在这平凡的一天 xff0c 赋予了它不平凡的意义 也许是立志成为一名专业 IT 作者 也许是记录一段刚实践的经验 但在那一刻
  • 自定义串口通讯协议

    通信协议 1 读操作 主机发送设备地址0x0A 读命令字 数据长度 xff08 数据长度不包括CRC xff09 xff0c 当主机接收完数据和CRC后 xff0c 需要进行数据校验 xff0c 并和从机返回的CRC进行对比 数据校验方式为