OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 7044|回复: 4

24V直流电机控制,用到PWM及定时器的计数模式

[复制链接]

1

主题

1

帖子

0

精华

新手入门

积分
25
金钱
25
注册时间
2014-11-20
在线时间
0 小时
发表于 2014-11-30 19:16:44 | 显示全部楼层 |阅读模式
目的:上位机发送速度指令到STM32,STM32据此控制两电机转速达到此速度。
STM32所用资源:主要用到了通用定时器(普通定时用),基本定时器(产生PWM波,用作编码器脉冲计数测速),串口1。
 硬件:STM32MIni开发板,双路直流电机驱动模块, CD74HC14E(施密特反相器),GGM 24V直流电机(带500线编码器)。
图片:

                   

   



[mw_shl_code=c,true]主要心得:本来也是很简单的事情,由于初学STM32很多东西也配置得不好,效率比较低。原来通用定时器的四路PWM占空比可以是不一样的。。。[/mw_shl_code] [mw_shl_code=c,true] 1: PID没调好,只是做了一个根据误差大小来确定pwm值增大或减小的程序见myControl(),控制程序在每次测速后运行(10ms一个周期),也可以 满足相应 的快速性,误差也可接受,毕竟调整周期很短。 [/mw_shl_code] [mw_shl_code=c,true] 2: 编码器的输出脉冲经过施密特反相器以后再接到STM32,测速会更稳定一些![/mw_shl_code]
程序:
引脚定义:
          //  VCC                        //  VCC
          //  ENA                        //  ENA
          //  IN1                        //  IN3
          //  IN2                        //  IN4
          //  GND                        //  GND
