【小白初学者】项目中遇到步进电机,别慌,照着改

2023-11-10

目录

前言:

实物:

共阴接法:

程序做法:

电源模块设置:

问题:

源代码:


前言:

首先面试时,当项目涉及了步进电机这一块,我们需要知道:

并不需要往底层等深钻,只需要懂基本原理,怎么配置引脚,开发中遇到一些问题及如何解决,可以大胆说出项目中用步进电机遇到的问题,diss缺陷。然后后面可以用matlab之类做一些高级点的东西。

我是因为一个项目需要驱动 丝杠机械装置运动和驱动一个迷你定制版的传送带,才开始接触步进电机的。为啥选步进电机,emm需要运转速度快、控制方便、成本稍低等,虽然缺点也挺明显的,噪音、发热、调速快了易失步,后面会说到。

在之前的必经项目 《智能小车》中,我们用到的是那种黄色的直流电机,就直接通过两端的电压正负来直接控制旋转的方向,通过两端的电压大小来控制旋转的速度。直流电机也是有PWM调速版本的,所以我们也是可以将那种黄色的直流电机改造成PWM调速版本。

步进电机:比较大块头,常卖的小个头都比直流电机的大。步进电机是将电脉冲信号转变为角位移或者线位移的开环控制电机,又称脉冲电机。嗯,步进电机和脉冲电机是一回事。对于它,你可以有一个很直观的看法,那就是读脉冲个数。来多少个脉冲,它就转相应的角度,并且这个角度是可以计算的!

实物:

42步进电机,12V变压器,电源驱动模块,电线若干,共阴接法

42步进电机:

TB6600两相32细分4.0A大电流步进电机驱动模块:

电源电压适合DC:9~42VDC

12V变压器:


共阴接法:

电源模块中,变压器接的GND不要把单片机引脚的GND搁上去。

下图中,红色的GND是接单片机的,下面的白色GND是接电源模块。

步进电机如何区分AB相?

很简单,只需要你把步进电机的随意两根线接在一起,然后去手动转一下步进电机,很难转动就是说明这两根线属于同一相,A,B随意。

一般同相的两个线是相连的。

电源模块接好之后

接法可以从图中见,接出来的两条线就是接到电源驱动模块最下面的那个VCC和GND。


程序做法:

首先是初始化:

很明显,我们需要三个引脚,且其中一个是PWM输出的引脚,我们随便来三个,哪个顺眼用哪个:

这三个引脚的功能通过名称也很好判断,EN应该是使能,DIR应该是转向,Pluse是脉冲信号口。

名称 引脚 高电平(设置为1) 低电平(设置为0)
Pluse+ PA.1
DIR+ PA.8 顺时针运转 逆时针运转
EN+ PA.2 不工作 使能输出

long current_pos[2]={0,0}; //有符号方向
DIR_Type motor_dir2=0;
u8 count[2]={0,0};

先初始化PA2,PA8:

void Driver_Init(void)
{
    GPIO_InitTypeDef  GPIO_InitStructure;
​
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);   //使能PA端口时钟
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2|GPIO_Pin_8;    //端口配置
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;        //推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;       //IO口速度为50MHz
    GPIO_Init(GPIOA, &GPIO_InitStructure);                  //根据设定参数初始化GPIOA
    
    GPIO_ResetBits(GPIOA,GPIO_Pin_2);                       //PA11输出低 使能输出  DRIVER_OE
    GPIO_SetBits(GPIOA,GPIO_Pin_8);                         //PA8输出高 顺时针方向  DRIVER_DIR  
}

选自正点原子案例历程:

初始化TIM2:


