自定义串口通讯协议

通信协议

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);
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

红红火火恍恍惚惚.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值