这次测试完成了CAN通信。
首先是添加了电机控制的函数:
void motor_control(CAN_HandleTypeDef* hcan, uint8_t can_id)
{
if(HAL_CAN_IsTxMessagePending(hcan, CAN_TX_MAILBOX0 | CAN_TX_MAILBOX1 | CAN_TX_MAILBOX2)) {
HAL_CAN_AbortTxRequest(hcan, CAN_TX_MAILBOX0 | CAN_TX_MAILBOX1 | CAN_TX_MAILBOX2);
}
uint8_t delay = 150;
if(motor_enable[can_id] == 0 && g_cmd.leg[can_id].flag == 1)
{
motor_enable[can_id] = g_cmd.leg[can_id].flag;
enter_motor_mode(can_tx_data);
CANx_SendStdData(hcan, 0x01, can_tx_data, 8);
delay_us(delay);
CANx_SendStdData(hcan, 0x02, can_tx_data, 8);
delay_us(delay);
CANx_SendStdData(hcan, 0x03, can_tx_data, 8);
delay_us(delay);
}
else if(motor_enable[can_id] == 1 && g_cmd.leg[can_id].flag == 0)
{
motor_enable[can_id] = g_cmd.leg[can_id].flag;
exit_motor_mode(can_tx_data);
CANx_SendStdData(hcan, 0x01, can_tx_data, 8);
delay_us(delay);
CANx_SendStdData(hcan, 0x02, can_tx_data, 8);
delay_us(delay);
CANx_SendStdData(hcan, 0x03, can_tx_data, 8);
delay_us(delay);
}
pack_cmd(can_tx_data, &g_cmd.leg[can_id].motor[0]);
CANx_SendStdData(hcan, 0x01, can_tx_data, 8);
delay_us(delay);
pack_cmd(can_tx_data, &g_cmd.leg[can_id].motor[1]);
CANx_SendStdData(hcan, 0x02, can_tx_data, 8);
delay_us(delay);
pack_cmd(can_tx_data, &g_cmd.leg[can_id].motor[2]);
CANx_SendStdData(hcan, 0x03, can_tx_data, 8);
delay_us(delay);
}
经过反复测试,原版的CAN总线通信延时20us,在当前程序中是无法完成通信的,同一时间发送的CAN数据太多会导致CAN的邮箱满了,使得电机控制的数据丢失。将延时扩展到150us,则可以达到很好的效果。
整体的运行流程是,首先接收到SPI通信的信号,随后通过事件告知CAN的任务开始运行,对两个CAN分别发送控制消息。在发送完成后,由默认任务进行最后的数据拷贝,为下一次通信做好准备。整个流程并不复杂:
/* USER CODE BEGIN Header_StartDefaultTask */
/**
* @brief Function implementing the mainTask thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartDefaultTask */
void StartDefaultTask(void *argument)
{
/* USER CODE BEGIN StartDefaultTask */
EventBits_t r_event = pdPASS;
/* Infinite loop */
for(;;)
{
r_event = osEventFlagsWait(CAN_EventHandle, EVENT1 | EVENT2, osFlagsWaitAll, portMAX_DELAY);
g_state.crc = calculate((uint8_t*)&g_state, sizeof(spine_state_t) - 4);
memcpy(spi_tx, &g_state, sizeof(spine_state_t));
//HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
//delay_us(50);
//HAL_UART_Transmit(&huart2, tx, sizeof(spine_state_t), 10000);
}
/* USER CODE END StartDefaultTask */
}
/* USER CODE BEGIN Header_Can1TaskFunc */
/**
* @brief Function implementing the Can1Task thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_Can1TaskFunc */
void Can1TaskFunc(void *argument)
{
/* USER CODE BEGIN Can1TaskFunc */
EventBits_t r_event = pdPASS;
/* Infinite loop */
for(;;)
{
r_event = osEventFlagsWait(SPI_EventHandle, EVENT1, osFlagsWaitAny, portMAX_DELAY);
motor_control(&hcan1, 0);
osEventFlagsSet(CAN_EventHandle, EVENT1);
}
/* USER CODE END Can1TaskFunc */
}
/* USER CODE BEGIN Header_Can2TaskFunc */
/**
* @brief Function implementing the Can2Task thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_Can2TaskFunc */
void Can2TaskFunc(void *argument)
{
/* USER CODE BEGIN Can2TaskFunc */
EventBits_t r_event = pdPASS;
/* Infinite loop */
for(;;)
{
r_event = osEventFlagsWait(SPI_EventHandle, EVENT2, osFlagsWaitAny, portMAX_DELAY);
motor_control(&hcan2, 1);
osEventFlagsSet(CAN_EventHandle, EVENT2);
}
/* USER CODE END Can2TaskFunc */
}
最后就剩下在500hz和1000hz的频率下,运行该流程的测试了,单步测试已经可以完成正常的电机控制。