基于CANOpen协议驱动直流无刷减速电机

  1.硬件连接

        硬件连接没什么复杂的,就连接对应的线即可,下面是我画的一个简单的电气连接图

 2.上位机配置

        上位机主要配置驱动器节点ID,波特率,心跳,CAN驱动。我用的是科亚的上位机和蓝玖的电机。使用上位机时,使用232转USB模块连接电脑,配置好波特率后即可用串口连接。当配置好一系列参数时就可以用串口把这些配置保存进驱动器了。

 3.初始化

        我这里用的MCU是STM32F407,下面先直接贴上我的初始化代码:

void CAN2_Mode_Init(uint8_t tsjw,uint8_t tbs2,uint8_t tbs1,uint16_t brp,uint8_t mode)
{
	GPIO_InitTypeDef		GPIO_InitStructure; 
	CAN_InitTypeDef			CAN_InitStructure;
	CAN_FilterInitTypeDef	CAN_FilterInitStructure;
	
	NVIC_InitTypeDef		NVIC_InitStructure;
	
	CAN_DeInit(CAN2);
	CAN_StructInit(&CAN_InitStructure);
	
	//使能相关时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能PORTB时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1|RCC_APB1Periph_CAN2, ENABLE);//使能CAN1和CAN2时钟
	
	//初始化GPIO
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12| GPIO_Pin_13;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
	GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化PB12,PB13
	
	//引脚复用映射配置
	GPIO_PinAFConfig(GPIOB,GPIO_PinSource12,GPIO_AF_CAN2); //GPIOB12复用为CAN2
	GPIO_PinAFConfig(GPIOB,GPIO_PinSource13,GPIO_AF_CAN2); //GPIOB13复用为CAN2
	
	//CAN单元设置
	CAN_InitStructure.CAN_TTCM=DISABLE;	//非时间触发通信模式
	CAN_InitStructure.CAN_ABOM=ENABLE;	//启用软件自动离线管理
	CAN_InitStructure.CAN_AWUM=DISABLE;	//睡眠模式通过软件唤醒(清除CAN->MCR的SLEEP位)
	CAN_InitStructure.CAN_NART=ENABLE;	//禁止报文自动传送
	CAN_InitStructure.CAN_RFLM=DISABLE;	//报文不锁定,新的覆盖旧的
	CAN_InitStructure.CAN_TXFP=DISABLE;	//优先级由报文标识符决定
	
	CAN_InitStructure.CAN_Mode= mode;//模式设置
	CAN_InitStructure.CAN_SJW=tsjw;	//重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位 CAN_SJW_1tq~CAN_SJW_4tq
	CAN_InitStructure.CAN_BS1=tbs1; //Tbs1范围CAN_BS1_1tq ~CAN_BS1_16tq
	CAN_InitStructure.CAN_BS2=tbs2;//Tbs2范围CAN_BS2_1tq ~	CAN_BS2_8tq
	CAN_InitStructure.CAN_Prescaler=brp;  //分频系数(Fdiv)为brp+1
	
	CAN_Init(CAN2, &CAN_InitStructure);// 初始化CAN2
	
		//配置过滤器
	CAN_FilterInitStructure.CAN_FilterNumber=15;//过滤器15
	CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;
	CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;//32位
	CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;32位ID
	CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;
	CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;//32位MASK
	CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;
	CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0;//过滤器0关联到FIFO0
	CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //激活过滤器0
	CAN_FilterInit(&CAN_FilterInitStructure);//滤波器初始化
	
	
	CAN_ITConfig(CAN2,CAN_IT_FMP0,ENABLE);//FIFO0消息挂号中断允许   
	
	NVIC_InitStructure.NVIC_IRQChannel = CAN2_RX0_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;// 主优先级为3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;// 次优先级为3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	
	NVIC_Init(&NVIC_InitStructure);
}

        主函数对CAN初始化的时候直接调用这个函数即可,传入的参数决定了CAN的波特率。由于我用的MCU是f407,其CAN时钟频率为42MHZ,所以公式即为42M/(tsjw+1+tbs2+1+tbs1+1)*brp

        我用的电机仅支持波特率250K,所以我的初始化调用是这样写的:

CAN2_Mode_Init(CAN_SJW_1tq, CAN_BS1_7tq, CAN_BS2_6tq, 12, CAN_Mode_Normal);//配置并启动CAN接口  250k波特率=42M/(1+7+6)*12

对了,还可以开启CAN接收中断,这样就可以接收到电机的心跳包和回复包了,但若要进接收中断就必须先开启CAN 1的时钟,再开启CAN2时钟,还必须将过滤器设置在14-27之间

//CAN2_RX0中断服务函数
void CAN2_RX0_IRQHandler(void)
{
	CAN_Receive(CAN2, 0, &CAN2RxMessage);//将CANFIFO中收到的数据储存到“CAN2RxMessage”变量中
	
	CAN2_rx_flag = FLAG_OK;//标志位置位
	
//	printf("can2irq\r\n");
}

