历史上的今天
今天是:2025年07月29日(星期二)
2019年07月29日 | 基于STM32F4单片机对步进电机的控制
2019-07-29 来源:eefocus
步进电机简介
步进电机是将电脉冲控制信号转变为角位移或线位移的一种常用的数字控制执行元件,又称为脉冲电机。在驱动电源的作用下,步进电机受到脉冲的控制,其转子的角位移量和速度严格地与输入脉冲的数量和脉冲频率成正比。步进电机每接收一个电脉冲,转子就转过一个相应的角度(步距角)。**改变通电顺序可改变步进电动机的旋转方向;改变通电频率可改变步进电动机的转速。**因此,通过控制输入电脉冲的数目、频率及电动机绕组的通电顺序就可以获得所需要的转角、转速及转向,利用单片机就可以很容易实现步进电机的开环数字控制。
传统的步进电机控制方法是由触发器产生控制脉冲来进行控制的,但此种控制方法工作方式单一而且难于实现人机交互,当步进电机的参数发生变化时,需要重新进行控制器的设计。因此适合于单片机控制,单片机通过向步进电机驱动电路发送控制信号就能实现对步进电机的控制。
PWM调速方法
在步进电机控制系统中可以通过输人PWM波的方法来对步进电动的运动进行控制。PWM波的产生可以通过时钟频率、自动重装值等参数进行设置,从而调节PWM波的占空比和输出频率。
脉冲宽度调制(PWM),是英文“Pulse Width Modulation” 的缩写,简称脉宽调制,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术。简单一点,就是对脉冲宽度的控制, PWM 原理如图:

我们假定定时器工作在向上计数 PWM模式,且当 CNT小于CCRx 时,输出 0,当 CNT大于等于CCRx 时输出 1。那么就可以得到如上的 PWM示意图:当 CNT 值小于 CCRx 的时候, IO 输出低电平(0),当 CNT 值大于等于 CCRx 的时候,IO 输出高电平(1),当 CNT 达到 ARR 值的时候,重新归零,然后重新向上计数,依次循环。改变 CCRx 的值,就可以改变 PWM 输出的占空比,改变 ARR 的值,就可以改变 PWM 输出的频率,这就是 PWM 输出的原理。,
通过控制脉冲占空比来改变电机的电枢电压.改变占空比的方法有3种:(1)定宽调频法,这种方法是保持t1不变,只改变t2,这样周期(T或频率)也随之改变;(2)调宽调频法,保持t1不变,而改变t2,这样也使周期T(或频率)改变;(3)定频调宽法,这种方法是使周期(T或频率)不变,而同时改变t1和t2.由于前两利,方法都改变了周期(或频率),当控制频率与系统的固有频率接近时,将会引起振荡,用的比较少,因此本系统用的是定频调宽法.在脉冲作用下,当电机通电时,速度增加.电机断电时,速度逐渐减小.只要按一定规律,改变通断电时间,即可实现对电机的转速控制。
系统硬件电路
系统硬件电路设计框图如下:

通过对STM32F4单片机编写程序实现对步进电机的控制,并且可以利用计算机和单片机的串口通信,接收到单片机所反馈回来的控制数据,包括:**步进电机的正向转动、反向转动、步进电机的定位功能以及调速功能。**要实现上述功能需要对STM32F4的以下模块进行设置,主要包括:串口通信模块、按键输入模块、电机驱动模块三大部分。下面就以重要模块的实现过程来进行详细的论述。
串口通信模块
串口作为 MCU 的重要外部接口,同时也是软件开发重要的调试手段, 其重要性不言而喻。现在基本上所有的 MCU 都会带有串口, STM32 自然也不例外。STM32F4 的串口资源相当丰富的,功能也相当强劲。 ALIENTEK 探索者 STM32F4 开发板所使用的 STM32F407ZGT6 最多可提供 6 路串口,有分数波特率发生器、支持同步单线通信和半双工单线通讯、支持 LIN、 支持调制解调器操作、 智能卡协议和 IrDA SIR ENDEC 规范、具有 DMA 等。
处理器与外部设备通信的两种方式:
并行通信:
-传输原理:数据各个位同时传输。
-优点:速度快
-缺点:占用引脚资源多
串行通信:
-传输原理:数据按位顺序传输。
-优点:占用引脚资源少
-缺点:速度相对较慢
这里我们选用串行通信。串行通信按照数据传送方向,分为:
单工:
数据传输只支持数据在一个方向上传输
半双工:
允许数据在两个方向上传输,但是,在某一时刻,只允许数
据在一个方向上传输,它实际上是一种切换方向的单工通信;
全双工:
允许数据同时在两个方向上传输,因此,全双工通信是两个
单工通信方式的结合,它要求发送设备和接收设备都有独立
的接收和发送能力。
这里我们给出串口配置的一般步骤:
①串口时钟使能:RCC_APBxPeriphClockCmd();
GPIO时钟使能:RCC_AHB1PeriphClockCmd();
② 引脚复用映射:
GPIO_PinAFConfig();
③GPIO端口模式设置:GPIO_Init(); 模式设置为GPIO_Mode_AF
④串口参数初始化:USART_Init();
⑤开启中断并且初始化NVIC(如果需要开启中断才需要这个步骤)
NVIC_Init();
USART_ITConfig();
⑥使能串口:USART_Cmd();
⑦编写中断处理函数:USARTx_IRQHandler();
⑧串口数据收发:
void USART_SendData();//发送数据到串口,DR
uint16_t USART_ReceiveData();//接受数据,从DR读取接受到的数据
⑨串口传输状态获取:
FlagStatus USART_GetFlagStatus();
void USART_ClearITPendingBit();
相关代码如下:
void uart_init(u32 bound) //GPIO端口设置
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); //使能GPIO时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//使能USART1
GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1); //使能GPIOA9时钟
GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1); //使能GPIOA10时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; //GPIOA9与GPIOA10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //速度50MHZ
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用功能
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉
GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化PA9,PA10
USART_InitStructure.USART_BaudRate = bound;//波特率设置
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式
USART_Init(USART1, &USART_InitStructure); //初始化串口1
USART_Cmd(USART1, ENABLE); //使能串口1
#if EN_USART1_RX
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启相关中断
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//串口1中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;//抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority =3; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
}
void USART1_IRQHandler(void) //串口1中断服务程序
{
u8 Res;
#if SYSTEM_SUPPORT_OS
//如果SYSTEM_SUPPORT_OS为真,则需要支持OS
OSIntEnter();
#endif
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断(接受到的数据必须是0x0d 0x0a结尾)
{
Res =USART_ReceiveData(USART1);//(USART1->DR); //(USART1->DR);//读取接收到的数据
if((USART_RX_STA&0x8000)==0)//接收未完成
{
if(USART_RX_STA&0x4000)//接收到了0x0d
{
if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始
else USART_RX_STA|=0x8000; //接收完成了
}
else //还没收到0X0D
{
if(Res==0x0d)USART_RX_STA|=0x4000;
else
{
USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
USART_RX_STA++;
if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收
}
}
}
}
#if SYSTEM_SUPPORT_OS
//如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
OSIntExit();
#endif
}
#endif
按键输入模块
STM32F4开发板上的按键 KEY0 连接在 PE4 上、 KEY1 连接在 PE3 上、 KEY2 连接在 PE2 上、 KEY_UP连接在 PA0 上。 如图所示:

在此次实验中,我们设置按下 KEY-UP, 电机以 所设定频率回到绝对原点; 按下 KEY0, 电机以所设定频率顺时针转动; 按下 KEY1, 电机以所设定频率逆时针转动。
下面给出实现按键输入的一般步骤:
①使能按键对应IO口时钟。调用函数:
RCC_AHB1PeriphClockCmd ();
②初始化IO模式:上拉/下拉输入。调用函数:
GPIO_Init();
③扫描IO口电平(库函数/寄存器/位操作)。
相关代码如下:
void KEY_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA|RCC_AHB1Periph_GPIOE, ENABLE);//使能GPIOA,GPIOE时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4; //KEY0 KEY1 KEY2对应引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;//普通输入模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100M
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
GPIO_Init(GPIOE, &GPIO_InitStructure);//初始化GPIO2,3,4
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;//WK_UP对应引脚 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN ;//下拉
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA0
}
u8 KEY_Scan(u8 mode)
{
static u8 key_up=1;//按键松开标志
if(mode)key_up=1; //支持连接
if(key_up&&(KEY0==0||KEY1==0||KEY2==0||WK_UP==1))
{
delay_ms(10);//去抖动
key_up=0;
if(KEY0==0)return 1;
else if(KEY1==0)return 2;
else if(KEY2==0)return 3;
else if(WK_UP==1)return 4;
}else if(KEY0==1&&KEY1==1&&KEY2==1&&WK_UP==0)key_up=1;
return 0;// 无按键按下
}
电机驱动模块
电源与驱动器连接方法如下图:

驱动器与STM32F4连接如下图:

代码需要用到的 4 个主要函数如下:
void Driver_Init(void);//驱动器初始化
void TIM8_OPM_RCR_Init(u16 arr, u16 psc); //TIM8_CH2 初始化 单脉冲+重复计数模式
void Locate_Rle(long num, u32 frequency, DIR_Type dir) //相对定位函数
void Locate_Abs(long num, u32 frequency);/绝对定位函数
1)驱动器初始化函数,主要就是初始化与驱动器 ENA+,DIR+相连的 2 个 IO为推挽输出。
2) TIM8_CH2 初始化, 此例程产生脉冲所使用的定时器均是 TIM8_CH2(PC7) ,定时器工作在单脉冲+重复计数模式,需要注意的是定时器必须初始化为 1MHz 计数频率。
3) 相对定位函数: 在步进电机当前位置基础上顺时针(CW)或者逆时针(CCW)走 num 个脉冲, 此函数带方向控制, DIR_Type 是 driver.h 下声明的一个枚举类型,用于设置电机旋转方向,参数 dir=CW,电机顺时针旋转; dir=CCW,电机逆时针旋转。
绝对定位函数:步进电机按设定频率转动到设置的绝对位置, 开发板上电和复位时,当前位置为 0,电机的当前位置用一个 long 型变量 current_pos 指示。 在current_pos=0 的基础上顺时针转动后 current_pos 为正, 否则为负。 5) 此例程配置了 usmart 函数和按键函数,可以通过按键或者串口调用相对定位函数和绝对定位函数控制驱动器,从而控制步进电机。
驱动模块代码如下:
u8 rcr_remainder; //重复计数余数部分
u8 is_rcr_finish=1; //重复计数器是否设置完成
long rcr_integer; //重复计数整数部分
long target_pos=0; //有符号方向
long current_pos=0; //有符号方向
DIR_Type motor_dir=CW;//顺时针
驱动控制信号线初始化:
void Driver_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);//使能GPIOE时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_6; //DRIVER_DIR DRIVER_OE对应引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100M
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
GPIO_Init(GPIOE, &GPIO_InitStructure);//初始化GPIOE5,6
GPIO_SetBits(GPIOE,GPIO_Pin_5);//PE5输出高 顺时针方向 DRIVER_DIR
GPIO_ResetBits(GPIOE,GPIO_Pin_6);//PE6输出低 使能输出 DRIVER_OE
}
单脉冲+重复计数模式:
void TIM8_OPM_RCR_Init(u16 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8,ENABLE); //TIM8时钟使能
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE); //使能PORTC时钟
GPIO_PinAFConfig(GPIOC,GPIO_PinSource7,GPIO_AF_TIM8); //GPIOC7复用为定时器8
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; //GPIOC7
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //复用功能
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //速度100MHz
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN; //下拉
GPIO_Init(GPIOC,&GPIO_InitStructure); //初始化PF9
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(TIM8, &TIM_TimeBaseStructure); //根据TIM_TimeBaseStructure中指定的参数化TIMX的时间基数单位
TIM_ClearITPendingBit(TIM8,TIM_IT_Update);
TIM_UpdateRequestConfig(TIM8,TIM_UpdateSource_Regular); /********* 设计只有计数溢出作为更新中断 ********/
TIM_SelectOnePulseMode(TIM8,TIM_OPMode_Single);/******* 单脉冲模式**********/
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //选择定时器模式:TIM脉冲宽度调制模式2
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出2使能
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable; /****** 比较输出2N使能 *******/
史海拾趣
|
本帖最后由 jameswangsynnex 于 2015-3-3 20:02 编辑 烧录一般是指使用刻录机把数据刻录(也称烧录)到刻录盘。现在有CD、DVD两种刻录盘,后者容量要比前者大的多,烧录就象COPY一样。把你电脑里的东西COPY在别的文件载体上,就象1.4寸的磁盘就可 ...… 查看全部问答> |
|
Array And Phased Array Antenna Basics 书本效果很不错~ 希望大家喜欢~ Array and Phased Array Antenna Basics by Hubregt J. VisserArray and Phased Array Antenna Basics introduces the principles of array and phased array antennas. Packed with first-handpractical exper ...… 查看全部问答> |
|
怎么判断WindowsMobile集成了红外模块,红外设备怎么开关? 没有找到API来判断设备是否支持红外。 在一篇文章中提到:红外通信中,一般而言红外并没有开启、关闭之类的状态。 难道红外设备就不能开关了? 但在一些WM手机的“通信管理”中,是可以打开关闭红外的,求解。… 查看全部问答> |
|
提供wince5.0(or ce6.0 R1) MLC解决方案 只需要替换微软FAL.lib即可支持MLC nand flash support: garbage collection, wearleveling, quick bootup(less than 10s with 4GB nand fully filled), power loss protection. pass tests: CETK, sudden power loss, read/write 只需要lib使用 ...… 查看全部问答> |
|
本人还在上学,要写毕业论文。很想搞一个和航空有关的项目。因为学校有一台真机,供研究用的。导师提议我可以用软件模拟巡航速度的控制,其实汽车也有这个系统。 看了一点资料,发现很多都和自适应控制有关。 我以前只学过C++,学了点JAVA,编过 ...… 查看全部问答> |
|
前面的 之三 写得很辛苦。我当时说,这一篇对于你直接点亮LED就有直接帮助,当时我以为我说完 数据传送类 指令的时候,大家就明白了,不好意思,我再一次食言了。 &n ...… 查看全部问答> |
|
【课后练习】launchpad课后练习十三 之 DAC0832学习 launchpad课后练习十三 之 DAC0832学习 1.DAC0832芯片介绍 * D0~D7:8位数据输入线,TTL电平,有效时间应大于90ns(否则锁存器的数据会出错); * ILE:数据锁存允许控制信号输入线,高电平有效; * CS:片选信号输入线(选通数据锁 ...… 查看全部问答> |
|
教材上、网上搜索的都是使用事件管理器EVA、EVB实现PWM输出,但tms320f2808的资料上没有事件管理器,只有ePWM模块的介绍。它们之间有什么对应关系呢? 我看这两部分的寄存器名称都不一样,不知到底怎样使用,在2808头文件找不到EVA、EVB等寄存器。… 查看全部问答> |
|
本帖最后由 paulhyde 于 2014-9-15 03:04 编辑 全国的同学都来南邮,我们南京那么多学校做A题,江苏那么多同学做A题,现在都不能再去南邮了。 只拿了省一,但是没有进入复测,是不是没有机会全国二等奖了呢? … 查看全部问答> |
|
用于可编程逻辑控制器 (PLC) 的 16 位模拟输出模块参考设计描述 此参考设计提供适用于可编程逻辑控制器 (PLC) 的完整的 4 通道、16 位模拟输出模块设计。此设计经过全面测试,符合适用于工业自动化系统的 IEC61000-4 EMC 和浪涌要求。 ...… 查看全部问答> |




