【15系列】SYK-0806-A2S1 工业自动化控制之【08-步进电机启动和停止】
大家好,我是『芯知识学堂』的SingleYork,前一篇文章给大家介绍了“SYK-0806-A2S1 工业自动化控制之【07-定时器产生特定频率脉冲】”,这一篇中,笔者要给大家介绍如何定时器产生特定频率来控制步进电机。
在工业自动化控制中,相信大家对步进电机并不会陌生,工业上用的步进电机一般还会配一个专门的驱动器,
下图中就是其中的一款带驱动器的57型步进电机套件:
那么,我们先来看一下步进电机的控制原理:
根据上图中的步进电机的控制原理我们可以知道,通过控制器产生脉冲信号,
再经过步进电机驱动器将脉冲信号转化为步进电机的角位移,便可以让步进电机动起来了!
接下来我们看下步进电驱动器的接线方法。步进电机驱动器有三种接线方式,
即:共阳极接法、共阴极接法和差分方式接法,分别如下图所示:
步进电机一般有四线、六线和八线三种,三种电机的接线方式如下图所示:
一般买电机的时候,厂家会给出具体的接线图,本例中,笔者就是用的8线步进电机并行高速接法。驱动器采用的是共阳极接法。
线路连接好了,接下来我们就要来分析代码部分了。
首先,我们还是来说一下本例要实现的功能,本例中笔者是分两种方式来实现步进电机的启动与停止:
通过控制定时器0的启动与停止来实现电机0脉冲的输出与关闭
定时器2一直开启,通过一个变量来控制电机2的脉冲输出与关闭
具体控制逻辑如下:
当X00信号由低电平变成高电平时,电机0启动;
当X01信号由低电平变成高电平时,电机0停止;
当X02信号由低电平变成高电平时,电机2启动;
当X03信号由低电平变成高电平时,电机2停止;
控制逻辑弄清楚了,现在就可以来看代码部分了,首先,还是两个定时器的配置,本例中笔者还是将两个定时器单独来配置:
#include "bsp_timer.h"
/************************ 定时器配置 ****************************/
void Timer0_config(u32 TIM0_Fre)
{
TIM_InitTypeDef TIM_InitStructure; //结构定义
TIM_InitStructure.TIM_Mode = TIM_16BitAutoReload; //指定工作模式, TIM_16BitAutoReload,TIM_16Bit,TIM_8BitAutoReload,TIM_16BitAutoReloadNoMask
TIM_InitStructure.TIM_Polity = PolityLow; //指定中断优先级(低到高) Polity_0,Polity_1,Polity_2,Polity_3
TIM_InitStructure.TIM_Interrupt = ENABLE; //中断是否允许, ENABLE或DISABLE
TIM_InitStructure.TIM_ClkSource = TIM_CLOCK_1T; //指定时钟源, TIM_CLOCK_1T,TIM_CLOCK_12T,TIM_CLOCK_Ext
TIM_InitStructure.TIM_ClkOut = DISABLE; //是否输出高速脉冲, ENABLE或DISABLE
TIM_InitStructure.TIM_Value = 65536UL - (MAIN_Fosc / TIM0_Fre/2); //初值,
TIM_InitStructure.TIM_Run = ENABLE; //是否初始化后启动定时器, ENABLE或DISABLE
Timer_Inilize(Timer0,&TIM_InitStructure); //初始化Timer0 Timer0,Timer1,Timer2,Timer3,Timer4
}
void Timer2_config(u32 TIM2_Fre)
{
TIM_InitTypeDef TIM_InitStructure; //结构定义
TIM_InitStructure.TIM_Mode = TIM_16BitAutoReload; //指定工作模式, TIM_16BitAutoReload,TIM_16Bit,TIM_8BitAutoReload
TIM_InitStructure.TIM_Polity = PolityLow; //指定中断优先级, PolityHigh,PolityLow
TIM_InitStructure.TIM_Interrupt = ENABLE; //中断是否允许, ENABLE或DISABLE
TIM_InitStructure.TIM_ClkSource = TIM_CLOCK_1T; //指定时钟源, TIM_CLOCK_1T,TIM_CLOCK_12T,TIM_CLOCK_Ext
TIM_InitStructure.TIM_ClkOut = DISABLE; //是否输出高速脉冲, ENABLE或DISABLE
TIM_InitStructure.TIM_Value = 65536UL - (MAIN_Fosc / TIM2_Fre/2); //初值,
TIM_InitStructure.TIM_Run = ENABLE; //是否初始化后启动定时器, ENABLE或DISABLE
Timer_Inilize(Timer2,&TIM_InitStructure); //初始化Timer1 Timer0,Timer1,Timer2,Timer3,Timer4
}
然后,在app.c文件中的app_int()函数中调用Timer0_config()、Timer2_config()这两个函数对定时器0和定时器2分别进行初始化,
同时因为电机0是直接通过控制定时器0的启动和停止来控制电机启停的,所以这里还需先将定时器0关闭,即“TR0= 0;”:
void app_init(void)
{
GPIO_Config(); //GPIO配置
Timer0_config(Timer0_Fre); //定时器0配置
Timer2_config(Timer2_Fre); //定时器2配置
TR0= 0; //定时器0停止运行
EA = 1; //开启总中断
}
这里设定的定时器0和定时器2的输出时钟频率依然为1000Hz:
u32 Timer0_Fre = 1000UL;//timer0频率初值
u32 Timer2_Fre = 1000UL;//timer2频率初值
接下来,我们为了后面程序的可读性更强,笔者这里用了一些宏定义来配置电机0和电机2的对应的控制信号:
#define M0_PUL Y00 //定义电机0脉冲对应的GPIO
#define M2_PUL Y01 //定义电机2脉冲对应的GPIO
#define M0_Start X00 //定义电机0启动信号对应的GPIO
#define M0_StopX01 //定义电机0停止信号对应的GPIO
#define M2_Start X02 //定义电机2启动信号对应的GPIO
#define M2_StopX03 //定义电机2停止信号对应的GPIO
同时,还定义了一个变量用作电机2的脉冲输出使能控制:
bit F_Motor2_EN= 0; //电机2脉冲输出使能标志位
接下来,就是两个电机的控制逻辑部分了,还是跟之前一样,这部分的代码均放在了app_run()函数中,
首先我们先定义4个标志位,用于X00-X03的状态的判断:
static bit F_M0_Start = 0;
static bit F_M0_Stop= 0;
static bit F_M2_Start = 0;
static bit F_M2_Stop= 0;
这里可能大家注意到了,每个变量前面都加了结果static关键字,相信有一定基础的小伙伴们都应该能明白此处加这个关键字的作用,
试想一下,如果此处没有static这个关键字的话,那么F_M0_Start 、F_M0_Stop 、F_M2_Start 、F_M2_Stop
这四个变量的值是不是在每次进入app_run()这个函数的时候,都会被初始化一遍(即赋值0)?
这种情况肯定不是我们本例中想要的,因此,此处加static这个关键字是很有必要的。
废话不多说,附上app.c的完整代码吧,注释也比较全,相信大家一看就能理解了:
#include "app.h"
#define M0_PUL Y00 //定义电机0脉冲对应的GPIO
#define M2_PUL Y01 //定义电机2脉冲对应的GPIO
#define M0_Start X00 //定义电机0启动信号对应的GPIO
#define M0_StopX01 //定义电机0停止信号对应的GPIO
#define M2_Start X02 //定义电机2启动信号对应的GPIO
#define M2_StopX03 //定义电机2停止信号对应的GPIO
bit F_Motor2_EN= 0; //电机2脉冲输出使能标志位
u32 Timer0_Fre = 1000UL;//timer0频率初值
u32 Timer2_Fre = 1000UL;//timer2频率初值
/********************* APP初始化 ***********************/
void app_init(void)
{
GPIO_Config(); //GPIO配置
Timer0_config(Timer0_Fre); //定时器0配置
Timer2_config(Timer2_Fre); //定时器2配置
TR0= 0; //定时器0停止运行
EA = 1; //开启总中断
}
/********************* APP运行 ***********************/
void app_run(void)
{
static bit F_M0_Start = 0;
static bit F_M0_Stop= 0;
static bit F_M2_Start = 0;
static bit F_M2_Stop= 0;
/*****************************************
X00由低电平变成高电平时,电机0启动
*****************************************/
if(!F_M0_Start)
{
if(!M0_Start) //X00低电平
{
delay_ms(10); //10ms消抖
if(!M0_Start)
{
F_M0_Start = 1;//X00低电平标志置“1”
}
}
}
else
{
if(M0_Start) //X00高电平
{
delay_ms(10); //10ms消抖
if(M0_Start)
{
F_M0_Start = 0;//X00低电平标志清“0”
TR0 = 1;//定时器0开始运行
}
}
}
/*****************************************
X01由低电平变成高电平时,电机0停止
*****************************************/
if(!F_M0_Stop)
{
if(!M0_Stop) //X01低电平
{
delay_ms(10); //10ms消抖
if(!M0_Stop)
{
F_M0_Stop= 1;//X01低电平标志置“1”
}
}
}
else
{
if(M0_Stop) //X01高电平
{
delay_ms(10); //10ms消抖
if(M0_Stop)
{
F_M0_Stop= 0; //X01低电平标志清“0”
TR0 = 0; //定时器0停止运行
M0_PUL = OutputT_OFF; //Y00保持高电平
}
}
}
/*--------------------------------------*/
/*****************************************
X02由低电平变成高电平时,电机2启动
*****************************************/
if(!F_M2_Start)
{
if(!M2_Start) //X02低电平
{
delay_ms(10); //10ms消抖
if(!M2_Start)
{
F_M2_Start = 1;//X02低电平标志置“1”
}
}
}
else
{
if(M2_Start) //X02高电平
{
delay_ms(10); //10ms消抖
if(M2_Start)
{
F_M2_Start = 0;//X02低电平标志清“0”
F_Motor2_EN= 1;//电机2脉冲输出使能
}
}
}
/*****************************************
X03由低电平变成高电平时,电机2停止
*****************************************/
if(!F_M2_Stop)
{
if(!M2_Stop) //X03低电平
{
delay_ms(10); //10ms消抖
if(!M2_Stop)
{
F_M2_Stop= 1;//X03低电平标志置“1”
}
}
}
else
{
if(M2_Stop) //X03高电平
{
delay_ms(10); //10ms消抖
if(M2_Stop)
{
F_M2_Stop= 0;//X03低电平标志清“0”
F_Motor2_EN= 0;//电机2脉冲输出失能
}
}
}
}
/********************* Timer0中断函数************************/
void timer0_int (void) interrupt TIMER0_VECTOR //频率可变
{
M0_PUL = !M0_PUL; //Y00状态翻转
}
/********************* Timer0中断函数************************/
void timer2_int (void) interrupt TIMER2_VECTOR //频率可变
{
if(F_Motor2_EN) //电机2脉冲输出使能
M2_PUL = !M2_PUL; //Y01状态翻转
else
M2_PUL = OutputT_OFF; //Y01保持高电平
}
最后,笔者给大家看一下程序运行的效果吧:
好了,关于使用本节内容笔者就介绍到这里了,有疑问的小伙伴们可以给笔者留言或者直接参与评论,
下一节笔者将给大家介绍“如何让步进电机正反转运行”,详见“SYK-0806-A2S1 工业自动化控制之【09-步进电机正反转】”,感谢大家的支持!
本章附件:
步进电机启动与停止控制详解
引言
在工业自动化控制中,步进电机因其精确的位置控制和简单的驱动方式而被广泛应用。本文将详细介绍如何通过定时器产生特定频率的脉冲信号来控制步进电机的启动与停止。本文基于SYK-0806-A2S1工业自动化控制模块,结合STC15系列微控制器,实现步进电机的精确控制。
步进电机控制原理
步进电机的控制核心在于脉冲信号的生成。控制器通过产生特定频率的脉冲信号,驱动步进电机驱动器,进而将脉冲信号转化为步进电机的角位移。步进电机的运动精度和速度直接取决于脉冲信号的频率和数量。
步进电机驱动器接线方法
步进电机驱动器通常有三种接线方式:共阳极接法、共阴极接法和差分方式接法。不同的接线方式适用于不同的应用场景,用户需根据具体需求选择合适的接线方式。
1. 共阳极接法:所有控制信号的阳极连接在一起,适用于需要高电平驱动的场合。
2. 共阴极接法:所有控制信号的阴极连接在一起,适用于需要低电平驱动的场合。
3. 差分方式接法:通过差分信号驱动,适用于抗干扰要求较高的场合。
步进电机接线方式
步进电机一般有四线、六线和八线三种类型。不同的接线方式会影响电机的运行性能和控制精度。本文以八线步进电机为例,采用并行高速接法,驱动器采用共阳极接法。
代码实现
本文通过两种方式实现步进电机的启动与停止控制:
1. 定时器0控制:通过控制定时器0的启动与停止,实现电机脉冲信号的输出与关闭。
2. 定时器2控制:定时器2一直开启,通过一个变量控制电机的启动与停止。
定时器0控制代码示例
c
include
sbit MOTORPULSE = P1^0; // 定义脉冲输出引脚
void Timer0Init(void) {
TMOD |= 0x02; // 定时器0模式2,8位自动重装
TH0 = 0xFC; // 定时器初值
TL0 = 0xFC;
ET0 = 1; // 使能定时器0中断
EA = 1; // 使能总中断
}
void Timer0ISR(void) interrupt 1 {
MOTORPULSE = ~MOTORPULSE; // 翻转脉冲信号
}
void main(void) {
Timer0Init();
TR0 = 1; // 启动定时器0
while (1) {
// 主循环
}
}
定时器2控制代码示例
c
include
sbit MOTORPULSE = P1^0; // 定义脉冲输出引脚
bit motorrunning = 0; // 电机运行状态标志
void Timer2Init(void) {
T2MOD = 0x00; // 定时器2模式
RCAP2H = 0xFC; // 定时器初值高字节
RCAP2L = 0xFC; // 定时器初值低字节
ET2 = 1; // 使能定时器2中断
EA = 1; // 使能总中断
}
void Timer2ISR(void) interrupt 5 {
if (motorrunning) {
MOTORPULSE = ~MOTORPULSE; // 翻转脉冲信号
}
}
void main(void) {
Timer2Init();
TR2 = 1; // 启动定时器2
while (1) {
// 主循环
if (/ 启动条件 /) {
motorrunning = 1;
} else if (/ 停止条件 /) {
motorrunning = 0;
}
}
}
总结
通过定时器产生特定频率的脉冲信号,可以精确控制步进电机的启动与停止。本文详细介绍了步进电机的控制原理、接线方法以及代码实现,为工业自动化控制中的步进电机应用提供了实用的参考。希望本文能对广大工程师和爱好者有所帮助,推动工业自动化技术的进一步发展。
参考文献
1. STC15系列微控制器数据手册
2. 步进电机驱动器技术手册
3. 工业自动化控制技术指南
作者简介:SingleYork,芯知识学堂创始人,专注于嵌入式系统与工业自动化控制技术的研究与教学。
[本文内容由国芯人工智能辅助生成,仅供参考]
页:
[1]