stm32与伺服驱动器进行can通信

发布者:Tianyun2021最新更新时间:2019-09-30 关键字:stm32  伺服驱动器  can通信 手机看文章 扫描二维码
随时随地手机看文章

实验室师兄之前用stm32之间进行can通信,其中一个作为主机,另外作为从机,从机负责电机运转,并取出电机的速度,然后通过can通信发送给主机,然后主机通过串口与上位机进行通信。这一部分操作可以参照以下链接:https://www.ncnynl.com/archives/201703/1414.html


现在我们选择用伺服驱动器与一个stm32进行can通信,从而实现对电机的控制,目前我们实现的是对电机的速度输入,启动电机,(并进行速度反馈,进行OLED输出,从而进行电机的PID调节)。

首先我们选择了以下图示伺服驱动器,驱动器这块选择淘宝搜索可进行can通信的编码器应该可以找到类似产品

在这里插入图片描述

然后按照手册,我们将电机的编码器信号线CN2,与电机相连,同时将电机三根动力线与电机相连,然后将RS232/CAN端口连出,由于我们首先测试的是商家给的PC端软件与伺服驱动器进行RS232通信,所以这里我们通过RS232与PC端相连,给伺服驱动器供电。效果图如下:

在这里插入图片描述

然后我们通过上位机软件给电机写入速度参数,加速度参数等,可以启动电机并有电流,位置,速度的实时反馈,初始如图:

在这里插入图片描述

上面进行了电机的初步测试,通过电机空载反馈回来的电流,我们初步判断电机是否工作正常,这里我们刚开始就出现电流在空载且速度较小的情况下,出现了电流输出过大的情况,于是在相关技术人员的帮助下随与商家联系更换了电机。

在这里插入图片描述

接下来就进入can通信的正题,can通信这一块我们最好通过实验板跑一下例程,然后结合程序去分析一下can通信的具体实现原理,及其各个寄存器的作用是什么,卡门一下stm32的技术文档(这里面时一些关于can通信的技术文档链接:https://pan.baidu.com/s/1LJJOMAxTTGgzYFfVnVGx5Q

提取码:agzo )。


想深入了解can通信,这里我推荐以下链接:

https://blog.csdn.net/qq_36355662/article/details/80607453

https://pan.baidu.com/s/1iy5z9g03Z4ZYn5gJYoN5WA?errno=0&errmsg=Auth Login Sucess&&bduss=&ssnerror=0&traceid=#list/path=%2F

(这是洋桃电子的资料,里面老师讲的很好很细,有助于对can通信理解)


首先在完成对can通信的理解后,我们会发现can通信的连线非常简单,只需要把can_h,can_l与其他can_h,can_l对应连接即可,其中两端需要串入120欧电阻,其作用是匹配总线阻抗,提高数据通信的抗干扰性及可靠行。(这里在设备较少时可以不接,但最好接上,消除干扰,本身stm32板内部已经串入120欧电阻,而且驱动器本身也有拨动按键来配置120欧电阻)

下一步我们需要按照手册编写can通信协议,通过stm32发送指令给伺服驱动器,从而实现电机的控制。这里特别提醒一下,这里需要用到can分析仪来分析到底哪里出了问题,这里我们走了弯路,问了技术人员后才发现这里离不开can分析仪对指令进行分析,can分析仪网上200元左右可以买到,如下:

在这里插入图片描述

接下来结合程序和手册分析一下到底如何编写指令,下面来自手册

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

通过这一块我们可以发现想要点对点的给伺服驱动器进行写数据操作的指令,这里伺服驱动器的ID号和组号可以通过之前的PC软件通过串口RS232写入。下一步就是需要用那些寄存器,并怎么给寄存器赋数据,这里从bite0-bite8的顺序我们可以发现指令写入的顺序。

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

通过 这一部分寄存器,我们实现给伺服驱动器发送速度模式,并设定速度,最后启动电机的指令。然后通过自动报告的方式可以获取到反馈回来的速度,电流,位置。

下面是在stm32上的部分程序:


//can通信发送指令

//motor_init.c的写入数据代码

void Motor_Init(void)

{

CommandData[0]=Group_Motors; 

CommandData[1]=FCW_One2One; 

CommandData[2]=Register_SpeedSet; //速度设定寄存器

CommandData[3]=0x02; 

CommandData[4]=0xFE;

CommandData[5]=Register_Moter; //启动电机

CommandData[6]=0x00; 

CommandData[7]=0x00;

CAN_SendMsg(ID_MASTER, CommandData);

   CommandData[0]=Group_Motors; 

CommandData[1]=FCW_One2One; 

CommandData[2]=Resister_ReportTime; //自动报告时间设置成1s

CommandData[3]=0x07; 

CommandData[4]=0xd0;

CommandData[5]=Resister_AutoReportMode; //位置反馈 ,电流,速度

CommandData[6]=0x00; 

CommandData[7]=0x00;

  CAN_SendMsg(ID_LeftMotor, CommandData);

}



