通信协议
1.读操作
主机发送设备地址0x0A、读命令字、数据长度(数据长度不包括CRC),当主机接收完数据和CRC后,需要进行数据校验,并和从机返回的CRC进行对比。数据校验方式为CRC8。CRC8会从主机发送的地址开始校验,包括地址(0x0A)、读命令字、读取的数据长度N、以及从机返回的N字节数据,校验多项式为X8 +X2 +X+1。
2.写操作
主机发送设备地址0x0A | 0x01、写命令字、数据长度(数据长度不包括CRC)、N字节数据、CRC;从机接收完数据和CRC后,需要进行数据校验,结果OK则返回ACK,否则返回NACK。数据校验方式为CRC8。CRC8会从主机发送的地址开始校验,包括地址(0x0A|0x01)、写命令字、写的数据长度N和N字节数据,校验多项式为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);
}