HAL库+CubeMX CAN总线的使用

编程入门 行业动态 更新时间:2024-10-27 17:22:45

HAL库+CubeMX CAN<a href=https://www.elefans.com/category/jswz/34/1769217.html style=总线的使用"/>

HAL库+CubeMX CAN总线的使用

HAL库+CubeMX CAN总线的使用

  • CAN 控制 RM 电机
    • 1、CAN 概述
      • 1.1、仲裁场
      • 1.2、控制场和数据场
    • 2、RM 3508电机使用
      • 2.1、电调发送报文格式
      • 2.2、电调接收报文格式
    • 3、CAN在cubeMX中的配置
    • 4、CAN发送函数
      • 4.1、CAN_cmd_chassis函数
        • 4.1.1、CAN发送的函数 HAL_CAN_AddTXMessage
      • 4.2、CAN_cmd_chassis函数
    • 5、CAN接收中断回调
      • 5.1、接收函数 HAL_CAN_GetRxMessage
        • 5.1.1、解码函数 get_motor_measure
    • 6、配置接收过滤器(筛选器)
  • Copy From 大疆学习文档


CAN 控制 RM 电机

1、CAN 概述

CAN是控制器局域网络(Controller Area Network, CAN)的简称,是一种能够实现分布式实时控制的串行通信网络。

CAN总线由CAN_H和CAN_L两根线构成,各个设备一起挂载在总线上。

RoboMaster系列电机也采用CAN协议进行通信,CAN协议比较复杂,一个完整的数据帧由下图中的各个部分组成:

每一个挂载在CAN总线上的CAN都有一个自己独属的ID,每当一个设备发送一帧数据时,总线其他设备会检查这个ID是否是自己需要接收数据的对象,如果是则接收本帧数据,如果不是则忽略。

1.1、仲裁场


如上图所示,ID存储在数据帧最前头的仲裁场内,CAN的ID分为标准ID和拓展ID两类,标准ID长度为11位。如果设备过多,标准ID不够用的情况下,可以使用拓展ID,拓展ID的长度有29位。

1.2、控制场和数据场


在通过ID判断本帧数据可以接收后,控制场中的DLC规定了本帧数据的长度,而数据场内的数据的大小为8Byte,即8个8位数据。CAN总线的一个数据帧中所需要传输的有效数据实际上就是这8Byte(即DLC长度一般都设置为0x08)。

2、RM 3508电机使用

2.1、电调发送报文格式


这是电调发送报文格式,即如果要发送数据给1号到4号电调,控制电机的输出电流,从而控制电机转速时,需要按照表中的内容,将发送的CAN数据帧的ID设置为0x200,数据域中的8Byte数据按照电调1到4的高八位和低八位的顺序装填,帧格式和DLC也按照表中内容进行设置,最后进行数据的发送。

2.2、电调接收报文格式


首先根据接收到的ID判断究竟接收到的是哪个电调发送来的数据,手册中规定1号电调ID为0x201,2号为0x202,3号为0x203,4号为0x204。判断完数据来源之后,就可以按照手册中的数据格式进行解码,通过高八位和低八位拼接的方式,得到电机的转子机械角度,转子转速,转矩电流,电机温度等数据。

3、CAN在cubeMX中的配置

  1. 首先在cubeMX中将CAN1开启,打开Connectivity下的CAN1,进行CAN1的配置。
  2. 在Mode中,将Master Mode选中打勾。
  3. 在Configuration界面中,需要进行CAN的波特率的配置,设置完分频系数 (Prescaler) 后,cubeMX会自动完成Time Quantum(简写为tq)的计算,将tq乘以tBS1 (Time Quanta in Bit Segment 1),tBS2 (Time Quanta in Bit Segment 1),RJW (ReSynchronization Jump Width) 之和刚好为1微秒,对应波特率为1M,这是CAN总线支持的最高通讯速率


    友情提示:将Prescaler调为3后,先将Time…Segment 1 设置为12或以上,再将Time…Segment 2设置为3,最后再将Time…Segment 1 设置为10
  4. 使能中断
  5. can2的配置方式与can1相同,Mode为Slave Mode。

4、CAN发送函数

程序中提供了CAN_cmd_chassis函数和CAN_cmd_gimbal函数,用于向底盘电机和云台电机发送CAN信号,控制电机运动。

4.1、CAN_cmd_chassis函数

CAN_cmd_chassis函数的输入为电机1到电机4的驱动电流期望值motor1到motor4,函数会将期望值拆分成高八位和低八位,放入8Byte的CAN的数据域中,然后添加ID (CAN_CHASSIS_ALL_ID 0x200),帧格式,数据长度等信息,形成一个完整的CAN数据帧,发送给各个电调。