float Get_SpeedActual(uint32_t ID, float actual_speed)

{

int speed = 0;

actual_speed = 0;

CommandData[0]=Group_Motors; 

CommandData[1]=FCR_One2One; 

CommandData[2]=Resister_RSpeed; //读取的输出转速

CommandData[3]=0x00; 

CommandData[4]=0x00;

CommandData[5]=0xFF; //设置为无效寄存器

CommandData[6]=0x00; 

CommandData[7]=0x00;

Clear_canBuffer();

  CAN_SendMsg(ID, CommandData);


OLED_ShowString(0, 2,"Lspeed:",16);

while(Check_canRX()) ;

if((RxMessage.StdId) == 0x05 && RxMessage.Data[2]==Resister_RSpeed ) //设置为无效寄存器)//是否收到八位字节,且为输出转速寄存器

{

//将得到的数组合并成原始数

speed = RxMessage.Data[3] << 8 | RxMessage.Data[4];

// speed = RxMessage.Data[6] << 8 | RxMessage.Data[7];

//*actual_speed = RPM2Speed(speed/3000.0 * 8192.0);

actual_speed = RPM2Speed(speed/8192.0 * 3000.0); //实际电机转速转换成m/s

// OLED_ShowNumber(54, 2, actual_speed);

OLED_ShowNumber(12, 4, actual_speed);


//OLED_ShowString(12, 3,"stm32_master",16);

return 1;

}

return 0;

}


在motor.h文件下,我们对寄存器进行了宏定义例如:


#ifndef __MOTOR_H

#define __MOTOR_H


//FunctionCodeWrite,点对点的写数据操作功能码

#define FCW_One2One  0x1A  //发送指令,指令码,写数据,但不保存数据

#define FCW_One2One_Ri 0x1B //接收正确后返回指令

#define FCW_One2One_E  0x1C //接收错误后返回指令


//FunctionCodeRead,点对点的读数据操作功能码

#define FCR_One2One 0x2A // 指令的功能码,表示读数据,从机接收到指令后,把地址相应的数据内容上传

#define FCR_One2One_Ri 0x2B //接收正确后返回指令

#define FCR_One2One_E 0x2C //接收错误后返回指令


//FunctionCodeWrite,一对多的写数据操作功能码,主机发送数据指令,接收正确后,从机返回相应数据指令

#define FCW_One2Many  0x8A  //发送指令,写数据,但不保存数据

#define FCW_One2Many_Ri 0x8B //接收正确后返回指令

#define FCW_One2Many_E  0x8C //接收错误后返回指令


//FunctionCodeRead,一对多的读数据操作功能码

#define FCR_One2Many 0x9A //发送指令

#define FCR_One2Many_E 0x9C //接收错误后返回指令


//相关寄存器地址

#define Register_Moter 0x00  //电机寄存器   功能:写入数据不同,电机的启动和停止

#define Register_Mode 0x02  //电机输入模式选择,功能:写入数据不同,模式不同

#define Resister_SiteMode 0x51 //位置模式寄存器

#define Register_SpeedSet 0x06  //PC模式-速度给定

#define Resister_GroupNum 0x0b //设置从机CAN组号

#define Resister_IDNum 0x0d //设置从机CAN-ID号

#define Resister_ReportTime 0x0c //设置从机CAN报告时间

#define Resister_AutoReportMode 0x2e //设置自动报告内容选择



//10代表0到3000RPM 所用时间是 100ms

#define Resister_AccTimeInSpeed 0x0A //速度模式下,加减速时间设定,

#define Resister_AccTimeInSite 0x09 //位置模式下,加减速时间设定

//设定的数字量 8192 对应实际转速 3000RPM

#define Resister_SpeedLimit 0x1D //位置模式下,速度限幅值


//读参数地址列表

#define Resister_RLocation  0x55 //定位是否完成

#define Resister_RCircuit   0xE2//输出电流

#define Resister_RSpeed 0xE4//输出转速

#define Resister_ROdomH 0xE8//位置反馈高16位

#define Resister_ROdomL 0xE9//位置反馈低16位

#define Resister_RError 0xE3


//电机的组号,以及ID号

