这次测试完成了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的频率下,运行该流程的测试了,单步测试已经可以完成正常的电机控制。