/***********************************************
//TIM2_CH2(PA1) 单脉冲输出+重复计数功能初始化
//TIM2 时钟频率 72MHz
//arr:自动重装值
//psc:时钟预分频数
************************************************/
void TIM2_Init(u16 arr,u16 psc)
{                            
    GPIO_InitTypeDef GPIO_InitStructure;
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    TIM_OCInitTypeDef  TIM_OCInitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
​
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);    //TIM2时钟使能
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);  //使能GPIOA外设时钟使能                                                                         
​
  //设置该引脚为复用输出功能,输出TIM2 CH2的PWM脉冲波形
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;               //TIM2_CH2
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;         //复用推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
    
    TIM_TimeBaseStructure.TIM_Period = arr;                 //设置在下一个更新事件装入活动的自动重装载寄存器周期的值,设置计数到这个值就产生溢出  
    TIM_TimeBaseStructure.TIM_Prescaler =psc;               //设置用来作为TIMx时钟频率除数的预分频值  
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;            //设置时钟分割:TDTS = Tck_tim,是改变作输入捕获时滤波用的并不是定时器的分频器
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);         //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
    TIM_ClearITPendingBit(TIM2,TIM_IT_Update);              //清除的是一些中断标志位
​
    TIM_UpdateRequestConfig(TIM2,TIM_UpdateSource_Regular); //TIM_UpdateSource_Regular 生成单一的脉冲:计数器在下一个更新事件停止,即关闭    
    TIM_SelectOnePulseMode(TIM2,TIM_OPMode_Single);         //单脉冲模式 
 
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;       //选择定时器模式:TIM脉冲宽度调制模式2[1]
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出2使能
    TIM_OCInitStructure.TIM_Pulse = arr>>1;                 //设置待装入捕获比较寄存器的脉冲值
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高[2]
    //----[1][2]这两个配合一起然后查手册可以得到->当计时器值小于比较器设定值时则TIMX输出脚此时输出有效低电位。
    TIM_OC2Init(TIM2, &TIM_OCInitStructure);                //根据TIM_OCInitStruct中指定的参数初始化外设TIMx
​
    TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable);       //CH2预装载使能   
    TIM_ARRPreloadConfig(TIM2, ENABLE);                     //使能TIMx在ARR上的预装载寄存器
    
    TIM_ITConfig(TIM2, TIM_IT_Update ,ENABLE);              //TIM2使能或者失能指定的TIM中断
 
    NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;         //TIM2中断
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //先占优先级0级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;      //从优先级0级
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;         //IRQ通道被使能
    NVIC_Init(&NVIC_InitStructure);                         //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
    
    TIM_ClearITPendingBit(TIM2, TIM_IT_Update);             //清除TIMx的中断待处理位:TIM 中断源
    TIM_Cmd(TIM2, DISABLE);                                 //使能TIM2                                      
}

设置TIM2中断函数:

void TIM2_IRQHandler(void)
{
    if(TIM_GetITStatus(TIM2,TIM_FLAG_Update)!=RESET)//更新中断
    {
        TIM_ClearITPendingBit(TIM2,TIM_FLAG_Update);//清除更新中断标志位     
        count[0]++; 
        TIM_GenerateEvent(TIM2,TIM_EventSource_Update);//产生一个更新事件 重新初始化计数器,
        //这里产生一个脉冲送到步进电机让电机运转一个脉冲数,即不细分的情况下,一般步进电机转1.8°
        //定时器初始化中,设置单脉冲模式是让计数器在下一个更新事件停止,即关闭,防止这次中断还没结束,
        //下一个计数器时间已经到了使中断紊乱,也就是进入中断后,定时器自动关闭。           
        TIM_Cmd(TIM2, ENABLE);                         //使能TIM2,让定时器开始下一个脉冲计数后输出    
        if(count[0]==200)
        {
            if(motor_dir2==CW)                         //如果方向为顺时针   
                current_pos[0]+=count[0];
            else                                       //否则方向为逆时针
                current_pos[0]-=count[0];
            TIM_Cmd(TIM2, DISABLE);                    //关闭TIM2         
            printf("motor2当前位置=%ld\r\n",current_pos[0]);//打印输出
            count[0]=0;
        }
    }
}

TIM启动函数:

void TIM2_Startup(u32 frequency)   //启动定时器2
{
    u16 temp_arr=1000000/frequency-1; 
    TIM_SetAutoreload(TIM2,temp_arr);//设定自动重装值  
    TIM_SetCompare2(TIM2,temp_arr>>1); //匹配值2等于重装值一半,是以占空比为50%,这个是一半高电平,一半低电平,
    //定时器计数到最高或最低就是产生一个脉冲,脉冲从这里发送到PA1(TIM2_CH2  ),占空比越大,输出的电压越大。
    TIM_SetCounter(TIM2,0);//计数器清零
    TIM_Cmd(TIM2, ENABLE);  //使能TIM2
}

