小车使用的电机是12v供电的直流电机,带编码器反馈,这样就可以采用闭环速度控制,这里电机使用PWM驱动,速度控制框图如下:

  由以上框图可知,STM32通过定时器模块输出PWM波来控制两个直流电机的转动,通过改变PWM占空比的大小可以改变电机的转速,由于我们的控制目标是实现电机运行在速度范围内任意给定的速度,这里就需要采用闭环控制的思想,通过编码器获取电机的实时转速,通过与给定速度做差,将偏差作为PID控制器的输入,通过PID控制改变PWM占空比的大小,从而使电机的速度运行在给定的速度上。

  这里使用的电机驱动芯片为TB6612,该芯片可以十分方便的驱动两个直流电机的运行,其驱动逻辑表如下:

  AIN1,AIN2的不同组合可以实现电机的正反转和停车,PWMA为PWM的输入引脚,通过输入不同的占空比可以改变电机转速的快慢。BIN1,BIN2,PWMB是控制另一路电机的引脚。

  首先我们需要利用STM32的定时器模块输出两路PWM波,这是使电机转起来的第一步。初始化PWM:

  //初始化PWM引脚
  void motorPWMPin_init(void)
  {
  GPIO_InitTypeDef GPIO_InitStructure;
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE,ENABLE);
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_11 ;//TIM1_Chn_1,TIM1_Chn_2
  GPIO_Init(GPIOE,&GPIO_InitStructure);
  GPIO_PinAFConfig(GPIOE,GPIO_PinSource9,GPIO_AF_TIM1);
  GPIO_PinAFConfig(GPIOE,GPIO_PinSource11,GPIO_AF_TIM1);
  }
  //初始化PWM
  void motorPWM_init(void)
  {
  TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStrecture;
  TIM_OCInitTypeDef TIM_OCInitStructure;
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);
  TIM_TimeBaseInitStrecture.TIM_Period = 400;/*PWM's frequency is 20KHz*/
  TIM_TimeBaseInitStrecture.TIM_Prescaler =21-1;//将TIM1的时钟频率设定为8MHz
  TIM_TimeBaseInitStrecture.TIM_ClockDivision = TIM_CKD_DIV1;
  TIM_TimeBaseInitStrecture.TIM_CounterMode = TIM_CounterMode_Up;//定时器向上计数
  TIM_TimeBaseInitStrecture.TIM_RepetitionCounter = 0;
  TIM_TimeBaseInit(TIM1,&TIM_TimeBaseInitStrecture);
  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High ;
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;
  TIM_OC1Init(TIM1,&TIM_OCInitStructure);
  TIM_OC2Init(TIM1,&TIM_OCInitStructure);
  // TIM_Cmd(TIM1,ENABLE);
  TIM_CtrlPWMOutputs(TIM1,ENABLE);
  }

  然后初始化电机控制引脚,程序如下:

  //初始化电机控制引脚
  void motorCtrlPin_init(void)
  {
  GPIO_InitTypeDef GPIO_InitStructure;
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE,ENABLE);
  //PE7,PE8控制电机A,PE9,PE10控制电机B
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_10;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
  GPIO_Init(GPIOE, &GPIO_InitStructure);
  }

  需要注意的是设置PWM输出引脚时要讲引脚复用到定时器TIM1,而电机控制引脚只需要设置成简单的推挽输出模式即可。

  接着我们需要使用两个定时器的编码器功能用于读取电机的实时转动速度,这里我使用的是定时器3和定时器4.

  这里的编码器是精度较低的霍尔感应式编码器,但是基本满足控制精度的要求,驱动代码如下:

  void encoderA_init(void)
  {
  GPIO_InitTypeDef GPIO_InitStructure;
  NVIC_InitTypeDef NVIC_InitStructure;
  TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
  TIM_ICInitTypeDef TIM_ICInitStructure;
  /*CLOCK Enable*/
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE); //PC6,PC7
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用引脚模式
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //100MHz
  GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //无上下拉
  /*Configure PC6,PC7 as encoder A,B Input*/
  GPIO_PinAFConfig(GPIOC,GPIO_PinSource6,GPIO_AF_TIM3);
  GPIO_PinAFConfig(GPIOC,GPIO_PinSource7,GPIO_AF_TIM3);
  GPIO_Init(GPIOC,&GPIO_InitStructure); //initialize PORTC
  /* Timer configuration in Encoder mode */
  /* Enable the TIM3 Update Interrupt */
  NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority =0x01;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
  TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
  TIM_TimeBaseStructure.TIM_Prescaler = 0; //不分频
  TIM_TimeBaseStructure.TIM_Period = 65535; //设置为最大
  TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up ; //向上计数
  TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
  TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising , TIM_ICPolarity_Rising );//上升沿计数
  TIM_ICStructInit(&TIM_ICInitStructure);
  TIM_ICInitStructure.TIM_ICFilter = 10;//设置滤波系数
  TIM_ICInit(TIM3, &TIM_ICInitStructure);
  TIM_ClearFlag(TIM3, TIM_FLAG_Update); //清除更新中断
  TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE); //使能更新中断
  TIM3->CNT = 0;//将计数值设为0
  TIM_Cmd(TIM3, ENABLE);//enable TIM3
  printf("Encoder_A initializztion is OK\n");
  }

  stm32视频资料

(stm32 USART串口应用)
http://www.makeru.com.cn/live/1392_1164.html?s=45051
PWM脉宽调制技术
http://www.makeru.com.cn/live/4034_2146.html?s=45051
基于STM32讲解串口操作
http://www.makeru.com.cn/live/1758_490.html?s=45051
通过Z-stack协议栈实现串口透传
http://www.makeru.com.cn/live/1758_330.html?s=45051
(stm32直流电机驱动)
http://www.makeru.com.cn/live/1392_1218.html?s=45051
(零基础电子产品设计)
http://www.makeru.com.cn/live/3727_1388.html?s=45051

