stm32f407 双CAN通信 cubemx 使用yz_aim电机作为历程

一、简介

(1)can是一种异步通信,具有CAN—HIGH和CAN—LOW两条信号线,其差分输出的信号模式,提高了其传递的抗干扰性能。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
(2)CAN通信的显性和隐形,还有逻辑电平的1和0很容易混淆,可以这样理解,CAN是通过CAN-HIGH和CAH-LOW的电压差来实现逻辑转换的,二者都为2.5v时,电压差是0,称之为隐性,对应为逻辑1. HIGH3.5v,LOW为1.5v,压差是2,称之为显性,对应逻辑0.
CAN是半双工异步通信方式,can的协议层can的位时序和同步:
位时序的组成:包含4段,ss, pts,pbs1,pbs2,将这四段加一起就是一个can数据位的长度。分解后的最小时间单位是tq,一个完整的位由8到25个Tq组成。

在这里插入图片描述
在这里插入图片描述

二、特性

  1. 隔离CAN通信(EasyCan协议,简易,快速上手,速率1M)。支持轮廓位置模式,和,周期同步模式。
  2. 15位绝对编码器,一圈脉冲高达32768。
  3. 多圈绝对值(需配电池)。脉冲模式:重新上电自动回断电位置。
    通信模式:可断电记录位置。
  4. 多级DD马达结构,大扭力输出。
  5. 一体化伺服,简化接线,体积超小。
  6. 低噪音,低振动,高速定位,高可靠性。
  7. FOC场定向矢量控制,支持位置/速度闭环。
  8. 可工作在零滞后给定脉冲状态,跟随零滞后。
  9. 16位电子齿轮功能。
  10. 提供串口上位机,可监测电机状态和修改参数。
  11. 位置模式,支持脉冲+方向信号,编码器跟随
  12. 速度模式,支持PWM占空比信号调速
  13. 具有堵转,过流保护,过压保护。