//       右电机接线                      左电机接线
////////////////////////////////////////////////////////////////////////////////////////
// 左电机(L)控制信号逻辑    (TIM3_CH1)                               (TIM5_CH1)
// IN3(PA4)     IN4(PA5)     ENA(PA6)      OUT1,OUT2输出          速度反馈(PA0)  
//  0             0              ×                                刹车
//  1             1              ×                         悬空(高电平)
//  1             0              WM                        反转调速
//  0             1              WM                        正转调速
//  1             0               1                             全速反转
//  0             1               1                             全速正转
///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
// 右电机(R)控制信号逻辑    (TIM3_CH2)                              (TIM4_CH1) 
// IN1(PA2)     IN2(PA3)    ENA(PA7)    OUT1,OUT2输出         速度反馈(PB6)
//  0             0              ×                                刹车
//  1             1              ×                          悬空(高电平)
//  1             0              WM                        反转调速
//  0             1              WM                        正转调速
//  1             0               1                             全速反转
//  0             1               1                             全速正转
///////////////////////////////////////////////////////////////////////////////////////
[mw_shl_code=c,true]#include "pwm.h" ////////////////////////////////////////////////////////// //arr:自动重装值 //psc:时钟预分频数 //左电机:PA6(TIM3_CH1) 右电机A7(TIM3_CH2) void TIM3_PWM_Init(u16 arr,u16 psc) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);      //使能TIM3时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);     //使能GPIO外设时钟使能 //设置该引脚为复用输出功能,输出TIM3 CH1的PWM脉冲波形 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7; //TIM3_CH1(PA6) TIM3_CH2(PA7) [/mw_shl_code] [mw_shl_code=c,true] GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); 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(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //选择定时器模式:TIM脉冲宽度调制模式2 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能 TIM_OCInitStructure.TIM_Pulse = 0; //设置待装入捕获比较寄存器的脉冲值 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高 TIM_OC1Init(TIM3, &TIM_OCInitStructure); //根据TIM_OCInitStruct中指定的参数初始化外设TIMx TIM_OC2Init(TIM3, &TIM_OCInitStructure); //根据TIM_OCInitStruct中指定的参数初始化外设TIMx TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable); //TIM3_CH1预装载使能 TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); //TIM3_CH2预装载使能 TIM_ARRPreloadConfig(TIM3, ENABLE); //使能TIMx在ARR上的预装载寄存器 } ////////////////////////////////////////////////////////// //左电机:设置PA4,PA5引脚为推挽输出,PA4连接驱动器IN1,PA5连接驱动器IN2 //右电机:设置PA2,PA3引脚为推挽输出,PA2连接驱动器IN1,PA3连接驱动器IN2 void IN1_IN2_GPIO_Init() { GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_ResetBits(GPIOA,GPIO_Pin_2); GPIO_ResetBits(GPIOA,GPIO_Pin_3); GPIO_ResetBits(GPIOA,GPIO_Pin_4); GPIO_ResetBits(GPIOA,GPIO_Pin_5); }
[mw_shl_code=c,true]#include "speedControl.h" #include "pwm.h" #define PARAM1 0.009751503597 //speed=PARAM1*pulses pulses:5ms内测得的脉冲个数 轮径:194mm 电机减速比:12.5:1 500线编码器 extern float setSpeed; struct _myStruct myStructL; struct _myStruct myStructR; int L_pwmval=700; int R_pwmval=700; ///////////////////////////////////////////////// //速度控制周期 10ms void TIM6_Init(u16 arr,u16 psc) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6 , ENABLE); TIM_TimeBaseStructure.TIM_Period = arr; TIM_TimeBaseStructure.TIM_Prescaler =psc; TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure); NVIC_InitStructure.NVIC_IRQChannel = TIM6_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); TIM_ITConfig(TIM6,TIM_IT_Update,ENABLE); } ///////////////////////////////////////////////// //速度控制周期 10ms,中断执行程序 void TIM6_IRQHandler(void) { u32 L_pulses=0; u32 R_pulses=0; if(TIM_GetITStatus(TIM6,TIM_IT_Update)!=RESET) //TIM6更新中断发生与否 { L_pulses=TIM5->CNT; R_pulses=TIM4->CNT; TIM4->CR1&=0XFFFE; // 停止计数器 TIM5->CR1&=0XFFFE; // 停止计数器 TIM6->CR1&=0XFFFE; // 停止定时器 myStructL.actualSpeed=L_pulses*PARAM1; myStructR.actualSpeed=R_pulses*PARAM1; printf("%f ",myStructL.actualSpeed); printf(" %f\n ",myStructR.actualSpeed);[/mw_shl_code] [mw_shl_code=c,true] myControl(); TIM_ClearITPendingBit(TIM6,TIM_IT_Update); TIM5->CNT=0; TIM4->CNT=0; TIM6->CR1|=1<<0; // 启动定时器 TIM5->CR1|=1<<0; // 启动计数器 TIM4->CR1|=1<<0; // 启动计数器 } } /////////////////////////////////////////////////////////////////////// //左电机测速设置 //TIM5_CH1外部时钟源模式1 void TIM5_CH1_Excnt_Init(u16 arr,u16 psc) { RCC->APB1ENR|=1<<3; // TIM5时钟使能 RCC->APB2ENR|=1<<2; // 使能PORTA时钟 GPIOA->CRL&=0XFFFFFFF0; // PA0清除之前设置 GPIOA->CRL|=0X00000004; //PA0输入 GPIOA->ODR|=0<<0; // PA0下拉 TIM5->ARR=arr; // TIM5->SC=psc; // TIM5->CCMR1|=1<<0; // 选择输入端IC1映射到TI1 TIM5->CCMR1&=0XFF0F; // IC1F=0000 配置输入滤波器不滤波 TIM5->CCER|=1<<0; // CC1P=0 上升沿计数 TIM5->SMCR|=5<<4; // 触发选择:滤波后的定时器输入1(TI1FP1) TIM5->SMCR|=7<<0; // 外部时钟模式1 } /////////////////////////////////////////////////////////////////////// //右电机测速设置 //TIM4_CH1(PB6)外部时钟源模式1 APB1 void TIM4_CH1_Excnt_Init(u16 arr,u16 psc) { RCC->APB1ENR|=1<<2; // TIM4时钟使能 RCC->APB2ENR|=1<<3; // 使能PORTB时钟 GPIOB->CRL&=0XF0FFFFFF; // PB6清除之前设置 GPIOB->CRL|=0X04000000; //PB6输入 GPIOB->ODR|=0<<6; // PB6下拉 TIM4->ARR=arr; // TIM4->SC=psc; // TIM4->CCMR1|=1<<0; // 选择输入端IC1映射到TI1 TIM4->CCMR1&=0XFF0F; // IC1F=0000 配置输入滤波器不滤波 TIM4->CCER|=1<<0; // CC1P=0 上升沿计数 TIM4->SMCR|=5<<4; // 触发选择:滤波后的定时器输入1(TI1FP1) TIM4->SMCR|=7<<0; // 外部时钟模式1 } //车轮速度控制(PID没调出来,用此代替(实测反应,误差都还好。)) void myControl(void) { //左电机 myStructL.speedError=myStructL.setSpeed-myStructL.actualSpeed; if(myStructL.speedError<-0.05) L_pwmval+=5 ; if(myStructL.speedError>-0.05 && myStructL.speedError<0 ) L_pwmval+=1; if(myStructL.speedError<0.05 && myStructL.speedError>0) L_pwmval-=1; if(myStructL.speedError>0.05) L_pwmval-=5 ; if(L_pwmval<0) L_pwmval=0; if(L_pwmval>900) L_pwmval=900; //右电机 myStructR.speedError=myStructR.setSpeed-myStructR.actualSpeed; if(myStructR.speedError<-0.05) R_pwmval+=5 ; if(myStructR.speedError>=-0.05 && myStructR.speedError<0 ) R_pwmval+=1; if(myStructR.speedError<=0.05 && myStructR.speedError>0) R_pwmval-=1; if(myStructR.speedError>0.05) R_pwmval-=5 ; if(R_pwmval<0) R_pwmval=0; if(R_pwmval>900) R_pwmval=900;   [/mw_shl_code] [mw_shl_code=c,true] TIM_SetCompare1(TIM3, L_pwmval); //左电机PWM TIM_SetCompare2(TIM3, R_pwmval); //右电机PWM } [/mw_shl_code] [mw_shl_code=c,true] [/mw_shl_code] [mw_shl_code=c,true] [/mw_shl_code]

[/mw_shl_code]











正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165524
金钱
165524
注册时间
2010-12-1
在线时间
2116 小时
发表于 2014-11-30 22:23:37 | 显示全部楼层
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

14

主题

58

帖子

0

精华

初级会员

Rank: 2

积分
163
金钱
163
注册时间
2015-8-5
在线时间
9 小时
发表于 2015-10-20 10:39:44 | 显示全部楼层
膜拜大神,学习了!!!!!!!!!
回复 支持 反对

使用道具 举报

1

主题

12

帖子

0

精华

初级会员

Rank: 2

积分
81
金钱
81
注册时间
2016-4-5
在线时间
32 小时
发表于 2016-4-5 21:07:40 | 显示全部楼层
为了表示感谢我特意注册了个账号
回复 支持 反对

使用道具 举报

0

主题

6

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
207
金钱
207
注册时间
2018-8-22
在线时间
64 小时
发表于 2021-3-27 15:27:03 | 显示全部楼层
求原理图
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-5-28 05:42

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表