stm32 42步进电机 上位机示例

脉冲到底是个啥东西?步进电机一直说发脉冲
步进电机通过接收脉冲信号来实现精确的位置控制。脉冲是一种短暂的电信号,它的变化可以触发步进电机转动一定的角度或步进。步进电机控制系统会根据输入的脉冲信号来精确定位和控制步进电机的转动,每个脉冲信号通常对应步进电机转动的一个固定的步进角度。

简单来说,当步进电机需要转动时,控制系统会发送一系列脉冲信号给步进电机,每个脉冲信号对应步进电机转动的一个步进角度。通过控制脉冲信号的频率和数量,可以精确地控制步进电机的转动,从而实现精准的位置控制和运动控制。

步进电机的相数是干嘛的,比如;两相是啥意思
步进电机的相数指的是步进电机的驱动方式中使用的线圈数量。常见的步进电机有两相、三相、四相和五相等不同的相数。

在两相步进电机中,驱动方式包含两个线圈(也称为相),每个线圈独立控制一个电机极性。两相步进电机通过交替激活这两个线圈来实现转动。具体来说,当一个线圈通电时,它会产生一个磁场,将电机转子吸引到对应位置;当另一个线圈通电时,前一个线圈的磁场会减弱,电机转子会被吸引到新的位置。通过交替激活两个线圈,可以实现步进电机的转动。

两相步进电机相对简单,结构紧凑,成本较低,广泛应用于一些低要求的应用领域。然而,由于只有两个线圈,步进角度较大,精度相对较低。

其他相数的步进电机,如三相、四相和五相步进电机,通过增加线圈的数量来提高步进角度的精度。随着相数的增加,步进电机的转动变得更加平滑和精确,但同时也增加了电机结构的复杂性和成本。

实物图:
在这里插入图片描述
上位机Qt软件图:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

思路就是stm32一直给步进电机发脉冲,然后通过驱动器驱动步进电机转动,这个项目多了一个qt发送串口消息给stm32,stm32接收对应的命令然后执行不同的函数,但是这样无法实现步进电机的反馈,无法实现限位,回零等功能。
不过目前可以实现步进电机转动度数的控制,因为实物没负载也没测试有没有丢步的现象,还能实现正反转
stm32主要代码:
Motor.h:

#ifndef __MOTOR_H
#define __MOTOR_H

void Motor_Init(void);
void Motor_Run(uint32_t dir,uint32_t num,uint32_t speed);
void Motor_RunDegree(uint32_t dir,uint32_t degree,uint32_t speed);

#endif

Motor.cpp:

#include "stm32f10x.h"
#include "Delay.h"

void Motor_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//开启GPIOA的时钟
	
	GPIO_InitTypeDef  GPIO_InitStructure;
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_4 | GPIO_Pin_3;  //PA5->EN;PA4->DIR;PA3->PWM
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
  GPIO_SetBits(GPIOA, GPIO_Pin_5 | GPIO_Pin_4| GPIO_Pin_3);	
}


void Motor_Run(uint32_t dir,uint32_t num,uint32_t speed)  
{
	if(dir==1)
	{
		GPIO_SetBits(GPIOA, GPIO_Pin_4);		
	}
	
	if(dir==0)
	{
		GPIO_ResetBits(GPIOA, GPIO_Pin_4);			
	}
	
	for(uint32_t i=0;i<=(num*3200);i++) 
	{		
		Delay_us(speed);                   
		GPIOA->ODR ^= GPIO_Pin_3;  				
	}	
}


void Motor_RunDegree(uint32_t dir,uint32_t degree,uint32_t speed)  
{
	if(dir==1)
	{
		GPIO_SetBits(GPIOA, GPIO_Pin_4);		
	}
	
	if(dir==0)
	{
		GPIO_ResetBits(GPIOA, GPIO_Pin_4);			
	}
	
	for(uint32_t i=0;i<=degree;i++) 
	{		
		Delay_us(speed);                   
		GPIOA->ODR ^= GPIO_Pin_3;  				
	}	
}


main.c:

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "Serial.h"
#include "string.h"
#include "Motor.h"