#define Group_Motors 0x00

#define ID_MASTER          0x00     //定义主机ID

#define ID_LeftMotor 0x05      //定义左伺服ID

#define ID_RightMotor 0x06      //定义右伺服ID


#define PI 3.1415926

#define Diameter 25 //轮子直径

#define PlusePerRound  2000 //脉冲数每转


#include "sys.h" 

#include "usart.h"

#include "delay.h"

#include "led.h" 

#include "oled.h"

#include "string.h"

#include "can.h"


//下面的速度单位是RPM,表示转每分钟(round per minute) 

void Motor_Init(void);

void Set_SpeedLimit(uint32_t ID, float limit_speed);

void Set_SpeedTarget(uint32_t ID, float target_speed);

//int Get_SpeedActual(uint32_t ID, float* actual_speed);

float Get_SpeedActual(uint32_t ID, float actual_speed);

int Get_Odometry(uint32_t ID, float* odom);

int Speed2RPM(float speed);

float RPM2Speed(int rpm);


#endif

写好指令后,首先用can分析仪给电机驱动器发消息,控制电机旋转,这样可以派出伺服驱动器是否有问题

如下

在这里插入图片描述

波特率的设置:1M,can通道用的2

在这里插入图片描述

首先看到接受到的数据是来自于伺服驱动器的心跳返回,

然后发送指令,发送正确后可以返回指令,可以看到can通讯成功了

在这里插入图片描述

其他指令是伺服驱动器的“心跳”,里面会包含我们自动报告的位置,速度等


然后我们用stm32与伺服驱动器进行通信

写入上述程序可以运行程序:

can分析仪:

在这里插入图片描述

然后发送指令,停止电机运转

在这里插入图片描述

can分析仪:

在这里插入图片描述

发现我们可以控制电机的运转和停止,并通过”心跳“可以取出返回的速度,这里目前只取出了一个速度并用OLED显示,希望显示实时速度,进行PID调试,后续还需要补充。

关键字:stm32  伺服驱动器  can通信 引用地址:stm32与伺服驱动器进行can通信

上一篇:小用stm32f4-CAN控制器(使用库函数)
下一篇:STM32 CAN 通讯发送不能连续,不能接收

推荐阅读最新更新时间:2024-11-10 22:27

