stm32电机控制之控制两路直流电机!看完你会了吗
手头上有一个差分驱动的小车,使用两个直流电机驱动,要实现小车的在给定速度下运动,完成直线行驶,转向,加速,刹车等复杂运动。
使用的电机是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直流电机驱动)
http://www.makeru.com.cn/live/1392_1218.html?s=45051
(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电机控制之控制两路直流电机!看完你会了吗的更多相关文章
- stm32电机控制之控制两路直流电机
小车使用的电机是12v供电的直流电机,带编码器反馈,这样就可以采用闭环速度控制,这里电机使用PWM驱动,速度控制框图如下: 由以上框图可知,STM32通过定时器模块输出PWM波来控制两个直流电机的转动 ...
- STM32高级定时器TIM1产生两路互补的PWM波(带死区)
测试环境:Keil 5.20.0.0 STM32F103RBT6 固件库版本:STM32F10x_StdPeriph_Lib_V3.5.0(2011) 本文使用TIM1的通道1,通道2,产生两路1kh ...
- STM32驱动ILI9341控制器控制TFTLCD显示
STM32驱动ILI9341控制器控制TFTLCD显示 一.用STM32控制TFTLCD显示的编程方法,在编程驱动TFTLCD液晶显示器之前,我们先熟悉以下概念: 1.色彩深度,这是一个与TFTLCD ...
- FPGA图像处理 两路sensor的色调不一致
怎么调?可以让两路sensor的色调一致.
- STM32F207 两路ADC连续转换及GPIO模拟I2C给MT9V024初始化参数
1.为了更好的方便调试,串口必须要有的,主要打印一些信息,当前时钟.转换后的电压值和I2C读出的数据. 2.通过GPIO 模拟I2C对镁光的MT9V024进行参数初始化.之前用我以前公司SP0A19芯 ...
- 基于STM32F767两路互补SPWM波(HAL库)
SPWM波指的是占空比呈正弦规律变化的PWM波,生成方式是在定时器中断中调整PWM波的占空比. 对于互补的两路SPWM波,一路为低电平 ‘0’ 时,另一路为高电平 ‘1’,即两路是互补的. 对于STM ...
- nRF51822 的两路 PWM 极性
忙了一阵这个PWM,玩着玩着终于发现了些规律.Nordic 也挺会坑爹的. nRF51822 是没有硬件 PWM 的,只能靠一系列难以理解的 PPI /GPIOTE/TIMER来实现,其实我想说,我醉 ...
- 125-FMC125-两路125Msps AD,两路160Msps DA FMC子卡模块
FMC125-两路125Msps AD,两路160Msps DA FMC子卡模块 1.板卡概述 该板卡可实现2路14bit 250Msps AD 和2路16bit 160MspsDA功能,FMC连接 ...
- C#本质论第四版-1,抄书才能看下去,不然两三眼就看完了,一摞书都成了摆设。抄下了记忆更深刻
C#本质论第四版-1,抄书才能看下去,不然两三眼就看完了,一摞书都成了摆设.抄下了记忆更深刻 本书面向的读者 写作本书时,我面临的一个挑战是如何持续吸引高级开发人员眼球的同时,不因使用assembly ...
随机推荐
- CommonsBeanutils1 分析笔记
1.PropertyUtils.getProperty commons-beanutils-1.9.2.jar 包下的 PropertyUtils#getProperty方法相对于getXxx方法,取 ...
- 使用ECS和OSS搭建个人网盘
体验简介 本场景将提供一台配置了Centos 7.7版本的ECS实例(云服务器)和对象存储OSS实例.通过本教程的操作,您可以基于ECS和OSS快速搭建一个个人网盘. 体验此场景后,可以掌握的知识有: ...
- Spring Cloud Eureka 之服务端自我注册
Eureka服务端实现了一种自我注册机制,涉及配置项: eureka.client.register-with-eureka spring.application.name Eureka Server ...
- 机器学习——Adaboost
1 Adaboost 的提出 1990年,Schapire最先构造出一种多项式级的算法,即最初的Boost算法; 1993年,Drunker和Schapire第一次将神经网络作为弱学习器,应用Boos ...
- 洛谷P1603——斯诺登的密码(字符串处理)
https://www.luogu.org/problem/show?pid=1603#sub 题目描述 2013年X月X日,俄罗斯办理了斯诺登的护照,于是他混迹于一架开往委内瑞拉的飞机.但是,这件事 ...
- swiper轮播高度不正常
第一次进入页面可能是网速原因,图片加载问题等吧,导致轮播图高度很大,下面出现空白, 需要加入参数 autoHeight: true, observer: true, observeParents: t ...
- Shell系列(12)- 预定义变量(5)
预定义变量 作用 $? 常用:最后一次执行的命令的返回状态. 如果这个变量的值为0,证明上一个命令正确执行:如果这个变量的值为非0(具体是哪个数,由命令自己来决定),则证明上一个命令执行不正确了 $$ ...
- csv或excel的utf-8乱码问题
方法1.数据导入 打开 Excel,执行"数据"->"自文本",选择 CSV 文件,出现文本导入向导,选择"分隔符号",下一步,勾选& ...
- AVS 端能力之蓝牙模块
该类为蓝牙端能力处理类,主要负责蓝牙设备配对和蓝牙音频播放功能. 功能简介 实现蓝牙设备的启动发现模式.扫描蓝牙设备.建立蓝牙连接功能 实现蓝牙设备音频播放.停止.上一首.下一首功能 其它细节参考&l ...
- python+selenium之浏览器滚动条操作
from selenium import webdriver import time #访问百度 driver=webdriver.Ie() driver.get("http://www.b ...