int main(void){
	Serial_Init();
	Motor_Init();
	while (1)
	{
		if (Serial_RxFlag == 1){
			if (strcmp(Serial_RxPacket, "1") == 0)
			{
				GPIO_SetBits(GPIOA, GPIO_Pin_5);
			}
			else if (strcmp(Serial_RxPacket, "3") == 0)
			{
					Motor_RunDegree(1,800,360);
			}else if (strcmp(Serial_RxPacket, "4") == 0)
			{
					Motor_RunDegree(0,800,360);
			}else if (strcmp(Serial_RxPacket, "5") == 0)
			{
					Motor_Run(1,1,300);
			}else if (strcmp(Serial_RxPacket, "6") == 0)
			{
					Motor_Run(0,1,300);
			}else if (strcmp(Serial_RxPacket, "7") == 0)
			{
					Motor_Run(1,1,400);
			}else if (strcmp(Serial_RxPacket, "8") == 0)
			{
					Motor_Run(0,1,400);
			}else if (strcmp(Serial_RxPacket, "9") == 0)
			{
					Motor_Run(1,1,500);
			}else if (strcmp(Serial_RxPacket, "10") == 0)
			{
					Motor_Run(0,1,500);
			}else if (strcmp(Serial_RxPacket, "11") == 0)
			{
					Motor_Run(1,2,300);
			}else if (strcmp(Serial_RxPacket, "12") == 0)
			{
					Motor_Run(0,2,300);
			}
			else if (strcmp(Serial_RxPacket, "2") == 0)
			{
				GPIO_ResetBits(GPIOA, GPIO_Pin_5);    
			}
			Serial_RxFlag = 0;
		}
	}
}

Qt的主要代码:

#include "widget.h"
#include <QHBoxLayout>
#include <QVBoxLayout>

//角度实时波形显示
Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    portSteepr=new Port(this);
    InitWidget();
    InitSignalAndSlot();
    ButtonDisabled();
}

Widget::~Widget(){

}

void Widget::InitWidget()
{
    setFixedSize(QSize(1200,800));
    LabelStatus=new QLabel(this);
    LabelStatus->move(100,200);

    PushButtonOpenDevice=new QPushButton(this);
    PushButtonOpenDevice->setText(tr("open device"));
    PushButtonOpenDevice->setFixedSize(120,60);

    PushButtonCloseDevice=new QPushButton(this);
    PushButtonCloseDevice->setText(tr("close device"));
    PushButtonCloseDevice->setFixedSize(120,60);


    PushButtonAdvance=new QPushButton(this);
    PushButtonAdvance->setText(tr("advance"));
    PushButtonAdvance->setFixedSize(120,60);



    PushButtonBackOff=new QPushButton(this);
    PushButtonBackOff->setText(tr("backoff"));
    PushButtonBackOff->setFixedSize(120,60);


    PushButton11300=new QPushButton(this);
    PushButton11300->setText(tr("pushbutton11300"));
    PushButton11300->setFixedSize(120,60);
    PushButton01300=new QPushButton(this);
    PushButton01300->setText(tr("pushbutton01300"));
    PushButton01300->setFixedSize(120,60);
    PushButton11400=new QPushButton(this);
    PushButton11400->setText(tr("pushbutton11400"));
    PushButton11400->setFixedSize(120,60);
    PushButton01400=new QPushButton(this);
    PushButton01400->setText(tr("pushbutton01400"));
    PushButton01400->setFixedSize(120,60);
    PushButton11500=new QPushButton(this);
    PushButton11500->setText(tr("pushbutton11500"));
    PushButton11500->setFixedSize(120,60);
    PushButton01500=new QPushButton(this);
    PushButton01500->setText(tr("pushbutton01500"));
    PushButton01500->setFixedSize(120,60);
    PushButton12300=new QPushButton(this);
    PushButton12300->setText(tr("pushbutton12300"));
    PushButton12300->setFixedSize(120,60);
    PushButton02300=new QPushButton(this);
    PushButton02300->setText(tr("pushbutton02300"));
    PushButton02300->setFixedSize(120,60);

    QVBoxLayout* vlayout1=new QVBoxLayout;
    QHBoxLayout* hlayout1=new QHBoxLayout;
    hlayout1->addWidget(PushButtonOpenDevice);
    hlayout1->addWidget(PushButtonCloseDevice);
    QHBoxLayout* hlayout2=new QHBoxLayout;
    hlayout2->addWidget(PushButtonAdvance);
    hlayout2->addWidget(PushButtonBackOff);
    QHBoxLayout* hlayout3=new QHBoxLayout;
    hlayout3->addWidget(PushButton01300);
    hlayout3->addWidget(PushButton11300);
    QHBoxLayout* hlayout4=new QHBoxLayout;
    hlayout4->addWidget(PushButton01400);
    hlayout4->addWidget(PushButton11400);
    QHBoxLayout* hlayout5=new QHBoxLayout;
    hlayout5->addWidget(PushButton01500);
    hlayout5->addWidget(PushButton11500);
    QHBoxLayout* hlayout6=new QHBoxLayout;
    hlayout6->addWidget(PushButton02300);
    hlayout6->addWidget(PushButton12300);
    vlayout1->addLayout(hlayout1);
    vlayout1->addLayout(hlayout2);
    vlayout1->addLayout(hlayout3);
    vlayout1->addLayout(hlayout4);
    vlayout1->addLayout(hlayout5);
    vlayout1->addLayout(hlayout6);
    setLayout(vlayout1);

}