三、示例代码

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "can.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "yz_aim.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* Private function prototypes -----------------------------------------------*/

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */
    uint16_t ret1=0;
    uint16_t ret2=0;
  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_CAN1_Init();
  MX_CAN2_Init();
  /* USER CODE BEGIN 2 */
    // HAL_Delay(200);
    // motor_stop(YZ_MOTOR_0);
    // HAL_Delay(10);
    // motor_stop(YZ_MOTOR_1);
    // HAL_Delay(200);
    // motor_relative_position_init(YZ_MOTOR_0);
    // HAL_Delay(10);
    // motor_set_trapezoidal_speed(YZ_MOTOR_0, 700); // 梯形速度写入 1500RPM
    // HAL_Delay(10);
    // motor_relative_position_init(YZ_MOTOR_1);
    // HAL_Delay(10);
    // motor_set_trapezoidal_speed(YZ_MOTOR_1, 200); // 梯形速度写入 500RPM
    // HAL_Delay(10);
    /* 设置找原点模式 */

    motor_test_find_the_origin();
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
    while (1)
    {
        ret1 = motor_get_state_word(YZ_MOTOR_0);
        if (ret1 != 0xFFFF)
        {
            if ((ret1 >> 12) & 0x01)
            {
                HAL_GPIO_TogglePin(LED0_GPIO_Port, LED0_Pin);
            }
            else
            {

            }
        }
        HAL_Delay(10);
        ret2 = motor_get_state_word(YZ_MOTOR_1);
        if (ret2 != 0xFFFF)
        {
            if ((ret2 >> 12) & 0x01)
            {
                HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
            }
            else
            {
                HAL_GPIO_TogglePin(BEEP_GPIO_Port, BEEP_Pin);
            }
        }
        HAL_Delay(500);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */

  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Configure the main internal regulator output voltage
  */
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 4;
  RCC_OscInitStruct.PLL.PLLN = 168;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 4;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
    /* User can add his own implementation to report the HAL error return state */
    while (1)
    {
    }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
    /* User can add his own implementation to report the file name and line number,
     tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

/********************************************************************************
* @file    yz_aim.c
* @author  jianqiang.xue
* @Version V1.0.0
* @Date    2021-05-05
* @brief   NULL
********************************************************************************/

/******************************************* 
CANopen 地址说明:
一个完整的 CANopen 地址格式为:60400010(控制字),
[6040]0010: Index(16 位地址)。
6040[00]10:Subindex(8 位子地址)形式表示寄存器寻址,
604000[10]:位数 0x08 表示此寄存器将存放的数据长度为 1 个 Byte,位数 0x10 表示存放的数据长度为 2 个
Byte,位数 0x20 表示存放的数据长度为 4 个 Byte,
R: 可读,W: 可写,S:可保存,M: 可映射,
*******************************************/

/******************************************* 
 * CAN 标识符          DLC(数据段长度)    1        (2   3)      4      5  6  7  8
 * 0x600 + device_ID      0x08        CS 命令符   对象索引    子索引   写入的数据
 *                                            高位在[3],底位在[2]     高位在[8]
 * CS 命令符: 0x2F=写1byte  0x2B=写2byte  0x23=写4byte
 *           0x40=读取
*******************************************/

/******************************************* 
 * 控制字(6040H)的位定义如下:
 * 位:    15:9    8      7          6             5             4            3       2       1       0
 * 定义:  无     停止  故障复位   0:绝对位置   位置立即生效  执行新设置点    允许操作 允许急停 电压输出  启动
 *                               1:相位位置
 * 
 * Bit0:置 1 后,外部脉冲控制无效。
 * Bit4:每写入一次 1,就运行到新位置值。执行新位置值后自动置 0;
 * Bit8:值为 1 时,电机急停,但是电机仍然是自锁状态。
*******************************************/

/******************************************* 
 * 状态字(6041H)的位定义如下:
 * 位:    7   6     5        4         3        2        1      0
 * 定义:  无  无  允许急停  电压输出  伺服报警  允许操作   启动  准备启动
 * 
 * 位:    15   14      13         12      11    10     9    8
 * 定义:  无   无   找原点错误  找原点完成  无  目标达到  无   无
 * 
 * 从机回复读命令符: 0x4F=读回复一个字节。 0x4B=读回复两个字节。0x43=读回复四个字节
*******************************************/

/* Includes ------------------------------------------------------------------*/
#include <stdio.h>
#include <string.h>

#include "can.h"
#include "yz_aim.h"

/* Private define ------------------------------------------------------------*/
#define MOTOR1_ID 0x601
#define MOTOR2_ID 0x601

/* Private variables ---------------------------------------------------------*/


/* Private function prototypes -----------------------------------------------*/
/***********************************基础层*************************************/
/**
  * @brief  设置状态字
  * @param  motor_id: 电机编号
  * @param  data: 状态字值
  * @retval None
  */
static void motor_set_control_word(yz_motor_t motor_id, uint16_t data)
{
    uint8_t buff[8] = {0x2B, 0x40, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00};

    buff[4] = (uint8_t)(data & 0x00ff);
    buff[5] = (uint8_t)((data & 0xff00) >> 8);

    if (motor_id == YZ_MOTOR_0)
    {
        can1_transmit(MOTOR1_ID, (uint8_t *)buff);
    }
    else if (motor_id == YZ_MOTOR_1)
    {
        can2_transmit(MOTOR2_ID, (uint8_t *)buff);
    }
}

/**
  * @brief  获取状态字
  * @param  motor_id: 电机编号
  * @retval 状态字值
  */
uint16_t motor_get_state_word(yz_motor_t motor_id)
{
    uint16_t i = 0xffff;
    uint8_t buff[8] = {0x40, 0x41, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00};

    if (motor_id == YZ_MOTOR_0)
    {
        can1_transmit(MOTOR1_ID, (uint8_t *)buff);
    }
    else if (motor_id == YZ_MOTOR_1)
    {
        can2_transmit(MOTOR2_ID, (uint8_t *)buff);
    }
    // 死等读取,后期如果上os后,可以换成os延时
    while (1)
    {
        i--;
        if (i == 0)
        {
            break;
        }
        if (motor_id == YZ_MOTOR_0)
        {
            if ((can1_recv_msg.data)[1] == 0x41 && (can1_recv_msg.data)[2] == 0x60)
            {
                return (buff[4]) | (buff[5] << 8);
            }
        }
        else if (motor_id == YZ_MOTOR_1)
        {
            if ((can2_recv_msg.data)[1] == 0x41 && (can2_recv_msg.data)[2] == 0x60)
            {
                return (buff[4]) | (buff[5] << 8);
            }
        }
    }
    return 0xFFFF;
}

/**
  * @brief  电机启动
  * @param  motor_id: 电机编号
  * @param  opt: 操作值[4:8]bit,支持混写
  * @retval 状态字值
  */
void motor_start(yz_motor_t motor_id, uint16_t opt)
{
    uint16_t data = 0;

    data = CONTROL_WORD_START | CONTROL_WORD_VOLTAGE_OUTPUT | CONTROL_WORD_EMERGENCY_STOP_EN | CONTROL_WORD_OPERATION_EN;

    data |= opt;

    motor_set_control_word(motor_id, data);
}

/**
  * @brief  电机停止
  * @param  motor_id: 电机编号
  * @retval None
  */
void motor_stop(yz_motor_t motor_id)
{
    motor_set_control_word(motor_id, 0x00);
}

/**
  * @brief  设置电机工作模式
  * @param  motor_id: 电机编号
  * @param  mode: 电机工作模式
  * @retval None
  */
void motor_set_work_mode(yz_motor_t motor_id, motor_work_mode_t mode)
{
    uint8_t buff[8] = {0x2F, 0x60, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00};

    buff[4] = (uint8_t)(mode & 0xff);

    if (motor_id == YZ_MOTOR_0)
    {
        can1_transmit(MOTOR1_ID, (uint8_t *)buff);
    }
    else if (motor_id == YZ_MOTOR_1)
    {
        can2_transmit(MOTOR2_ID, (uint8_t *)buff);
    }
}

/**
  * @brief  设置电机位置缓存
  * @param  motor_id: 电机编号
  * @param  val: 位置缓存值
  * @retval None
  */
void motor_set_location_cache(yz_motor_t motor_id, uint32_t val)
{
    uint8_t buff[8] = {0x23, 0x7A, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00};

    buff[4] = (uint8_t)(val & 0x000000ff);
    buff[5] = (uint8_t)((val & 0x0000ff00) >> 8);
    buff[6] = (uint8_t)((val & 0x00ff0000) >> 16);
    buff[7] = (uint8_t)((val & 0xff000000) >> 24);

    if (motor_id == YZ_MOTOR_0)
    {
        can1_transmit(MOTOR1_ID, (uint8_t *)buff);
    }
    else if (motor_id == YZ_MOTOR_1)
    {
        can2_transmit(MOTOR2_ID, (uint8_t *)buff);
    }
}

/**
  * @brief  设置电机转速
  * @param  motor_id: 电机编号
  * @param  val: 范围0~3000r/min
  * @retval None
  */
void motor_set_trapezoidal_speed(yz_motor_t motor_id, uint32_t val)
{
    uint8_t buff[8] = {0x23, 0x81, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00};

    buff[4] = (uint8_t)(val & 0x000000ff);
    buff[5] = (uint8_t)((val & 0x0000ff00) >> 8);
    buff[6] = (uint8_t)((val & 0x00ff0000) >> 16);
    buff[7] = (uint8_t)((val & 0xff000000) >> 24);

    if (motor_id == YZ_MOTOR_0)
    {
        can1_transmit(MOTOR1_ID, (uint8_t *)buff);
    }
    else if (motor_id == YZ_MOTOR_1)
    {
        can2_transmit(MOTOR2_ID, (uint8_t *)buff);
    }
}

/**
  * @brief  设置电机加速度
  * @param  motor_id: 电机编号
  * @param  val: 0~65535(r/min)/s  参数小于 60000 时,驱动器内部产生加减速曲线,
  *              参数大于60000 时,驱动器内部不产生加减速脉冲
  * @retval None
  */
void motor_set_trapezoidal_acceleration(yz_motor_t motor_id, uint32_t val)
{
    uint8_t buff[8] = {0x23, 0x83, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00};

    buff[4] = (uint8_t)(val & 0x000000ff);
    buff[5] = (uint8_t)((val & 0x0000ff00) >> 8);
    buff[6] = (uint8_t)((val & 0x00ff0000) >> 16);
    buff[7] = (uint8_t)((val & 0xff000000) >> 24);

    if (motor_id == YZ_MOTOR_0)
    {
        can1_transmit(MOTOR1_ID, (uint8_t *)buff);
    }
    else if (motor_id == YZ_MOTOR_1)
    {
        can2_transmit(MOTOR2_ID, (uint8_t *)buff);
    }
}

/**
  * @brief  获取电机当前位置
  * @param  motor_id: 电机编号
  * @retval 电机当前的实际位置
  */
uint32_t motor_get_current_location(yz_motor_t motor_id)
{
    uint16_t i = 0xffff;
    uint8_t buff[8] = {0x40, 0x64, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00};

    if (motor_id == YZ_MOTOR_0)
    {
        can1_transmit(MOTOR1_ID, (uint8_t *)buff);
    }
    else if (motor_id == YZ_MOTOR_1)
    {
        can2_transmit(MOTOR2_ID, (uint8_t *)buff);
    }
    // 死等读取,后期如果上os后,可以换成os延时
    while (1)
    {
        i--;
        if (i == 0)
        {
            break;
        }
        if (motor_id == YZ_MOTOR_0)
        {
            if ((can1_recv_msg.data)[1] == 0x64 && (can1_recv_msg.data)[2] == 0x60)
            {
                return (buff[4]) | (buff[5] << 8) | (buff[6] << 16) | (buff[7] << 24);
            }
        }
        else if (motor_id == YZ_MOTOR_1)
        {
            if ((can2_recv_msg.data)[1] == 0x64 && (can2_recv_msg.data)[2] == 0x60)
            {
                return (buff[4]) | (buff[5] << 8) | (buff[6] << 16) | (buff[7] << 24);
            }
        }
    }
    return 0;
}

/**
  * @brief  设置电机回原点方法
  * @param  type: 找原点方法 [17:22]
  * @retval 0--成功 1--错误
  */
uint8_t motor_set_find_origin_mode(yz_motor_t motor_id, uint8_t type)
{
    uint8_t buff[8] = {0x2f, 0x98, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00};

    if (type > 22 || type < 17)
    {
        return 1;
    }

    buff[4] = type;

    if (motor_id == YZ_MOTOR_0)
    {
        can1_transmit(MOTOR1_ID, (uint8_t *)buff);
    }
    else if (motor_id == YZ_MOTOR_1)
    {
        can2_transmit(MOTOR2_ID, (uint8_t *)buff);
    }
    return 0;
}

/**
  * @brief  设置电机最大允许电流
  * @param  motor_id: 电机编号
  * @param  max_val: 最大工作允许电流 [0-10000]mA
  * @param  keep_time: 最大电流持续多长时间才报警[0-9]s
  * @retval None
  */
void motor_set_max_electric(yz_motor_t motor_id, uint32_t val, uint8_t keep_time)
{
    uint8_t buff[8] = {0x23, 0x83, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00};

    buff[4] = (uint8_t)(val & 0x000000ff);
    buff[5] = (uint8_t)((val & 0x0000ff00) >> 8);
    buff[6] = (uint8_t)((val & 0x00ff0000) >> 16);
    buff[7] = (uint8_t)((val & 0xff000000) >> 24);

    if (motor_id == YZ_MOTOR_0)
    {
        can1_transmit(MOTOR1_ID, (uint8_t *)buff);
    }
    else if (motor_id == YZ_MOTOR_1)
    {
        can2_transmit(MOTOR2_ID, (uint8_t *)buff);
    }
}

/**
  * @brief  设置电机相对角度
  * @param  motor_id: 电机编号
  * @param  degree: 角度
  * @retval None
  */
void motor_set_relative_degree(yz_motor_t motor_id, int16_t degree)
{
    motor_set_location_cache(motor_id, ((32768 * 80) / 360) * degree);
}

/**
  * @brief  得到厂家ID
  * @param  motor_id: 电机编号
  * @retval None
  */
uint32_t motor_get_manufacturer_id(yz_motor_t motor_id)
{
    uint8_t buff[8] = {0x40, 0x18, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00};
    uint32_t i = 0xffff;

    if (motor_id == YZ_MOTOR_0)
    {
        can1_transmit(MOTOR1_ID, (uint8_t *)buff);
    }
    else if (motor_id == YZ_MOTOR_1)
    {
        can2_transmit(MOTOR2_ID, (uint8_t *)buff);
    }
    while (1)
    {
        i--;
        if (i == 0)
        {
            break;
        }
        if (motor_id == YZ_MOTOR_0)
        {
            if ((can1_recv_msg.data)[1] == 0x18 && (can1_recv_msg.data)[2] == 0x10)
            {
                return (buff[4]) | (buff[5] << 8) | (buff[6] << 16) | (buff[7] << 24);
            }
        }
        else if (motor_id == YZ_MOTOR_1)
        {
            if ((can2_recv_msg.data)[1] == 0x18 && (can2_recv_msg.data)[2] == 0x10)
            {
                return (buff[4]) | (buff[5] << 8) | (buff[6] << 16) | (buff[7] << 24);
            }
        }
    }
    return 0xFFFF;
}

/**
  * @brief  得到系统电压
  * @param  motor_id: 电机编号
  * @retval None
  */
uint16_t motor_get_sys_vcc(yz_motor_t motor_id)
{
    uint8_t buff[8] = {0x40, 0x79, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00};
    uint16_t i = 0xffff;

    if (motor_id == YZ_MOTOR_0)
    {
        can1_transmit(MOTOR1_ID, (uint8_t *)buff);
    }
    else if (motor_id == YZ_MOTOR_1)
    {
        can2_transmit(MOTOR2_ID, (uint8_t *)buff);
    }
    while (1)
    {
        i--;
        if (i == 0)
        {
            break;
        }
        if (motor_id == YZ_MOTOR_0)
        {
            if ((can1_recv_msg.data)[1] == buff[1] && (can1_recv_msg.data)[2] == buff[2])
            {
                return (buff[4]) | (buff[5] << 8);
            }
        }
        else if (motor_id == YZ_MOTOR_1)
        {
            if ((can2_recv_msg.data)[1] == buff[1] && (can2_recv_msg.data)[2] == buff[2])
            {
                return (buff[4]) | (buff[5] << 8);
            }
        }
    }
    return 0xFFFF;
}

/**
  * @brief  得到系统温度
  * @param  motor_id: 电机编号
  * @retval None
  */
uint16_t motor_get_sys_temp(yz_motor_t motor_id)
{
    uint8_t buff[8] = {0x40, 0x12, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00};
    uint16_t i = 0xffff;

    if (motor_id == YZ_MOTOR_0)
    {
        can1_transmit(MOTOR1_ID, (uint8_t *)buff);
    }
    else if (motor_id == YZ_MOTOR_1)
    {
        can2_transmit(MOTOR2_ID, (uint8_t *)buff);
    }
    while (1)
    {
        i--;
        if (i == 0)
        {
            break;
        }
        if (motor_id == YZ_MOTOR_0)
        {
            if ((can1_recv_msg.data)[1] == buff[1] && (can1_recv_msg.data)[2] == buff[2])
            {
                return (buff[4]) | (buff[5] << 8);
            }
        }
        else if (motor_id == YZ_MOTOR_1)
        {
            if ((can2_recv_msg.data)[1] == buff[1] && (can2_recv_msg.data)[2] == buff[2])
            {
                return (buff[4]) | (buff[5] << 8);
            }
        }
    }
    return 0xFFFF;
}

/**
  * @brief  得到系统温度
  * @param  motor_id: 电机编号
  * @retval None
  */
uint16_t motor_get_sys_pwm(yz_motor_t motor_id)
{
    uint8_t buff[8] = {0x40, 0x13, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00};
    uint16_t i = 0xffff;

    if (motor_id == YZ_MOTOR_0)
    {
        can1_transmit(MOTOR1_ID, (uint8_t *)buff);
    }
    else if (motor_id == YZ_MOTOR_1)
    {
        can2_transmit(MOTOR2_ID, (uint8_t *)buff);
    }
    while (1)
    {
        i--;
        if (i == 0)
        {
            break;
        }
        if (motor_id == YZ_MOTOR_0)
        {
            if ((can1_recv_msg.data)[1] == buff[1] && (can1_recv_msg.data)[2] == buff[2])
            {
                return (buff[4]) | (buff[5] << 8);
            }
        }
        else if (motor_id == YZ_MOTOR_1)
        {
            if ((can2_recv_msg.data)[1] == buff[1] && (can2_recv_msg.data)[2] == buff[2])
            {
                return (buff[4]) | (buff[5] << 8);
            }
        }
    }
    return 0xFFFF;
}

/***********************************应用层*************************************/

/**
  * @brief  初始化为相对位移模式
  * @param  motor_id: 电机编号
  * @retval None
  */
void motor_relative_position_init(yz_motor_t motor_id)
{
    motor_start(motor_id, 0x00); // 启动+电压输出+允许急停+允许操作
    HAL_Delay(10);
    motor_set_work_mode(motor_id, LOCATION_MODE); // 工作模式设置为位置模式
    HAL_Delay(10);
    motor_set_location_cache(motor_id, 50000); // 位置缓存写入 50000 脉冲
    HAL_Delay(10);
    motor_set_trapezoidal_speed(motor_id, 500); // 梯形速度写入 500RPM
    HAL_Delay(10);
    motor_set_trapezoidal_acceleration(motor_id, 65000); // 梯形加减速写入 60000RPM/S
    HAL_Delay(10);
    motor_start(motor_id, CONTROL_WORD_RELATIVE_POSITION); // 相对位置控制模式
    HAL_Delay(10);
    motor_start(motor_id, CONTROL_WORD_RELATIVE_POSITION | CONTROL_WORD_EXECUTE_NEW_SET_POINT); // 相对位置控制模式 + 走到新的位置点
    HAL_Delay(10);
}

/**
  * @brief  设置相对位移位置缓存
  * @param  motor_id: 电机编号
  * @retval None
  */
void motor_set_relative_position(yz_motor_t motor_id, uint32_t new_location_cache)
{
    motor_set_location_cache(motor_id, new_location_cache); // 位置缓存写入脉冲
    HAL_Delay(10);
    motor_start(motor_id, CONTROL_WORD_RELATIVE_POSITION | CONTROL_WORD_EXECUTE_NEW_SET_POINT); // 相对位置控制模式 + 走到新的位置点
    HAL_Delay(10);
}

/***********************************测试层*************************************/
/**
  * @brief  测试电机正反转
  * @retval None
  */
void motor_test_positive_inversion(void)
{
    uint8_t i = 0;
    uint8_t flag = 0;

    while (1)
    {
        if (flag == 0)
        {
            motor_set_relative_position(YZ_MOTOR_0, 1800000);
            motor_set_relative_position(YZ_MOTOR_1, 1800000);
            HAL_Delay(2000);
        }
        else
        {
            motor_set_relative_position(YZ_MOTOR_0, 0xFFE488BF);
            motor_set_relative_position(YZ_MOTOR_1, 0xFFE488BF);
            HAL_Delay(2000);
        }
        i++;
        if (i == 10)
        {
            i = 0;
            motor_set_relative_position(YZ_MOTOR_0, 0);
            motor_set_relative_position(YZ_MOTOR_1, 0);
            HAL_Delay(1000);
            if (flag == 0)
            {
                flag = 1;
            }
            else
            {
                flag = 0;
            }
        }
    }
}

/**
  * @brief  测试电机找原点模式
  * @retval None
  */
void motor_test_find_the_origin(void)
{
    HAL_Delay(10);
    motor_stop(YZ_MOTOR_0);
    HAL_Delay(10);
    motor_stop(YZ_MOTOR_1);
    HAL_Delay(200);
    motor_set_find_origin_mode(YZ_MOTOR_0, 17);
    HAL_Delay(10);
    motor_set_find_origin_mode(YZ_MOTOR_1, 17);
    HAL_Delay(10);
    motor_set_work_mode(YZ_MOTOR_0, FIND_ORIGIN_MODE);
    HAL_Delay(10);
    motor_set_work_mode(YZ_MOTOR_1, FIND_ORIGIN_MODE);
}

/********************************************************************************
* @file    yz_aim.h
* @author  jianqiang.xue
* @Version V1.0.0
* @Date    2021-05-05
* @brief   
********************************************************************************/

#ifndef __YZ_AIM_H
#define __YZ_AIM_H

#include <stdint.h>

#define CONTROL_WORD_START                     (1<<0)
#define CONTROL_WORD_VOLTAGE_OUTPUT            (1<<1)
#define CONTROL_WORD_EMERGENCY_STOP_EN         (1<<2)
#define CONTROL_WORD_OPERATION_EN              (1<<3)
#define CONTROL_WORD_EXECUTE_NEW_SET_POINT     (1<<4)
#define CONTROL_WORD_LOCATION_START            (1<<5)

#define CONTROL_WORD_ABSOLUTE_POSITION         (0<<6)
#define CONTROL_WORD_RELATIVE_POSITION         (1<<6)

#define CONTROL_WORD_FAULT_RESET_EN            (1<<7)
#define CONTROL_WORD_STOP                      (1<<8)

typedef enum
{
    YZ_MOTOR_0 = 0,
    YZ_MOTOR_1
} yz_motor_t;

typedef enum
{
    LOCATION_MODE    = 1,
    SPEED_MODE       = 3,
    FIND_ORIGIN_MODE = 6,
    MOVEMENT_MODE    = 7
} motor_work_mode_t;

uint16_t motor_get_state_word(yz_motor_t motor_id);
void motor_start(yz_motor_t motor_id, uint16_t opt);
void motor_stop(yz_motor_t motor_id);

void motor_set_work_mode(yz_motor_t motor_id, motor_work_mode_t mode);
void motor_set_location_cache(yz_motor_t motor_id, uint32_t val);
void motor_set_trapezoidal_speed(yz_motor_t motor_id, uint32_t val);
void motor_set_trapezoidal_acceleration(yz_motor_t motor_id, uint32_t val);
uint32_t motor_get_current_location(yz_motor_t motor_id);
uint8_t motor_set_find_origin_mode(yz_motor_t motor_id, uint8_t type);

void motor_set_max_electric(yz_motor_t motor_id, uint32_t val, uint8_t keep_time);

void motor_set_relative_degree(yz_motor_t motor_id, int16_t degree);

uint32_t motor_get_manufacturer_id(yz_motor_t motor_id);
uint16_t motor_get_sys_vcc(yz_motor_t motor_id);
uint16_t motor_get_sys_temp(yz_motor_t motor_id);
uint16_t motor_get_sys_pwm(yz_motor_t motor_id);

void motor_relative_position_init(yz_motor_t motor_id);
void motor_set_relative_position(yz_motor_t motor_id, uint32_t new_location_cache);

void motor_test_positive_inversion(void);
void motor_test_find_the_origin(void);

#endif

代码下载:https://download.csdn.net/download/qq_29246181/70668701

  • 0
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
STM32的CAN(Controller Area Network)是指控制器局域网络,可以用于在微控制器和其他设备之间进行通信。在STM32微控制器中,通过使用两路CAN来实现重启的功能。 首先,要重启两路CAN,我们需要通过对CAN控制器的寄存器进行配置和操作来实现。可以使用STM32提供的HAL库或底层寄存器编程的方式来实现操作。 重启CAN的步骤如下: 1. 配置CAN控制器:首先,需要配置CAN控制器的一些基本参数,如波特率、模式等。可以使用相应的寄存器来进行设置。 2. 初始化CAN:接下来,需要初始化CAN的硬件资源和数据结构。可以使用CAN_Init函数来初始化。 3. 启动CAN:配置完成后,可以使用CAN_Cmd函数来启动CAN控制器。 4. 监测CAN状态:可以使用CAN_GetState函数来监测CAN的状态,确保CAN处于正常工作状态。 5. 发送和接收消息:通过使用CAN的发送和接收函数,来实现数据的传输。 6. 关闭CAN:如果需要重启CAN,首先需要关闭CAN控制器。可以使用CAN_DeInit函数来关闭。 7. 重新配置CAN:当CAN关闭后,可以重新配置CAN的参数,以适应新的需求。 8. 重启CAN:最后,可以通过步骤1至7来重新启动CAN,使其重新开始工作。 总结起来,通过配置和操作CAN的寄存器以及使用CAN的相关函数,我们可以实现STM32通过两路CAN进行重启的功能。重启过程中需要注意适当的顺序和参数设置,以确保CAN能够正常工作。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

jianqiang.xue

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

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

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

打赏作者

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

抵扣说明:

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

余额充值