资料下载群:830802928

stm32电机控制之控制两路直流电机的更多相关文章

  1. stm32电机控制之控制两路直流电机!看完你会了吗

    手头上有一个差分驱动的小车,使用两个直流电机驱动,要实现小车的在给定速度下运动,完成直线行驶,转向,加速,刹车等复杂运动. 使用的电机是12v供电的直流电机,带编码器反馈,这样就可以采用闭环速度控制, ...

  2. STM32高级定时器TIM1产生两路互补的PWM波(带死区)

    测试环境:Keil 5.20.0.0 STM32F103RBT6 固件库版本:STM32F10x_StdPeriph_Lib_V3.5.0(2011) 本文使用TIM1的通道1,通道2,产生两路1kh ...

  3. STM32驱动ILI9341控制器控制TFTLCD显示

    STM32驱动ILI9341控制器控制TFTLCD显示 一.用STM32控制TFTLCD显示的编程方法,在编程驱动TFTLCD液晶显示器之前,我们先熟悉以下概念: 1.色彩深度,这是一个与TFTLCD ...

  4. FPGA图像处理 两路sensor的色调不一致

    怎么调?可以让两路sensor的色调一致.

  5. STM32F207 两路ADC连续转换及GPIO模拟I2C给MT9V024初始化参数

    1.为了更好的方便调试,串口必须要有的,主要打印一些信息,当前时钟.转换后的电压值和I2C读出的数据. 2.通过GPIO 模拟I2C对镁光的MT9V024进行参数初始化.之前用我以前公司SP0A19芯 ...

  6. 基于STM32F767两路互补SPWM波(HAL库)

    SPWM波指的是占空比呈正弦规律变化的PWM波,生成方式是在定时器中断中调整PWM波的占空比. 对于互补的两路SPWM波,一路为低电平 ‘0’ 时,另一路为高电平 ‘1’,即两路是互补的. 对于STM ...

  7. nRF51822 的两路 PWM 极性

    忙了一阵这个PWM,玩着玩着终于发现了些规律.Nordic 也挺会坑爹的. nRF51822 是没有硬件 PWM 的,只能靠一系列难以理解的 PPI /GPIOTE/TIMER来实现,其实我想说,我醉 ...

  8. 125-FMC125-两路125Msps AD,两路160Msps DA FMC子卡模块

    FMC125-两路125Msps AD,两路160Msps DA FMC子卡模块 1.板卡概述  该板卡可实现2路14bit 250Msps AD 和2路16bit 160MspsDA功能,FMC连接 ...

  9. STM32之外部中断控制

    一.STM32外部中断 1.STM32外部中断结构图 如上图所示:主要包括四个环节,GPIO.AFIO.EXTI.NVIC.以STM32F103VE(100脚)为例说明硬件模块的数量: GPIO:   ...

随机推荐

  1. Java基础学习3

    Java语法学习3 基本运算符 关系运算符返回结果为布尔类型 %:取余 模运算 +.-.*./.% :二元运算符 两个变量间的运算 ++.-- 一元运算符 package Study; public ...

  2. AWK的内置变量

    ARGC: number (2) 在命令行提供的参数的个数,不包括命令awkARGIND: number (0) 当前文件中正在处理的 ARGV 数组的索引值. 文件的位置,从1开始计数.一个文件处在 ...

  3. 关于软链接ln -s 的使用

    1.效果跟windows创建快捷方式是一样的,先找到要被创建的原始文件或目录.然后才能创建. 2.格式:ln  -s   [源文件或目录]   [目标文件或目录] 3.源文件或目录必须是绝对目录. 4 ...

  4. 动态规划精讲(一)LC 最长递增子序列的个数

    最长递增子序列的个数 给定一个未排序的整数数组,找到最长递增子序列的个数. 示例 1: 输入: [1,3,5,4,7]输出: 2解释: 有两个最长递增子序列,分别是 [1, 3, 4, 7] 和[1, ...

  5. 免费iApp后台-云接口

    免费稳定,UI易懂简洁,功能强大 应用名称:云接口 应用版本:1.5.9 应用大小:3.55 MB 适用平台:Android(安卓) 应用用处:详情请下载软件 软件安全无毒 更新内容: 1.支付宝当面 ...

  6. DS博客作业05--查找

    这个作业属于哪个班级 数据结构--网络2011/2012 这个作业的地址 DS博客作业05--查找 这个作业的目标 学习查找的相关结构 姓名 黄静 目录 0.PTA得分截图 1.本周学习总结 1.1 ...

  7. 网络协议之:WebSocket的消息格式

    目录 简介 WebSocket的握手流程 webSocket的消息格式 Extensions和Subprotocols 总结 简介 我们知道WebSocket是建立在TCP协议基础上的一种网络协议,用 ...

  8. SourceTree使用详解-摘录收藏

    前言: 非原创,好文收录,原创作者:追逐时光者 俗话说的好工欲善其事必先利其器,Git分布式版本控制系统是我们日常开发中不可或缺的.目前市面上比较流行的Git可视化管理工具有SourceTree.Gi ...

  9. Linux系列(23) - echo

    作用:打印 格式:echo [选项] [输出内容] 选项:-e :支持反斜线控制的字符转换 前置条件:必须加选项-e才能使用 控制字符 作用 \a 输出警告音 \b 退格符,也就是向左删除键 \n 换 ...

  10. 如何解决SVN Upgrade working copy问题

    电脑还原系统后,安装了最新版本的SVN,发现原来在svn检出的文件夹出现了SVN Upgrade working copy,没有commit ,没有update. 在网上查询到:出现这个的原因是因为你 ...