void Widget::InitSignalAndSlot()
{
    connect(PushButtonOpenDevice,&QPushButton::clicked,this,&Widget::slotOpenDevice);
    connect(PushButtonCloseDevice,&QPushButton::clicked,this,&Widget::slotCloseDevice);
    connect(PushButtonAdvance,&QPushButton::clicked,this,&Widget::slotDriverSteeprAdvance);
    connect(PushButtonBackOff,&QPushButton::clicked,this,&Widget::slotDriverSteeprBackOff);

    connect(PushButton01300,&QPushButton::clicked,[=]{

        portSteepr->DriverSteeprMotor01300();

    });
    connect(PushButton11300,&QPushButton::clicked,[=]{
        portSteepr->DriverSteeprMotor11300();
    });
    connect(PushButton01400,&QPushButton::clicked,[=]{
        portSteepr->DriverSteeprMotor01400();
    });
    connect(PushButton11400,&QPushButton::clicked,[=]{
        portSteepr->DriverSteeprMotor11400();
    });
    connect(PushButton01500,&QPushButton::clicked,[=]{
        portSteepr->DriverSteeprMotor01500();
    });
    connect(PushButton11500,&QPushButton::clicked,[=]{
        portSteepr->DriverSteeprMotor11500();
    });
    connect(PushButton02300,&QPushButton::clicked,[=]{
        ButtonDisabled();
        portSteepr->DriverSteeprMotor02300();
        ButtonEnabled();
    });
    connect(PushButton12300,&QPushButton::clicked,[=]{
        portSteepr->DriverSteeprMotor12300();
    });
}

void Widget::slotOpenDevice()
{
    ButtonEnabled();
    portSteepr->EnableSteepr();
}

void Widget::slotCloseDevice()
{
    ButtonDisabled();
    portSteepr->DisEnableSteepr();
}

void Widget::slotDriverSteeprAdvance()
{
    portSteepr->DriverSteeprAdvance();
}


void Widget::slotDriverSteeprBackOff()
{
    portSteepr->DriverSteeprBackOff();
}


void Widget::ButtonDisabled()
{
    PushButtonAdvance->setEnabled(false);
    PushButtonBackOff->setEnabled(false);
    PushButton01300->setEnabled(false);
    PushButton11300->setEnabled(false);
    PushButton01400->setEnabled(false);
    PushButton11400->setEnabled(false);
    PushButton01500->setEnabled(false);
    PushButton11500->setEnabled(false);
    PushButton02300->setEnabled(false);
    PushButton12300->setEnabled(false);
}


void Widget::ButtonEnabled()
{
    PushButtonAdvance->setEnabled(true);
    PushButtonBackOff->setEnabled(true);
    PushButton01300->setEnabled(true);
    PushButton11300->setEnabled(true);
    PushButton01400->setEnabled(true);
    PushButton11400->setEnabled(true);
    PushButton01500->setEnabled(true);
    PushButton11500->setEnabled(true);
    PushButton02300->setEnabled(true);
    PushButton12300->setEnabled(true);

}

