【零基础 STM32通过CAN通信驱动Maxon电机】第四章 STM32的CAN通信收发与信号过滤

零基础 STM32通过CAN通信驱动Maxon电机

第四章 STM32的CAN通信收发与信号过滤



一、Maxon电机CAN通信收发信号

1.回顾Maxon的CAN通信指令

在Maxon的CAN通信指令中所包含的内容如下图所示。

在这里插入图片描述
CAN-ID为601为发送指令,CAN-ID为581则为接收指令。Byte0使用0x22或0x23都可以,代码中出现的0x2B等可以替换为0x22或0x23(请咨询代理商)。Byte1-3位控制类,参照技术手册。Byte4-7位为16进制发送数据值。

在编写指令时请注意,CAN通信指令是倒着输入的。例如控制类0x60FF-00,输入时Byte1=FF , Byte2=60 , Byte3=00。再比如输入数据值为10000,对应十六进制数为00002710,则Byte4-7 分别为 10 27 00 00;输入数值为100000,对应十六进制数为000186a0,则Byte4-7 分别为 a0 86 01 00。

本项目中定义发送数据指令为can_send_msg,具体定义请参考can.c。can_send_msg第一项为CAN-ID,第二项指令,第三项指令长度。

// 发送指令 601 2F 60 60 00 01
uint8_t canbuf1[]={0x2F,0x60,0x60,0x00,0x01};
res = can_send_msg(0X601, canbuf1, 5);

2.接收EPOS返回信号并分析

在当前实验中,EPOS在成功接收所有CAN-ID为0x601的指令时,实际上都会返回一条(一些)指令,如下图所示。

在这里插入图片描述
STM32f103的CAN外设共有2个接收FIFO,每个FIFO都可以存放3个完整的报文,FIFO存储器遵循先入先出的规则。所以若在发送指令后不进行收指令操作,那么如果后续有需要接收指令,则指令将会遵守先入先出的规则接收。这会导致接收的指令不是当前发送指令对应的返回指令。

以上图为例,86行发送指令0x601 0x40 0x64 0x60 0x00代表的含义是查询当前位置,87行返回指令八位中的后四位代表返回的位置数据(遵循1.1当中的规则)。实际操作中,若之前并未接受指令且未清空寄存器,那么接收到的数据将会是83行返回的指令,而非87行代表返回位置数据的返回的指令。

同时,EPOS返回的指令并非全部都是CAN-ID为0x581代表的可用数据,还存在其他CAN-ID的数据,这些数据对控制电机没有意义,需要对其进行过滤。

综上所述,接收EPOS返回信号需要进行1.发送一条消息便收一条消息(或清空FIFO或覆盖指令)2.过滤返回信号。

二、配置CAN通信过滤器

有关于CAN通信过滤器的知识,可以到大佬的帖子仔细学习,本文不再赘述。

STM32 CAN过滤器 http://t.csdnimg.cn/3boRx

本文仅针对EPOS返回信号进行CAN通信过滤器的设计。

目的:仅接收标准标识符为0x581的报文(无扩展标识符),其余过滤。

  /*配置CAN过滤器*/
  sFilterConfig.FilterBank = 0;                   
  sFilterConfig.FilterMode = CAN_FILTERMODE_IDLIST;    
  sFilterConfig.FilterScale = CAN_FILTERSCALE_16BIT;  
  sFilterConfig.FilterIdHigh = 0x0000;                 
  sFilterConfig.FilterIdLow = 0x581<<5;
  sFilterConfig.FilterMaskIdHigh = 0x0000;              
  sFilterConfig.FilterMaskIdLow = 0xFFFF;
  sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;   
  sFilterConfig.FilterActivation = ENABLE;     
  sFilterConfig.SlaveStartFilterBank = 14;

以上配置在can.c当中完成,通过以上配置,STM32的FIFO0存储器仅接收标准标识符为0x581的报文。

三、封装函数及收发

1.STM32 CAN通信接收报文

在STM32中,通过can.c中的can_receive_msg实现接收报文。