void CAN_cmd_chassis(int16_t motor1, int16_t motor2, int16_t motor3, int16_t motor4) 
{ uint32_t send_mail_box; chassis_tx_message.StdId = CAN_CHASSIS_ALL_ID; chassis_tx_message.IDE = CAN_ID_STD; chassis_tx_message.RTR = CAN_RTR_DATA;chassis_tx_message.DLC = 0x08; chassis_can_send_data[0] = motor1 >> 8; chassis_can_send_data[1] = motor1; chassis_can_send_data[2] = motor2 >> 8; chassis_can_send_data[3] = motor2; chassis_can_send_data[4] = motor3 >> 8; chassis_can_send_data[5] = motor3; chassis_can_send_data[6] = motor4 >> 8; chassis_can_send_data[7] = motor4; HAL_CAN_AddTxMessage(&CHASSIS_CAN, &chassis_tx_message, chassis_can_send_data, &send_mail_box); 
}
4.1.1、CAN发送的函数 HAL_CAN_AddTXMessage

HAL库提供了实现CAN发送的函数HAL_CAN_AddTXMessage

HAL_StatusTypeDef HAL_CAN_AddTxMessage(CAN_HandleTypeDef *hcan, 
CAN_TxHeaderTypeDef *pHeader, uint8_t aData[], uint32_t *pTxMailbox)

4.2、CAN_cmd_chassis函数

CAN_cmd_gimbal函数的功能为向云台电机和发射机构电机发送控制信号,输入参数为yaw轴电机,pitch轴电机,发射机构电机的驱动电流期望值yaw,pitch,shoot(rev为保留值),函数会将期望值拆分成高八位和第八位,放入8Byte的CAN的数据域中,然后添加ID(CAN_GIMBAL_ALL_ID 0x1FF),帧格式,数据长度等信息,形成一个完整的CAN数据帧,发送给各个电调。

void CAN_cmd_gimbal(int16_t yaw, int16_t pitch, int16_t shoot, int16_t rev) 
{ uint32_t send_mail_box; gimbal_tx_message.StdId = CAN_GIMBAL_ALL_ID; gimbal_tx_message.IDE = CAN_ID_STD; gimbal_tx_message.RTR = CAN_RTR_DATA; gimbal_tx_message.DLC = 0x08; gimbal_can_send_data[0] = (yaw >> 8); gimbal_can_send_data[1] = yaw; gimbal_can_send_data[2] = (pitch >> 8); gimbal_can_send_data[3] = pitch; gimbal_can_send_data[4] = (shoot >> 8); gimbal_can_send_data[5] = shoot; gimbal_can_send_data[6] = (rev >> 8); gimbal_can_send_data[7] = rev; HAL_CAN_AddTxMessage(&GIMBAL_CAN, &gimbal_tx_message, gimbal_can_send_data, &send_mail_box); 
}

5、CAN接收中断回调

HAL库提供了CAN的接收中断回调函数 HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan),每当CAN完成一帧数据的接收时,就会触发一次CAN接收中断处理函数,接收中断函数完成一些寄存器的处理之后会调用CAN接收中断回调函数。

在中断回调函数中首先判断接收对象的ID,是否是需要的接收的电调发来的数据。完成判断之后,进行解码,将对应的电机的数据装入电机信息数组motor_chassis各个对应的位中。