我这个电机初始化完了还需要发送一条使能指令:

void Servo_can_enable_test(void)
{
	uint8_t post_can2;
	CAN2TxMsg.ExtId = 0x00000601;//CANOpen协议,正常通信包,主机发送ID为:0x600 + 目标设备id
	CAN2TxMsg.DLC = 4;
	CAN2TxMsg.IDE = CAN_ID_EXT;// 使用扩展标识符
	CAN2TxMsg.RTR=0;// 消息类型为数据帧,一帧8位
	
	
	CAN2TxMsg.Data[0] = 0x23;
	CAN2TxMsg.Data[1] = 0x0D;//索引的低8位(LSB)0x00
	CAN2TxMsg.Data[2] = 0x20;//索引的高8位(MSB) 0x20
	CAN2TxMsg.Data[3] = 0x01;//子索引 0x01
	
	post_can2=CAN_Transmit(CANOPEN_PORT, &CAN2TxMsg);
	
}

        直接在初始化完了之后调用一次就行,为啥要发这几个字节呢,因为厂家文档写的,具体情况具体讨论,有可能你的电机配置与我不同,这就需要你仔细发现问题了

        使能之后就可以发送扩展帧数据驱动电机旋转了,比如我要让电机以100的速度旋转,我是这样写的:

void Servo_speed_tx_test(void)
{
//	uint8_t post_can1,i;
	uint8_t post_can1;
	CAN2TxMsg.ExtId = 0x00000601;//CANOpen协议,正常通信包,主机发送ID为:0x600 + 目标设备id
	CAN2TxMsg.DLC = 8;
	CAN2TxMsg.IDE = CAN_ID_EXT;// 使用扩展标识符
	CAN2TxMsg.RTR=0;// 消息类型为数据帧,一帧8位
	
	CAN2TxMsg.Data[0] = 0x23;
	CAN2TxMsg.Data[1] = 0x00;//索引的低8位(LSB)0x00
	CAN2TxMsg.Data[2] = 0x20;//索引的高8位(MSB) 0x20
	CAN2TxMsg.Data[3] = 0x01;//子索引 0x01
	CAN2TxMsg.Data[4] = 0x64;//(0x00FF&speed_data)
	CAN2TxMsg.Data[5] = 0x00;//(0xFF00&speed_data)>>8
	CAN2TxMsg.Data[6] = 0x00;
	CAN2TxMsg.Data[7] = 0x00;
		
	post_can1=CAN_Transmit(CANOPEN_PORT, &CAN2TxMsg);
	printf("post_can1:%d\r\n",post_can1);
	
}

        直接在while(1)中调用即可,但调用的时候必须加延时,如果不加延时就会导致数据发送过快,邮箱一直被占用,这样也是驱动不了电机的。但如果你需要频繁地改动速度,不可能每次都计算好速度高低位再写入,这样太麻烦了。我们需要直接填入速度值,然后再在函数内部自动计算高低位并填入指令中发送出去。我是这样写的

//CANOpen读取或写入从设备的寄存器
int8_t CAN_OPEN_Read_Or_Write_Driver_Reg(	uint8_t dev_addr,
											uint16_t index,
											uint8_t subindex,
											uint8_t *data,
											uint8_t len,
											uint8_t wr_state)
{
	uint8_t i;
	
	CAN2TxMsg.ExtId = 0x600 + dev_addr;//CANOpen协议,正常通信包,主机发送ID为:0x600 + 目标设备id
	CAN2TxMsg.DLC = 8;
	CAN2TxMsg.IDE = CAN_ID_EXT;// 使用扩展标识符
	CAN2TxMsg.RTR=0;// 消息类型为数据帧,一帧8位
	
	CAN2TxMsg.Data[1] = index & 0xFF;//索引的低8位(LSB)0x00
	CAN2TxMsg.Data[2] = (index >> 8) & 0xFF;//索引的高8位(MSB) 0x20
	CAN2TxMsg.Data[3] = subindex;//子索引 0x01
	
	//CAN发送状态为:写寄存器
	if(wr_state == CAN_OPEN_REG_WRITE)
	{
		//不同的数据长度,data[0]的值不同
		if(len == 1)
		{
			CAN2TxMsg.Data[0] = 0x2F;
		}
		else if(len == 2)
		{
			CAN2TxMsg.Data[0] = 0x2B;
		}
		else if(len == 4)
		{
			CAN2TxMsg.Data[0] = 0x23;
		}
		else
		{
			return CAN_OPEN_WRONG_LENGTH;
		}
		
		//将数据写入待发送的变量中
		for (i = 4 ; i < 4+len ; i++)
		{
			CAN2TxMsg.Data[i] = data[i-4];
		}
		
		for (i = 4+len ; i < 8 ; i++)
		{
			CAN2TxMsg.Data[i] = 0;
		}
	}
	else if(wr_state == CAN_OPEN_REG_READ)//CAN发送状态为:读寄存器
	{
		CAN2TxMsg.Data[0] = (2 << 5);//由于读寄存器一般不需要带参数,所以数据长度data[0]一般为0X40(即:2 << 5)
		
		for (i = 4 ; i < 8 ; i++)
		{
			CAN2TxMsg.Data[i] = 0;
		}
	}
	
	CAN2_Receive_Flag_Init();//为了保险,将CAN接收数据的标志位重置,以免将CAN发送之前收到的CAN数据错误地当成了其对应地应答
	
	CAN_Transmit(CANOPEN_PORT, &CAN2TxMsg);
	
	return CAN_OPEN_SUCCESS ;
}

        然后,再调用即可

int32_t speed1_test=50;
CAN_OPEN_Read_Or_Write_Driver_Reg(SERVO_ID, 0x2000, MOTOR_1_ID, (uint8_t *)&speed1_test, 4,CAN_OPEN_REG_WRITE);

        CANOpen协议中还有许多操作也是类似的道理,我这里就不一一介绍了,下面我会贴上我的源代码,供大家参考:CAN扩展帧_电机

  • 4
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: Canopen DS402协议是一种常用于电机驱动器的通信协议。作为一种开放式的通信协议Canopen DS402协议已经被广泛应用于各种工业自动化系统中,特别是机器人、包装机械、气动系统等领域。该协议支持多种数据表示格式,如二进制、十六进制、BCD码等,同时还提供了多种通讯速率和数据帧长度的选项以满足不同需求。 与传统的通信协议相比,Canopen DS402协议的优点在于其灵活性和可扩展性。该协议支持多个物理层,如CAN总线、以太网等,并且能够进行网络拓扑的配置和管理。此外,Canopen DS402协议还支持多种节点类型,如主节点、从节点等,以确保数据传输的稳定性和可靠性。 对于电机驱动器而言,Canopen DS402协议的应用可以将控制命令通过通信总线传输到电机控制器中,从而实现对电机速度、位置、转矩等参数的控制。此外,该协议还可以实现多轴控制、位置同步等功能,以满足各种复杂的应用场景需求。 总之,Canopen DS402协议是一种高效、灵活、可扩展的通信协议,适用于各种工业自动化应用场景,特别是电机驱动器中的应用。 ### 回答2: Canopen_DS402协议-电机驱动器.pdf是一份关于Canopen协议电机驱动器领域的应用指南。Canopen作为一个开放式的通用领域网络协议,已经被广泛应用于工业自动化、车辆控制、航空航天等领域。在电机驱动领域,Canopen协议可以优化驱动器的性能和控制方式,提高其可靠性和功能性。 本文主要介绍了Canopen电机驱动领域的应用场景和具体实现方式,包括控制方式、数据通信、网络拓扑结构等方面。其中,Canopen_DS402协议Canopen电机驱动器领域的具体应用,它针对电机驱动器的控制和监测等功能进行了详细的规范和要求。Canopen_DS402协议提供了丰富的命令和状态反馈功能,使得不同品牌、不同类型的电机驱动器可以相互兼容。 Canopen电机驱动领域的应用可以优化电机的控制方式和性能,提高其精度和响应速度,同时也能够通过网络实现电机控制器之间的通信和协同工作。Canopen_DS402协议作为Canopen电机驱动领域的具体实现,不仅提高了电机驱动器的功能性,还减少了设备的成本和维护成本,促进了技术领域的交流和合作。 总之,Canopen_DS402协议-电机驱动器.pdf是一份具有参考价值的文档,可以为电机驱动领域的从业者、研究者提供具体的操作和实践指南,促进Canopen技术在电机驱动领域的广泛应用和推广。 ### 回答3: CANopen DS402协议-电机驱动器是一个在工业环境中使用的通信协议,这个协议定义了一些命令和数据对象,可以在电机驱动器和控制器之间进行通信。通过CAN总线进行数据传输,可以实现电机的控制、监测和故障诊断。 CANopen DS402协议-电机驱动器定义了许多数据对象,比如控制字、状态字、速度反馈、电流反馈、电机位置等等。这些数据对象可以用来描述电机的状态、控制模式、运动参数等,具有很强的灵活性和可配置性,可以适应不同的应用环境和操作要求。 在使用CANopen DS402协议进行电机控制时,通常需要对驱动器进行配置,比如设置反馈类型、限制电流和速度、设定控制模式等等。控制器可以向驱动器发送相应的控制命令,比如使能电机、停止电机、改变电机转速和方向等等。同时,控制器可以根据驱动器上传的状态和反馈信息进行状态监测和故障诊断,实现对电机的全面控制和管理。 总之,CANopen DS402协议-电机驱动器是工业领域中使用广泛的通信协议之一,它可以实现电机的高效控制和监测,具有很高的通信速率和灵活性,是现代工业自动化控制系统中必不可少的一部分。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值