然后是接线:
采用共阳极接线法:
PUL+ ENA+ DIR+接3.3V,ENA-接A5 DIR-接A4 PUL-接A3 然后USB转TTL接线 RX接A9 TX接A10
在这里插入图片描述
注意事项:
电机如果发热严重记得调节拨码开关的电流

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/189802.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Datax安装部署及读取MYSQL写入HDFS

一.DataX简介 1.DataX概述 DataX 是阿里巴巴开源的一个异构数据源离线同步工具&#xff0c;致力于实现包括关系型数据库(MySQL、Oracle等)、HDFS、Hive、ODPS、HBase、FTP等各种异构数据源之间稳定高效的数据同步功能。 源码地址&#xff1a;https://github.com/alibaba/Data…

⑩【Redis Java客户端】:Jedis、SpringDataRedis、StringRedisTemplate

个人简介&#xff1a;Java领域新星创作者&#xff1b;阿里云技术博主、星级博主、专家博主&#xff1b;正在Java学习的路上摸爬滚打&#xff0c;记录学习的过程~ 个人主页&#xff1a;.29.的博客 学习社区&#xff1a;进去逛一逛~ Jedis、SpringDataRedis、StringRedisTemplate…

数据结构——线性表

目录 1.线性表的定义 2.顺序表 2.1顺序表的定义 2.2 顺序表的应用 2.2.1 顺序表的管理 &#xff08;1&#xff09; 顺序表的初始化 &#xff08;2&#xff09; 销毁顺序表 &#xff08;3&#xff09; 打印顺序表的值 &#xff08;4&#xff09;检查顺序表的容量 &…

C#文件操作File类vsFileInfo类和Directory类vsDirectoryInfo类

目录 一、File类vsFileInfo类 1.File类 &#xff08;1&#xff09;示例源码 &#xff08;2&#xff09;生成效果 2.FileInfo类 &#xff08;1&#xff09;示例源码 &#xff08;2&#xff09;生成效果 二、 Directory类vsDirectoryInfo类 1.Directory类 &#xff08;…

C语言基础介绍

1. C语言基础知识 C语言是一种计算机编程语言&#xff0c;是一门用于编写系统软件和应用软件的高级语言。C语言的基础知识包括&#xff1a; 数据类型&#xff1a;C语言中的数据类型包括整型、浮点型、字符型等。 变量&#xff1a;C语言中使用变量来存储数据&#xff0c;变量必…

量化交易:因子风险暴露

本文介绍了如何计算因子风险暴露的内容。 判断风险暴露的建模是否合理 通常&#xff0c;此分析是基于历史数据&#xff0c;而对历史风险暴露的估计可能会影响未来的风险暴露。 因此&#xff0c;计算因子风险暴露是不够的。 必须对风险暴露保持信心&#xff0c;并明白对风险暴…

Vue框架学习笔记——键盘事件

文章目录 前文提要键盘事件&#xff08;并不是所有按键都能绑定键盘事件&#xff09;常用的按键不同的tab和四个按键keyCode绑定键盘事件&#xff08;不推荐&#xff09;Vue.config.keyCode.自定义键名 键码 神奇的猜想div标签和click.enterbutton标签和click.enter 前文提要 …

定长子网划分和变长子网划分问题_二叉树解法_通俗易懂_配考研真题

引入:定长子网划分和变长子网划分的基本概念 定长子网划分和变长子网划分的基本概念 目前常用的子网划分&#xff0c;是基于CIDR的子网划分&#xff0c;也就是将给定的CIDR地址块划分为若干个较小的CIDR地址块。 定长子网划分: 使用同一个子网掩码来划分子网&#xff0c;因…

【版本管理 | Git】Git rebase 命令最佳实践!确定不来看看?

&#x1f935;‍♂️ 个人主页: AI_magician &#x1f4e1;主页地址&#xff1a; 作者简介&#xff1a;CSDN内容合伙人&#xff0c;全栈领域优质创作者。 &#x1f468;‍&#x1f4bb;景愿&#xff1a;旨在于能和更多的热爱计算机的伙伴一起成长&#xff01;&#xff01;&…