业务处理函数:

/********************************************
//相对定位函数 
//num 0~2147483647
//frequency: 20Hz~100KHz
//dir: CW(顺时针方向)  CCW(逆时针方向)
*********************************************/
void Locate_Rle2(u32 frequency,DIR_Type dir) //相对定位函数
{
    
    if(TIM2->CR1&0x01)//上一次脉冲还未发送完成  直接返回,TIM2->CR1=0x01是使能定时器,
        //上面中断2函数进入后,产生一个脉冲,然后定时器自动关闭,再程序中开启,即TIM2->CR1=0x01
    {
        printf("\r\nThe last time pulses is not send finished,wait please!\r\n");
        return;
    }
    if((frequency<20)||(frequency>100000))//脉冲频率不在范围内 直接返回
    {
        printf("\r\nThe frequency is out of range! please reset it!!(range:20Hz~100KHz)\r\n");
        return;
    }
    motor_dir2=dir;//将枚举类型为DIR_Type的dir的值赋值给另一个枚举类型motor_dir2,方便在中断中判断motor_dir2是否为正
    //然后在中断中的current_pos[0]进行总和计算出当前的位置
    DRIVER_DIR2=motor_dir2;              //将旋转方向赋值给DRIVER_DIR2所定义的接口
    TIM2_Startup(frequency);                 //开启TIM2
}

main函数

int main(void)
{    
    delay_init();               //延时函数初始化     
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);      //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
    Driver_Init();              //驱动器初始化
    TIM2_Init(999,72-1);        //1MHz计数频率,第一个参数自动装载值在后面TIM2_Startup函数中会被改变
    while(1) 
    {   
        Locate_Rle2(800,CW);//500的意思你点进去看函数就明白了,大概就是重新设置定时器自动重装载值,让PWM一半高电平,
    }           
}
​

通电复位,就正转。多少圈,这个还跟你的电源驱动模块的设置有关:


电源模块设置:

如上图左侧,有S1--S6 6个开关,它们在模块的上方:

往上拨就是OFF,往下拨就是ON,具体看自己买的电源模块。

都是啥意思呢?

MicroStep,细分步距,

Pulse/rev,多少个脉冲一圈

我买的步进电机的步距角是1.8°,就是一个脉冲转1.8°,具体看你们自己买的步进电机的参数。假设你用到3D打印机上,要很精密的,就叫你称1.79°的瓜,错了,1.79°的角度,你如何实现?这时候就要细分了。

如调到400,那就是步进电机转一圈需要400个脉冲,这样就能到0.9°

Current(A),PK Current,设置电流参数,也是要看着自己的步进电机的额定电流来设置的。

我的设置:

S1 S2 S3 S4 S5 S6
ON ON OFF ON OFF ON

就是初始设置,一个脉冲 1.8°


问题:

下面额想到一些面试问题,不过好像很少问这种的:

1.为什么项目中用步进电机?

呃,因为这个项目涉及到传送带和丝杠机械装置的驱动控制,需要的扭矩普通的直流电机远远达不上,所以选用了步进电机。而且步进电机可以很精准的控制旋转的方向和度数,丝杠运动也可以得到精确限位。

2.一套步进电机怎么接?

emm,这个在上面就提到了,转述一下就可以了。

3.开发中最困难的点?

1.初始化配置,有点多且复杂,还要写定时器中断函数之类,还有一个小坑就是上一个没有执行完就开始下一步的命令,这需要判断一下,并且所有函数先经过这个判断函数才可以进行下一步。

2.优先级的设置,电机在运转时,TIM中断函数会打断原来主函数的进行,如果没有设置好的话,那就会成为电机运行中,单片机其他所有服务都会被限制,更可能直接停止。所以优先级也是一个大的问题。

3.开发中的噪音,发热问题,无法解决,尤其是步进电机驱动丝杠时,有一定载荷的时候,就一直搁那发出大的噪音,听到人实在难受。而且在正转后再反转这种稍微密集一点的操作就开始发热发烫。还好工作过程中并未有接触,倒也可以接受。

