串口调试界面如下:
协议如下:
1、 此协议为半全工UART通讯,9600波特率,1位起始位,8位数据位,无奇偶校验,1位停止位; 上位面板为主机,电机驱动板为从机,主机和从机周期事件发送一帧数据,周期为100ms; 同一个命令主机必须发送三次及以上,以方便下位机接收命令进行校准。当通信检测超过2s未收到 信息时,从机会自动停机并报通信故障。 2、 面板向电机驱动板发送的一帧命令数据包包含如下信息: 起始码(1字节)+功能命令(CMD,1字节)+数据(DATA0,DATA1,2字节)+校验码(CHECKSUM,1字节)。 a. 空闲:不发数据时为高电平,收发双方为高电平。 b. 起始码: 0x5a c. 校验:CHECKSUM = (STARTID + CMD + DATA0 + DATA1)。相加后的溢出位舍去。 起始码 | | | | | | | BIT0-2:1表示启动电机; 0表示停止电机, 其他值表示保持当前状态不变。 BIT3: 清零故障。 | | | | 1、电机驱动板接收速度数据RPM=DATA1*256+DATA0. 2、当电机发生故障自动停机后,若想让电机重启,需要置位BIT3,清零电机故障信息后重新启动电机。 |
举例1:面板发送以1024RPM转速启动电机的指令数据帧为: 0x5a,0x01,0x00,0x04,0x5f. 举例2:面板发送以1024RPM转速,清零故障信息重新启动电机的指令数据帧为: 0x5a,0x09,0x00,0x04,0x67. 3、 电机向面板发送的命令数据格式: 起始码(1字节)+功能命令(CMD,1字节)+数据(DATA0-DATA6,7字节)+校验码(CHECKSUM,1字节)。 a. 空闲:不发数据时为高电平,收发双方为高电平。 b. 起始码: 0xa5 c. 校验:CHECKSUM = (STARTID+ CMD + DATA0 + DATA1+…..DATA6)。相加后的溢出位舍去。 d. DATA0,DATA1,表示速度;DATA2,DATA3,表示故障; DATA4,DATA5,DATA6为备用,用户可根据需要自行定义如电机电流、电压等信息。 起始码 | | | | | | | BIT0-1:0,表示电机工作正常。 1,表示电机故障已自动停机。 | | | | DATA0,DATA1表示电机速度数据;RPM=DATA1*256+DATA0. DATA2,DATA3表示故障信息; DATA2.BIT0:表示峰值电流保护DATA2.BIT1:表示均值电流0保护DATA2.BIT2:表示均值电流1保护 DATA2.BIT3:表示过压保护 DATA2.BIT4:表示欠压保护DATA2.BIT5:表示过温保护DATA2.BIT6:表示缺相保护 DATA2.BIT7:表示堵转保护 DATA3.BIT0:表示硬件过流保护DATA3.BIT1:表示MCU的ID保护DATA3.BIT2:表示通讯故障保护 DATA4-DATA6预留 |
例3:当电机正常工作时,电机驱动板发出1024RPM转速的数据帧: 0xa5,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0xa9, 例4:当电机欠压停机时,电机驱动板发出0RPM转速的数据帧: 0xa5,0x01,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0xae,
部分代码如下: //////////////////////////////////////////////////////////////////////////
//函数名称: void Usart_Config(u32 BaudRate)
//函数功能说名:串口初始化
//输入参数: 无
//输出参数: 无
//调用函数: 无
//完成时间:2022-02-28
//作者: Danny
/////////////////////////////////////////////////////////////// void Usart_Config(u32 BaudRate) { UART_InitTypeDef UART_InitStruct; UART_StructInit(&UART_InitStruct); UART_InitStruct.BaudRate = BaudRate; UART_InitStruct.WordLength = UART_WORDLENGTH_8b; UART_InitStruct.StopBits = UART_STOPBITS_1b; UART_InitStruct.FirstSend = UART_FIRSTSEND_LSB; UART_InitStruct.ParityMode = UART_Parity_NO; UART_InitStruct.IRQEna = 0; UART_Init(UART0, &UART_InitStruct);
} //////////////////////////////////////////////////////////////////////////
//函数名称: void ReceivedDataParsing(void)
//函数功能说明:接收数据解析
//输入参数:
//输出参数:
//调用函数: 无
//完成时间:2022-02-28
//作者: Danny
/////////////////////////////////////////////////////////////// void ReceivedDataParsing(void) //接收解析数据,用户可以根据自行的协议将接受的数据解析 { }
/* Local Variables----------------------------------------------------------*/ //////////////////////////////////////////////////////////////////////////
//函数名称: void Uart_RecieveCmd(void)
//函数功能说明:接收一帧固定长度数据,放在不小于500US的时间片中用于查询接收数据
//输入参数:
//输出参数:
//调用函数: ReceivedDataParsing(void)
//完成时间:2022-02-28
//作者: Danny
/////////////////////////////////////////////////////////////// void Uart_RecieveCmd(void) { static u8 UartRxIndex; if(UART_IF & BIT1) //接收完成事件 { UART_IF = BIT1; //清除接收完成标志位 UART_Compnent.RecvTimeCnt = 0; UART_Compnent.RecieveBuff[UART_Compnent.Rcv_Ptr++] = UART_ReadData(UART0); if(UART_Compnent.RecieveBuff[RX_HEADER_ADDR] != RX_FRAME_HEADER_DATA) { UART_Compnent.Rcv_Ptr = 0; } else { if(UART_Compnent.Rcv_Ptr >= RX_DATA_LENGTH) { UART_Compnent.Rcv_Ptr =0; //一帧数据接收完,接收指针清零 UART_Compnent.CalcRxdCheakSum = 0; //验证校验和清零 for(UartRxIndex = 0;UartRxIndex < RX_CHEAKSUM_A_ADDR;UartRxIndex++) //验证校验和 { UART_Compnent.CalcRxdCheakSum += UART_Compnent.RecieveBuff[UartRxIndex]; } if(UART_Compnent.CalcRxdCheakSum == UART_Compnent.RecieveBuff[RX_CHEAKSUM_A_ADDR])//校验码正确解析一帧数据 { if(UART_Compnent.RecDataCompFlag) //二次确认后接收命令信息 { ReceivedDataParsing(); } UART_Compnent.RecDataCompFlag = 1; } else { UART_Compnent.RecDataCompFlag = 0; } } } } if(UART_Compnent.RecvTimeCnt++ > RX_TIMEOUT_DIV)//长时间没接收到数据清零接收指针,用户可以在此加入通讯故障标志,表示长时间未和上位机取得通讯 { UART_Compnent.Rcv_Ptr = 0; UART_Compnent.RecvTimeCnt = 0;
} }
//////////////////////////////////////////////////////////////////////////
//函数名称: void TxdDataProcessing(void)
//函数功能说明:发送数据处理,客户按自行协议增加返回数据
//输入参数:
//输出参数:
//调用函数: 无
//完成时间:2022-02-28
//作者: Danny
/////////////////////////////////////////////////////////////// void TxdDataProcessing(void) { static u8 UartTxIndex; UART_Compnent.SendBuff[TX_HEADER_ADDR] = TX_FRAME_HEADER_DATA; UART_Compnent.SendBuff[TX_MOTOR_STATE_ADDR] = UART_Compnent.Txd_State; UART_Compnent.CalcTxdCheakSum = 0; for(UartTxIndex = 0;UartTxIndex < (TX_CHEAKSUM_A_ADDR);UartTxIndex++) //验证校验和 { UART_Compnent.CalcTxdCheakSum += UART_Compnent.SendBuff[UartTxIndex]; } UART_Compnent.SendBuff[TX_CHEAKSUM_A_ADDR] = UART_Compnent.CalcTxdCheakSum;
}
//////////////////////////////////////////////////////////////////////////
//函数名称: void Uart_TxdCmd(void)
//函数功能说明:发送一帧固定长度数据
//输入参数:
//输出参数:
//调用函数: 无
//完成时间:2022-02-28
//作者: Danny
/////////////////////////////////////////////////////////////// void Uart_TxdCmd(void) { if(++UART_Compnent.Txd_Clk_Div >= UART_PERIOD_DIV) //定义发送一帧数据周期,100ms,在全双工通讯时定义的发送周期,此时需打开周期发送标志,在半双工通讯无功能。 {
UART_Compnent.Start_Txd_Flag = 1; if((UART_Compnent.Txd_Clk_Div%TX_TIME_MS_DIV)== 0) { UART_Compnent.Txd_Clk_Div = 0; } } if((UART_Compnent.Txd_Clk_Div%TX_TIME_MS_DIV)== 0)//分频发送时间,防止一个字节数据发送没完成,又向buff装载数据 { if(UART_Compnent.Start_Txd_Flag) { if(UART_Compnent.Txd_Ptr++ >= TX_DATA_LENGTH) { UART_Compnent.Txd_Ptr = 0; if(UART_Compnent.Txd_En_Flag) { UART_Compnent.Start_Txd_Flag = 0; } UART_Compnent.Txd_En_Flag = 1; TxdDataProcessing(); } else { if(UART_Compnent.Txd_En_Flag) { UART_SendData(UART0, UART_Compnent.SendBuff[UART_Compnent.Txd_Ptr-1]); } } } } }
|