/*
motor data,  0:chassis motor1 3508;1:chassis motor3 3508;2:chassis motor3 3508;3:chassis motor4 3508;
4:yaw gimbal motor 6020;5:pitch gimbal motor 6020;6:trigger motor 2006;
电机数据, 0:底盘电机1 3508电机,  1:底盘电机2 3508电机,2:底盘电机3 3508电机,3:底盘电机4 3508电机;
4:yaw云台电机 6020电机; 5:pitch云台电机 6020电机; 6:拨弹电机 2006电机*/
static motor_measure_t motor_chassis[7];static CAN_TxHeaderTypeDef  gimbal_tx_message;
static uint8_t              gimbal_can_send_data[8];
static CAN_TxHeaderTypeDef  chassis_tx_message;
static uint8_t              chassis_can_send_data[8];/*** @brief          hal CAN fifo call back, receive motor data* @param[in]      hcan, the point to CAN handle* @retval         none*/
/*** @brief          hal库CAN回调函数,接收电机数据* @param[in]      hcan:CAN句柄指针* @retval         none*/
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{CAN_RxHeaderTypeDef rx_header;uint8_t rx_data[8];HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &rx_header, rx_data);switch (rx_header.StdId){case CAN_3508_M1_ID:case CAN_3508_M2_ID:case CAN_3508_M3_ID:case CAN_3508_M4_ID:case CAN_YAW_MOTOR_ID:case CAN_PIT_MOTOR_ID:case CAN_TRIGGER_MOTOR_ID:{static uint8_t i = 0;//get motor idi = rx_header.StdId - CAN_3508_M1_ID;get_motor_measure(&motor_chassis[i], rx_data);break;}default:{break;}}
}

5.1、接收函数 HAL_CAN_GetRxMessage

接收时调用了HAL库提供的接收函数HAL_CAN_GetRxMessage

HAL_StatusTypeDef HAL_CAN_GetRxMessage(CAN_HandleTypeDef *hcan, 
uint32_t RxFifo, CAN_RxHeaderTypeDef *pHeader, uint8_t aData[])


motor_chassis为motor_measure_t类型的数组,其中装有电机转子角度,电机转子转速,控制电流,温度等信息。

typedef struct { uint16_t ecd; int16_t speed_rpm; int16_t given_current; uint8_t temperate; int16_t last_ecd; 
} motor_measure_t;
5.1.1、解码函数 get_motor_measure

解码功能实际上完成的工作是将接收到的数据按照高八位和低八位的方式进行拼接,从而得到电机的各个参数。

#define get_motor_measure(ptr, data) \{ \ (ptr)->last_ecd = (ptr)->ecd; \ (ptr)->ecd = (uint16_t)((data)[0] << 8 | (data)[1]); \ (ptr)->speed_rpm = (uint16_t)((data)[2] << 8 | (data)[3]); \ (ptr)->given_current = (uint16_t)((data)[4] << 8 | (data)[5]); \ (ptr)->temperate = (data)[6]; \ }

6、配置接收过滤器(筛选器)

过滤器是需要自己配置的,而且不配置过滤器CAN不能正常接收数据。
其初始化要在进入while循环前进行调用

extern CAN_HandleTypeDef hcan1;
extern CAN_HandleTypeDef hcan2;void can_filter_init(void)
{CAN_FilterTypeDef can_filter_st;can_filter_st.FilterActivation = ENABLE; //筛选器激活can_filter_st.FilterMode = CAN_FILTERMODE_IDMASK; //标识符屏蔽位模式can_filter_st.FilterScale = CAN_FILTERSCALE_32BIT; //过滤器位宽为单个32位can_filter_st.FilterIdHigh = 0x0000;can_filter_st.FilterIdLow = 0x0000;can_filter_st.FilterMaskIdHigh = 0x0000;can_filter_st.FilterMaskIdLow = 0x0000;can_filter_st.FilterBank = 0;can_filter_st.FilterFIFOAssignment = CAN_RX_FIFO0; //FIFO0的中断和FIFO1的中断是不一样的,这里是把接收到的报文放入到FIFO0中HAL_CAN_ConfigFilter(&hcan1, &can_filter_st);HAL_CAN_Start(&hcan1);HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING);can_filter_st.SlaveStartFilterBank = 14; //为从属can选择开始的过滤库,对于单个CAN实例,这个参数没有意义can_filter_st.FilterBank = 14;HAL_CAN_ConfigFilter(&hcan2, &can_filter_st);HAL_CAN_Start(&hcan2);HAL_CAN_ActivateNotification(&hcan2, CAN_IT_RX_FIFO0_MSG_PENDING);}

标识符屏蔽位模式:FxR0为标识符匹配值,FxR1为屏蔽码。若FxR1中某一位为1,FxR0中相应的位必须与收到的帧的标识符中的相应位吻合才能通过过滤器。FxR1中为0的位表示FxR0的相应位可不必与收到的帧进行匹配。
例如:标识符寄存器的bit15=0,屏蔽位寄存器的bit15=1,那么接受的Message里面的标识符的bit15必须为0才可能被硬件接受。如果屏蔽位寄存器的bit15=0,Message里面的标识符的bit15无论为什么值,bit15都能匹配通过。当bit0~bit31都能通过时。此Message就会被硬件接受。

标识符列表模式:FR1和FR2都是要匹配的标识符,收到的帧的标识符必须与其中一个吻合才能通过过滤。
例如:现在设置为0x602和0x601,那么只有ID为0x602和0x601时才会通过过滤器

所有过滤器是并联的,一个报文只要通过了一个过滤器就算是有效的

CAN_FxR1与CAN_FxR2寄存器分别被拆成两段,CAN_FxR1寄存器的高16位对应着代码中的FilterIdHigh,低16位对应着FilterIdLow,而CAN_FxR2寄存器的高16位对应着FilterMaskIdHigh,低16位对应着FilterMaskIdLow。

Copy From 大疆学习文档

更多推荐

HAL库+CubeMX CAN总线的使用

本文发布于:2024-03-08 01:58:36,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1719547.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:总线   HAL   CubeMX

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!