4.....

不公开部分)


源代码:

下面的工程基本配置

/*
步进电机1,由按键PA.0控制
Pluse+->PA.1,Pluse-接GND
DIR+->PA.8,DIR-接GND0
EN+->PA.2,EN-接GND   
​
KEY1-->PA.0   正转
KEY2-->PC.13  反转
*/

实现两个按钮控制一个步进电机的正反转。

奶牛快传:

奶牛快传 | 免费大文件传输工具,上传下载不限速 点击链接查看 [ 单步进电机控制.rar ] ,或访问奶牛快传 cowtransfer.com 输入传输口令 37twbn 查看;

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【小白初学者】项目中遇到步进电机,别慌,照着改 的相关文章

  • 补码的作用

    补码的作用 避免零在二进制中的歧义 另一个好处就是方便运算 所有运算都能用加法运算器来实现 不再需要减法运算器 其实在计算机中 所有的减法操作都被转化为加法操作 如果想要深入研究 可以看看计算机组成原理 举个简单的例子 正数的补码和反码 原
  • 《Learning CUDA Programming》读书笔记(三)

    CUDA occupancy 一般等于 Active Thread Blocks per Multiprocessor Max Threads per Multiprocessor 分子是用户kernel和GPU硬件条件共同决定的 分母完全
  • Java SPI机制

    一 SPI机制简介 SPI的全名为Service Provider Interface java spi机制的思想 系统里抽象的各个模块 往往有很多不同的实现方案 在面向的对象的设计里 一般推荐模块之间基于接口编程 模块之间不对实现类进行硬
  • 完全分布式Hadoop集群搭建

    环境说明 操作系统 CentOS 8 x86 64 Hadoop版本 2 10 1 节点数 3 服务器规划 node1 node2 node3 199 188 166 111 199 188 166 112 199 188 166 113
  • 去趋势理解(detrend)

    https blog csdn net wokaowokaowokao12345 article details 60138308