uint16_t can_receive_msg(uint32_t id, uint8_t *buf)
{
  if (HAL_CAN_GetRxFifoFillLevel(&g_canx_handler, CAN_RX_FIFO0) == 0)  
  {
		printf("no recv");
		return 0;
  }

  if (HAL_CAN_GetRxMessage(&g_canx_handler, CAN_RX_FIFO0, &g_canx_rxheader, buf) != HAL_OK) 
  {
		printf("read recv err");
		return 0;
  }
  
  if (g_canx_rxheader.StdId!= id || g_canx_rxheader.IDE != CAN_ID_STD || g_canx_rxheader.RTR != CAN_RTR_DATA)       
  {
		printf("data err");
		return 0;  		
  }

  return g_canx_rxheader.StdId;
}

值得注意的是,在调试过程中需要返回接收报文的标准标识符,由于EPOS的有效返回标准标识符为0x581,所以需要将can_receive_msg的类型修改为uint16_t。

调用can_receive_msg输入的参数包括CAN-ID和返回报文存储位置(指针)。

2.封装及调用

在本项目中,在can.c中将EPOS指令进行封装方便调用。
已有的函数包括:

void can_run(void); //激活操作模式
uint8_t can_run_outline_speed(void);//激活轮廓速度模式
uint8_t can_set_outline_speed(int speed);//设置轮廓速度为speed
uint8_t can_exit(void);//去使能
uint8_t can_enable(void);//使能
uint8_t can_set_position(int position);//设置目标位置为position
uint8_t can_run_imm(void);//运行(相对立即)
uint8_t can_read_pos(void);//查询当前位置(请求)
int can_recv_pos(void);//当前位置的值(返回)

需要注意的是,在同一个封装函数当中同时调用can_send_msg和can_receive_msg可能会出现:接收不到本次发送报文的返回报文(可在函数外接收)的问题。

3.STM32的进制转换问题

网上有很多16进制转换十进制的解决方案,可能并不都适合STM32的uint数据类型。通过按位与移位操作,可以实现十六进制与十进制之间的转换。

//通过移位和按位与操作实现将speed转换为十六进制数,并按规则写入canbufotlspd的后四位
uint8_t can_set_outline_speed(int speed)
{
	uint16_t res=1;
	uint8_t canbufotlspd[]={0x23,0x81,0x60,0x00,0x00,0x00,0x00,0x00};
	canbufotlspd[7] = (uint8_t)((speed >> 24) & 0xFF); 
	canbufotlspd[6] = (uint8_t)((speed >> 16) & 0xFF);  
	canbufotlspd[5] = (uint8_t)((speed >> 8) & 0xFF);  
	canbufotlspd[4] = (uint8_t)(speed & 0xFF);
	res=can_send_msg(0X601, canbufotlspd, 8);
	if (res==0)
	{
		printf("can set otl spd\r\n");
		return 1;
	}
	return 0;
}
//通过移位和按位与操作实现将接收位置报文后四位转换为position十进制数
int can_recv_pos(void)
{
	uint16_t res=1;
	int position=0;
	uint8_t read_position[]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
	res=can_receive_msg(0X581, read_position);
	if (res==0X581 && read_position[0]==0x43 && read_position[1]==0x64 && read_position[2]==0x60 && read_position[3]==0x00)
	{
		position=(int)(read_position[4] & 0xFF)+(int)(read_position[5] & 0xFF)*256+(int)(read_position[6] & 0xFF)*256*256+(int)(read_position[6] & 0xFF)*256*256*256;
		printf("can read_recv_pos\r\n");
		return position;
	}
	return 0;
}

4.运行

按照下图的步骤发送报文,并逐步接收报文,验证封装函数正确性,实验完成。
在这里插入图片描述
在这里插入图片描述

总结

本章主要讲STM32实现CAN通信收发相关的内容,目前能够实现正确控制电机并读取电机位置。其他类型函数的封装类似。目前暂未封装位置回零功能(电机不动),后续可封装home函数实现软件回零。

本章项目链接:https://pan.baidu.com/s/12Ip0d-lvgkK8P_3YmvSV_g
提取码:1234

  • 35
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值