智能优化算法应用:基于斑点鬣狗算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于斑点鬣狗算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于斑点鬣狗算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.斑点鬣狗算法4.实验参数设定5.算法结果6.参考…

VM虚拟机中Ubuntu14.04安装VM tools后仍不能全屏显示

1、查看Ubuntu所支持的分辨率大小。 在终端处输入&#xff1a; xrandr&#xff0c;回车 2、输入你想设置的分辨率参数。 我设置的为1360x768&#xff0c;大家可以根据自己的具体设备设置。 在终端输入&#xff1a;xrandr -s 1360x768 注意&#xff1a;这里1360后边是字母 x 且…

<JavaEE> Thread线程类 和 Thread的常用方法

目录 一、Thread概述 二、构造方法 三、常用方法 1.1 getId()、getName()、getState()、getPririty() 1.2 start() 1.3 isDaemon()、setDaemon() 1.4 isAlive() 1.5 currentThread() 1.6 Interrupt()、interrupted()、isInterrupted() 1.6.1 方法一&#xff1a;添加共…

S25FL系列FLASH读写的FPGA实现

文章目录 实现思路具体实现子模块实现top模块 测试Something 实现思路 建议读者先对 S25FL-S 系列 FLASH 进行了解&#xff0c;我之前的博文中有详细介绍。 笔者的芯片具体型号为 S25FL256SAGNFI00&#xff0c;存储容量 256Mb&#xff0c;增强高性能 EHPLC&#xff0c;4KB 与 6…

Java中static、final、static final的区别

文章目录 finalstaticstatic final final final可以修饰&#xff1a;属性&#xff0c;方法&#xff0c;类&#xff0c;局部变量&#xff08;方法中的变量&#xff09; final修饰的属性的初始化可以在编译期&#xff0c;也可以在运行期&#xff0c;初始化后不能被改变。 final修…

nginx配置文件的简单结构

nginx的配置文件&#xff08;nginx.conf&#xff09;整体上可分为三个部分&#xff1a;全局块、events块、http块 区域职责全局块配置和nginx运行相关的全局配置events块配置和网络连接相关的配置http块配置代理、缓存、日志记录、虚拟主机等配置在http块中&#xff0c;可以包含…

python:傅里叶分析,傅里叶变换 FFT

使用python进行傅里叶分析&#xff0c;傅里叶变换 FFT 的一些关键概念的引入&#xff1a; 1.1.离散傅里叶变换&#xff08;DFT&#xff09; 离散傅里叶变换(discrete Fourier transform) 傅里叶分析方法是信号分析的最基本方法&#xff0c;傅里叶变换是傅里叶分析的核心&…

摆脱无用代码的负担:TreeShaking 的魔力

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

【教学类-06-12】20231126 (一)如何让加减乘除题目从小到大排序(以1-20之间加法为例,做正序排列用)

结果展示 优化后 优化前 背景需求&#xff1a; 生成列表 单独抽取显示题目排序方法 存在问题: 我希望 00 01 02……这样排序&#xff0c;但是实际上&#xff0c;除了第一个加数会从小到大排序&#xff0c;第二个被加数的第十位数和个位数都会从小到大排序&#xff0c;也就是…

NeoPreference延伸:为SharedPreferences配置项生成配置页面

代码地址&#xff1a;https://github.com/Nagi1225/NeoPreference.git 最初在开发NeoPreference这个SharedPreferences工具的时候&#xff0c;就期望完成三个目标&#xff1a; 代码简洁&#xff0c;新增配置项的时候一行代码&#xff08;最多两行&#xff09;&#xff1b;读写…

线程的常用方法-wait和notify以及线程的结束方式

再复习一下Java中的线程的状态图 wait和sleep的区别是&#xff1a;wait需要先持有锁&#xff08;wait需要再synchronized代码块中执行&#xff09;&#xff0c;执行后会让出锁。而sleep不需要先持有锁&#xff0c;执行后也不会释放锁&#xff08;有锁的话抱着锁睡觉&#xff09…