STM32使用DMA加串口空闲中断接收数据
STM32中,需要用串口接收数据,是使用串口中断来接收数据。但是用这种方法的话,就要频繁进入串口中断,然后处理,效率就比较低。于是就想到用DMA来接收串口数据,这个STM32也是支持的。但是关键的一点,怎么知道数据接收完毕了呢?如果接收的数据长度固定,那就好办,直接设置DMA的接收数据个数就行了。但是如果长度不固定了,那应该怎么办了? 这个时候,就要用到STM32在串口中提供的另一个好用的东西了,就是串口空闲中断。在STM32的串口控制器中,设置了有串口空闲中断,即如果串口空闲,又开启了串口空闲中断的话,就触发串口空闲中断,然后程序就会跳到串口中断去执行。有了这个,是不是可以判断什么时候串口数据接收完毕了呢?因为串口数据
[单片机]
<font color='red'>STM32</font>使用DMA加串口空闲中断接收数据
STM32直接存储器访问DMA
第一次接触DMA是在学校学习ARM9裸板程序的时候,想起来都时隔快2年了。现在来看看STM32平台的DMA,一样,在标准外设库的支持下,STM32的DMA编程十分简单,但是既是学习,那还是花点时间看看DMA的相关概念及原理的了解下。 1. DMA简介 DMA是Direct Memory Access的简称,是直接存储器访问的意思。DMA是STM32单片机的外设之一,主要功能是用来搬移数据的。通过DMA搬移数据不需要CPU直接参与控制,也不需要中断处理方式那样保留现场和恢复现场。在传输数据的时候,CPU可以干其他事情。 无使用DMA的数据传输: 使用DMA后的数据传输: DMA数据传输支持从外设到存储器、存储器到外设
[单片机]
<font color='red'>STM32</font>直接存储器访问DMA
基于stm32的呼吸灯课程设计
1、呼吸灯简介 呼吸灯是指灯光在微电脑的控制之下完成由亮到暗的逐渐变化,感觉好像是人在呼吸。其广泛应用于手机之上,并成为各大品牌新款手机的卖点之一,起到一个通知提醒的作用。当你的手机里面有未处理的通知,比如说未接来电,未查收的短信等等,呼吸灯就会由暗到亮的变化,像呼吸一样那么有节奏,起到一个通知提醒的作用。 要使用数字器件控制灯光的强弱,我们很自然就想到PWM(脉冲宽度调制)技术。假如以LED作为灯光设备,且由控制器输出的PWM信号可以直接驱动LED,PWM信号中的低电平可点亮LED灯。由于视觉暂留效应,人眼可以看不到LED灯的闪烁现象,反应到人眼中的是亮度的差别,因此我们需要LED以较高的频率进行开关(亮灭)切换。因此我们可
[单片机]
基于<font color='red'>stm32</font>的呼吸灯课程设计
STM32】PWM 输出 (标准库)
一、PWM简介 PWM:脉冲宽度调制(Pulse width modulation,PWM) 脉冲宽度调制是一种模拟控制方式,根据相应载荷的变化来调制晶体管基极或MOS管栅极的偏置,来实现晶体管或MOS管导通时间的改变,从而实现开关稳压电源输出的改变。这种方式能使电源的输出电压在工作条件变化时保持恒定,是利用微处理器的数字信号对模拟电路进行控制的一种非常有效的技术。脉冲宽度调制是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术,广泛应用在从测量、通信到功率控制与变换的许多领域中。——百度百科 二、PWM输出模式 PWM 输出就是对外输出脉宽(即占空比)可调的方波信号,信号频率由自动重装 寄存器 ARR 的值决
[单片机]
【<font color='red'>STM32</font>】PWM 输出 (标准库)
STM32 输入捕获的脉冲宽度及频率计算
输入捕获模式可以用来测量脉冲宽度或者测量频率。STM32 的定时器,除了 TIM6 和 TIM7,其他定时器都有输入捕获功能。以下是对脉冲宽度及频率的计算。 1、脉冲宽度 如下图所示,采集该高电平脉冲的宽度,只需要进入输入捕获上升沿检测,记录当前的发生上升沿时的CNT值,再进行输入捕获下降沿检测,也记录当前发生下降沿时的CNT值,两次CNT值的差值再根据计数的频率就可以算出脉冲的宽度。 上升沿及下降沿捕获的程序具体实现如下: TIM8_Cap_Init(0XFFFF,72-1); //以1Mhz的频率计数 void TIM8_UP_IRQHandler(void) { if((TIM8CH4_CAPTURE_
[单片机]
<font color='red'>STM32</font> 输入捕获的脉冲宽度及频率计算
STM32之FreeRTOS
学习操作系统,我并没有一开始就学习UCOS,而是选择了FreeRTOS。FreeRTOS可以方便地搭建在各个平台上,因为汇编相关,都已经由官方完成,我们要做的仅是添加自己的代码,可省去很多工作量。 问题1:在使用多任务时,我想利用USART输出信息,但是如果直接放在任务中输出,往往会造成字符收发顺序不一致的情况,这是仿真时遇到的实际问题。为解决这个问题,可以在USART输出信息时挂起其它任务,利用vTaskSuspendAll函数挂起,再利用xTaskResumeAll重启内核调度。这样可以保证USART正确发送信息。但是,我觉得还不如为USART建立一个任务,这样子,USART就不会发生发送字符顺序错乱的问题了!而完成任务间
[单片机]
STM32用USART发送字符串,以USART_FLAG_TXE和USART_FLAG_TC怎么用
一:STM32用USART发送字符串 void UART_Send_Message(u8 *Data) { while(*Data!='') { USART_SendData(USART1, *Data); while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);//读取串口状态 Data++; } } void main(void) { u8 str_buf ; memset((char *) &str_buf, 0, sizeof(str_buf)); UART_Send_Message(str_buf); }
[单片机]
<font color='red'>STM32</font>用USART发送字符串,以USART_FLAG_TXE和USART_FLAG_TC怎么用
GD32单片机和STM32单片机的区别
一、前言 什么GD32? GD32是国内开发的一款单片机,据说开发的人员是来自ST公司的,GD32也是以STM32作为模板做出来的。 所以GD32和STM32有很多地方都是一样的,不过GD32毕竟是不同的产品,不可能所有东西都沿用STM32,有些自主开发的东西还是有区别的。相同的地方我们就不说了,下面我给大家讲一下不同的地方。 二、区别 1、内核 GD32采用二代的M3内核,STM32主要采用一代M3内核,下图是ARM公司的M3内核勘误表,GD使用的内核只有752419这一个BUG。 2、主频 使用HSE(高速外部时钟):GD32的主频最大108M,STM32的主频最大72M 使用HSI(高速内部时钟):GD32的主频最大10
[单片机]
GD32单片机和<font color='red'>STM32</font>单片机的区别
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved