完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
1个回答
|
|
实验室有个项目涉及到多个步进电机以及伺服电机的控制,需要电机得到一个触发信号后精确移动一段距离。
下面以单个伺服电机控制为例,利用伺服电机的指令脉冲加方向位置控制模式实现精确位置控制。 关于伺服电机 所谓指令脉冲+方向控制模式 就是由一路PWM波控制电机转动,一个IO控制电机方向。PWM的占空比控制电机转速,PWM的脉冲数控制电机的转动距离。 计算方法如下: 电机转动一圈所需脉冲数=电机驱动内置编码器线数*4/电子齿轮数 4为编码器对AB相计数模式 若仅对AB相上升沿或者下降沿计数则取2 若对AB相上升沿和下降沿都计数则取4 电子齿轮即为电机驱动对脉冲的细分数,使控制更加精确。 例: 伺服电机编码器为2500线 驱动细分为4:1 则一圈脉冲数=2500*4/4=2500 指令脉冲频率=(需要电机运行的转速 r/min/60)*一圈的脉冲数 此次操作不涉及到电机速度控制 不做介绍 一圈所需脉冲数为2500 则一个脉冲转动1/2500圈 设电机转动一圈移动距离为C,则一个脉冲移动C/2500 所以通过对脉冲计数可以实现非常精确的位置控制。 关于PWM脉冲数精确控制 PWM脉冲数精确控制有以下三种方案:
关于STM32主从定时器 在stm32中文参考手册”定时器同步“那一小节中有详细介绍 选择使用模式1 使用一个定时器(主)作为另一个定时器(从)的预分频器 其实就是将stm32的72MHz的时钟由主定时器分为一个周期为主定时器period的新脉冲(可理解为从定时器的新时钟),在主定时器的每个period溢出的那一刻会产生更新事件,由更新事件作为从定时器的时钟。 由下表可以看到STM32 TIMX的内部连接,在程序中通过选择ITRX将主从定时器联系起来,如本程序从定时器为TIM4,主定时器选择TIM3,则应选择ITR2. 下面直接上代码: 下为伺服电机控制头文件代码 下为伺服电机控制头文件代码 #ifndef ms_counter_h #define ms_counter_h #include "sys.h" #define PWM_CLK RCC_APB2Periph_GPIOC //定义PWM输出时钟 #define Motor_CCW GPIO_ResetBits(GPIOE,GPIO_Pin_5) //电机逆时针旋转 #define Motor_CW GPIO_SetBits(GPIOE,GPIO_Pin_5) //电机顺时针旋转 void Master_TIM(u16 period,u16 prescaler,u16 pulse); //主定时器配置函数 void Slave_TIM(u16 period); //从定时器配置函数 void DIR_Crl(void); //方向控制IO配置函数 #endif 下为主/从定时器配置函数代码: #include"stm32f10x.h" #include "MS_Counter.h" /*************** 主定时器配置函数 period:PWM周期 prescaler:预分频系数 pulse:占空比控制变量 也就是PWM有效电平的宽度 PWM输出IO为GPIOC_7 完全重映射至 TIM3_CH2 ***************/ void Master_TIM(u16 period,u16 prescaler,u16 pulse) { TIM_OCInitTypeDef TIM_OCInitStructure; //OC2初始化结构体 TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; //TIM3时基初始化结构体 GPIO_InitTypeDef GPIO_InitTypeStructure; //GPIO初始化结构体 RCC_APB2PeriphClockCmd(PWM_CLK|RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO,ENABLE); //使能PWM输出的时钟和复用IO时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE); //使能主定时器时钟 GPIO_InitTypeStructure.GPIO_Mode=GPIO_Mode_Out_PP; //沙雕核心板默认蜂鸣器开启状态,每次还要专门写代码关蜂鸣器... GPIO_InitTypeStructure.GPIO_Pin=GPIO_Pin_8; GPIO_InitTypeStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOB,&GPIO_InitTypeStructure); GPIO_ResetBits(GPIOB,GPIO_Pin_8); GPIO_InitTypeStructure.GPIO_Mode=GPIO_Mode_AF_PP; //PWM输出IO设为复用推挽 GPIO_InitTypeStructure.GPIO_Pin=GPIO_Pin_7; GPIO_InitTypeStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOC,&GPIO_InitTypeStructure); GPIO_PinRemapConfig(GPIO_FullRemap_TIM3,ENABLE); //完全重映射至TIM3_CH2 /********* 初始化TIM3的时基 设定PWM周期和预分频系数 *********/ TIM_TimeBaseInitStructure.TIM_ClockDivision=1; //时钟分频为1即为72MHz TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; TIM_TimeBaseInitStructure.TIM_Period=period; TIM_TimeBaseInitStructure.TIM_Prescaler=prescaler; TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0; TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure); /*********** 初始化PWM输出通道OC2 设定PWM占空比 ***********/ TIM_OCInitStructure.TIM_OCIdleState=ENABLE; TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1; //PWM模式1 TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High; //高电平为有效位 TIM_OCInitStructure.TIM_OutputState=ENABLE; TIM_OCInitStructure.TIM_Pulse=pulse; TIM_OC2Init(TIM3,&TIM_OCInitStructure); TIM_OC2PreloadConfig(TIM3,TIM_OCPreload_Enable); //预装载TIM3的pulse值 TIM_Cmd(TIM3,DISABLE); //初始化过程中不开启TIM3 //中断响应后再开启,保证主从定时器同步工作 TIM_SelectMasterSlaveMode(TIM3,TIM_MasterSlaveMode_Enable); //TIM3选择使能主从模式主定时器 TIM_SelectOutputTrigger(TIM3,TIM_TRGOSource_Update); //TIM3选择更新事件作为 trgo触发源 } /************ 从定时器配置函数 period:TIM4的溢出值 即设定的PWM脉冲数 ***********/ void Slave_TIM(u16 period) { NVIC_InitTypeDef NVIC_InitStructure; //中断初始化结构体 TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; //TIM4时基初始化结构体 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE); //使能TIM4时钟 /******** 初始化TIM4时基 设定所需PWM脉冲数 ********/ TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1; //时钟不分频即直接使用 //TIM3脉冲 TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; TIM_TimeBaseInitStructure.TIM_Period=period; TIM_TimeBaseInitStructure.TIM_Prescaler=0; //PWM不分频 TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0; TIM_TimeBaseInit(TIM4,&TIM_TimeBaseInitStructure); TIM_SelectSlaveMode(TIM4,TIM_SlaveMode_External1); //TIM4选择从定时器模式 TIM_SelectInputTrigger(TIM4,TIM_TS_ITR2); //TIM4选择内部触发来源为 //TIM3 TIM_Cmd(TIM4,DISABLE); //同样初始化中不使能TIM4 /*************** 配置TIM4的中断 利用TIM4计数溢出作为中断事件关闭TIM3 可达到精确计数的目的 ****************/ NVIC_InitStructure.NVIC_IRQChannel=TIM4_IRQn; NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2; NVIC_InitStructure.NVIC_IRQChannelSubPriority=2; NVIC_Init(&NVIC_InitStructure); TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE); //TIM4中断触发事件为update } /************* 方向控制IO配置函数 GPIOE_5 高电平顺时针 低电平逆时针 *************/ void DIR_Crl(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE,ENABLE); GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOE,&GPIO_InitStructure); } 使用按键信号来模拟外部触发信号,通过外部中断开启TIM3进行PWM输出,开启TIM4进行计数 下为按键配置代码: #include"stm32f10x.h" #include "key.h" /********** 按键配置函数 通过外部按键触发中断 使主定时器发出设定数量的PWM脉冲 也可将按键改为其他触发信号接入 按键IO为 GPIOE_4 **********/ void KEY_Config(void) { NVIC_InitTypeDef NVIC_InitStructure; //中断初始化结构体 EXTI_InitTypeDef EXTI_InitStructure; //外部中断通道初始化结构体 GPIO_InitTypeDef GPIO_InitStructure; //按键IO初始化结构体 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE|RCC_APB2Periph_AFIO,ENABLE); //使能按键IO时钟和复用时钟 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU; GPIO_InitStructure.GPIO_Pin=GPIO_Pin_4; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOE,&GPIO_InitStructure); GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource4); //选择外部中断通道 EXTI_InitStructure.EXTI_Line=EXTI_Line4; EXTI_InitStructure.EXTI_LineCmd=ENABLE; EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling; EXTI_Init(&EXTI_InitStructure); NVIC_InitStructure.NVIC_IRQChannel=EXTI4_IRQn; NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1; NVIC_InitStructure.NVIC_IRQChannelSubPriority=2; NVIC_Init(&NVIC_InitStructure); } 下为中断服务函数: 外部按键按下后触发外部中断 在外部中断中将主从定时器同时开启 主定时器开始发出设定数量的PWM脉冲 void TIM4_IRQHandler (void) //TIM4中断服务函数 { if (TIM_GetITStatus(TIM4,TIM_IT_Update)!=RESET) { TIM_Cmd(TIM3,DISABLE); //TIM4产生中断后关闭TIM3 TIM_ClearITPendingBit(TIM4,TIM_IT_Update); } } void EXTI4_IRQHandler(void) //按键外部中断服务函数 { if (EXTI_GetITStatus(EXTI_Line4)!=RESET) //按键按下后TIM3/4开启,电机动作 { TIM_Cmd(TIM3,ENABLE); TIM_Cmd(TIM4,ENABLE); } EXTI_ClearITPendingBit(EXTI_Line4); } 下为主函数: include "stm32f10x.h" #include "MS_Counter.h" #include "key.h" #include "delay.h" int main() { NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //配置中断优先级 delay_init(); DIR_Crl(); //电机方向接口初始化 Motor_CCW; //控制电机逆时针旋转 Master_TIM(999,719,399); //主定时器预分频为720,周期为1000则PWM频率为100Hz Slave_TIM(20); //设定脉冲数为20,小数量便于验证 KEY_Config(); delay_ms(10); while(1); } 不多不少 正好20个脉冲 |
|
|
|
只有小组成员才能发言,加入小组>>
2388 浏览 0 评论
8923 浏览 4 评论
36506 浏览 19 评论
4987 浏览 0 评论
24336 浏览 34 评论
1383浏览 2评论
1636浏览 1评论
2030浏览 1评论
1451浏览 0评论
396浏览 0评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-24 22:16 , Processed in 1.242712 second(s), Total 79, Slave 62 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号