随机推荐

  • 开漏输出、推挽输出、上拉电阻的原理及用途

    一 开漏输出 open drain 开漏电路概念中提到的 漏 就是指MOS FET的漏极 开漏主要是为了获得更大的驱动而来的 一般外面需要加上拉电阻 或下拉电阻 开楼电路的内部所有上拉全部断开 若要使用 必须在外部加上拉电阻 这样的话 其驱
  • JavaScript笔记:函数作用域和块作用域

    1 函数中的作用域 考虑如下的代码 function foo a var b 2 一些代码 function bar 更多的代码 var c 3 在这个代码片段中 foo 的作用域中包含了标识符 a b c 和 bar bar 拥有自己的作
  • 软件测试判断题总结

    判断题 1 验收测试是由最终用户来实施的 解析 当软件以项目的形式出现 那么验收测试由最终用户来实施的情况是比较长见的 但是对于产品形式的软件 生产企业内部的验收测试会更多 2 软件测试的目的是尽可能多的找出软件的缺陷 3 Beta测试是验
  • java的前期绑定和后期绑定

    原文地址 http blog sina com cn s blog 600046120100wdza html 程序绑定的概念 绑定指的是一个方法的调用与方法所在的类 方法主体 关联起来 对java来说 绑定分为静态绑定和动态绑定 或者叫做
  • 运算放大器(运放)选型、参数分析以及应用OPA2350

    1 运放选型速记指南 知乎 本文章旨在总结备份 方便以后查询 由于是个人总结 如有不对 欢迎指正 另外 内容大部分来自网络 书籍 和各类手册 如若侵权请告知 马上删帖致歉 运放 作为硬件电路上不可缺失的一部分 生活中也经常出现 因此在这里记
  • GCC同时使用静态库和动态库链接

    一原文连接 http blog csdn net wangzhen209 article details 47153239 GCC同时使用静态库和动态库链接 在应用程序需要连接外部库的情况下 linux默认对库的连接是使用动态库 在找不到动
  • What is tethering and how do you enable tethering?

    https 3g co uk guides tethering everything you need to know What is tethering and how do you enable tethering 30 Sep 201
  • 线性回归方程

    线性回归方程在嵌入式开发中是非常常用的 尤其在参数校准这块应用非常普遍 无论你是写在上位机代码中 还是直接写在嵌入式软件中 下面是我在PT100校准中写的关于线性回归方程代码 线性回归方程公式 平均值XA X1 X2 XN N 平均值YA
  • c语言用自动机识别字符串,C语言 字符串匹配算法

    字符串匹配算法 一 简介 收藏 注 本文大致翻译自EXACT STRING MATCHING ALGORITHMS 去掉一些废话 增加一些解释 文本信息可以说是迄今为止最主要的一种信息交换手段 而作为文本处理中的一个重要领域 字符串匹配 就
  • malloc函数两个使用实例

    第一个例子用malloc函数实现一维数组的模拟 include
  • CentOS 7中添加一个新用户并授权

    创建新用户 创建一个用户名为 linuxidc root localhost adduser linuxidc 为这个用户初始化密码 linux会判断密码复杂度 不过可以强行忽略 root localhost passwd linuxidc
  • 【机器学习】聚类【Ⅴ】密度聚类与层次聚类

    主要来自周志华 机器学习 一书 数学推导主要来自简书博主 形式运算 的原创博客 包含自己的理解 有任何的书写错误 排版错误 概念错误等 希望大家包含指正 由于字数限制 分成五篇博客 机器学习 聚类 基础知识与距离度量 机器学习 聚类 原型聚
  • JavaScript中,for in 和for of的区别

    for in 遍历的是数组的索引 即键名 而 for of 遍历的是数组元素值 即键值 for in 循环出的是 key for of 循环出的是 value 推荐在循环对象属性的时候使用 for in 在遍历数组的时候的时候使用 for
  • EDAS 系统check上传稿件时提示PDF中存在未内嵌的字体

    问题描述 在上传稿件时 系统提示 upload failed One or more fonts are not embedded See EDAS FAQ 并给出了字体未内嵌图片所在位置 提供的解决方案需要从配置环境开始 重新绘制图片 比
  • Theano下用CNN(卷积神经网络)做车牌中文字符OCR

    之前时间一直在看 Michael Nielsen 先生的 Deep Learning 教程 用了他的代码在theano下测试了下中文车牌字符的识别 由于我没有GPU 简单的在进行了16个epoch之后 识别率达到了 98 41 由于图像本来
  • 简单易懂,终于搞明白怎么用nginx在vue开发环境中跨域了,详细

    先说一下vue自己的proxy跨域 毕竟作为前端这个很简单 也更方便 vue cli3 x中 vue cli2 0版本在config文件夹index js中设置 proxyTable 设置方法一样 在新建的vue cofig js里 dev
  • 算法设计与分析——分治法

    归并排序 算法流程 归并排序 分解数组 递归求解 合并排序 步骤 1 首先将待排序的数组不断两两分解直至每一组只有一个元素 2 构建有序数组 两两合并 伪代码 递归式求解 递归树法 代入法 主定理法 最大子数组问题 快速排序 步骤 划分 选
  • vue项目中swipe自定义pagination,navigationButton,鼠标滑过暂停播放

    最近在vue项目中使用了swipe 为了修改样式踩了不少坑记录一下 先上最终成果图 项目要求自定义分页器 前后按钮 以及鼠标滑过时暂停轮播 下载安装 npm install swiper 5 x vue awesome swiper 注意一
  • p值校正,FDR(BH法)的实现过程

    原理 我们要看下最常用的BH法的论文 做m次无效假设作物的数量 那么 被错误地拒绝了的无效假设的比例Q V V S V R 所谓的FDR值就是Q的期望值 E Q E V R 如果无效假设是正确的 s 0且v r FDR值就和FWER fam
  • 【小白初学者】项目中遇到步进电机,别慌,照着改

    目录 前言 实物 共阴接法 程序做法 电源模块设置 问题 源代码 前言 首先面试时 当项目涉及了步进电机这一块 我们需要知道 并不需要往底层等深钻 只需要懂基本原理 怎么配置引脚 开发中遇到一些问题及如何解决 可以大胆说出项目中用步进电机遇