一文搞懂如何使用STM32驱动直流电机(普通PWM输出和L298N、高级定时器输出带死区双通道互补PWM和IR2110S及自举电路、H桥电路和电机正反转) |
您所在的位置:网站首页 › 24v正反转电机怎么接 › 一文搞懂如何使用STM32驱动直流电机(普通PWM输出和L298N、高级定时器输出带死区双通道互补PWM和IR2110S及自举电路、H桥电路和电机正反转) |
本文将用最通俗易懂的语言讲解怎么使用STM32驱动直流电机,以及在使用过程中容易遇到的问题和解决办法。本文将介绍两种驱动方式:普通PWM驱动L298N驱动直流电机;互补PWM驱动IR2110S驱动直流电机。笔者将文章分为两部分:不懂原理直接使用部分和一定要懂原理再用(仅IR2110S)部分。看完后,你会说:圆哥NB,原来驱动电机如此简单。
文章目录
本文将用最通俗易懂的语言讲解怎么使用STM32驱动直流电机,以及在使用过程中容易遇到的问题和解决办法。本文将介绍两种驱动方式:普通PWM驱动L298N驱动直流电机;互补PWM驱动IR2110S驱动直流电机。笔者将文章分为两部分:不懂原理直接使用部分和一定要懂原理再用(仅IR2110S)部分。看完后,你会说:圆哥NB,原来驱动电机如此简单。前言一、不懂原理直接使用0.了解L298N和IR2110S怎么驱动直流电机的1.普通PWM和L298N2.互补PWM和IR2110S
二、我要懂原理1.IR2110S的优势2.IR2110S自举电路
总结
前言
笔者从开始接触嵌入式单片机开始,就和驱动电机相伴而走。从最开始的直接买L298N驱动模块直接驱动直流电机,到现在自己设计PCB电路板驱动直流电机,可以说是和电机驱动共同成长了。现在笔者将这一过程的收获记录下来,希望对大家有所帮助。 一、不懂原理直接使用 0.了解L298N和IR2110S怎么驱动直流电机的不用详细了解L298N芯片和IR2001S的芯片引脚,但是要知道这两个芯片是干嘛的。这两个芯片的相同功能就是把单片机输出的3.3VPWM波变成你给这两个芯片供电的电压PWM波。比如你给芯片供电12V,那么输出的就是12V的PWM波,占空比和单片机输出的PWM波占空比一致。 改变电机的电压可以改变电机的转速,改变电机的正负极可以改变电机的转向。改变电机的驱动电压通过改变PWM波的占空比实现,比如给芯片供电12V,PWM的占空比是60%,那么就相当于给电机供电12V*60% = 7.2V。供电电压乘以占空比就是电机的供电电压。需要注意的是,这里的占空比指的是高电平时间和周期的比值。 改变电机的转向(改变电机的正负极),这个操作很简单,会在下面介绍。 1.普通PWM和L298NSTM32输出普通PWM笔者这里不再赘述,这个驱动过程十分简单,网上随便一搜索就有一大堆的例子。 L298N可以买到别人设计好的模块,在淘宝等店铺直接搜索L298N电机驱动模块就可以看到各种各样的产品。这些产品的驱动方式大同小异,笔者下面将选取一种介绍。 笔者使用的单片机型号是STM32F103C8T6,下面将介绍基于这款单片机高级定时器一的带死区的互补PWM怎么配置的。事实上,由于CMSIS协议的存在,这个配置只需做少量修改或者无需修改就可以使用在Cotex-M内核的其他单片机上。 代码如下: void TIM1_PWM_DeadtimeInit(u16 arr,u16 psc,u16 deadtime) { GPIO_InitTypeDef GPIO_InitSturcture; TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; TIM_OCInitTypeDef TIM_OCInitStructure; TIM_BDTRInitTypeDef TIM_BDTRInitStructure; NVIC_InitTypeDef NVIC_InitStructure; //时钟配置 RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE ); RCC_APB2PeriphClockCmd( RCC_APB2Periph_TIM1, ENABLE ); RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //TIM1 PWM CH1->PA8 CH2->PA9 CH1N->PB13 CH2N->PB14,PWM管脚映射 //与PWM管脚初始化 GPIO_InitSturcture.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9; GPIO_InitSturcture.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitSturcture.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init( GPIOA, &GPIO_InitSturcture ); GPIO_InitSturcture.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14; GPIO_InitSturcture.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitSturcture.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init( GPIOB, &GPIO_InitSturcture ); GPIO_SetBits(GPIOA, GPIO_Pin_8 | GPIO_Pin_9); GPIO_SetBits(GPIOB, GPIO_Pin_13 | GPIO_Pin_14); //关于定时器中断的配置,有的资料上需要配置,有的资料上不需要 //配置,笔者配置和不配置的都试了,都可以使用,这里还是配置上 NVIC_InitStructure.NVIC_IRQChannel = TIM1_UP_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); //关于定时器重装载值和分频系数的配置,决定了PWM的频率 //timer base set TIM_TimeBaseInitStructure.TIM_Period = arr; TIM_TimeBaseInitStructure.TIM_Prescaler = psc; TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInitStructure.TIM_ClockDivision = 0x00; TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0x00; TIM_TimeBaseInit( TIM1, &TIM_TimeBaseInitStructure ); TIM_ARRPreloadConfig(TIM1, ENABLE); //OC1 Mode set 高级定时器互补输出的设置 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_Pulse = 50; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCPolarity_High; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable; TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset; TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset; TIM_OC1Init( TIM1, &TIM_OCInitStructure ); TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable); //OC2 Mode set TIM_OCInitStructure.TIM_Pulse = 0; TIM_OC2Init( TIM1, &TIM_OCInitStructure ); TIM_OC2PreloadConfig(TIM1, TIM_OCPreload_Enable); //DeadTime Set 死区时间的设置 TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable; TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable; TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_2; TIM_BDTRInitStructure.TIM_DeadTime = deadtime; TIM_BDTRInitStructure.TIM_Break = TIM_Break_Disable; TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High; TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable; TIM_BDTRConfig( TIM1, &TIM_BDTRInitStructure ); TIM_CtrlPWMOutputs( TIM1, ENABLE ); TIM_Cmd( TIM1, ENABLE ); }代码如上图所示,和常规固件库编程思路一样:对时钟进行配置、对管脚进行初始化、对定时器进行初始化、对PWM进行初始化、对死区进行配置。 这里有几点需要注意。首先是高级互补输出的设置的第一行,那里有几种不同的模式,笔者选择的是PWM模式一。如果感兴趣,你可以试一试其他的模式。 第二点是死区时间的设置。死区时间的计算比较复杂,感兴趣的请移步以下链接,是CSDN的另一个博主写的。 链接: STM32F1死区时间配置详解 第三点是这个函数怎么用。需要首先在主函数里进行初始化。 TIM1_PWM_DeadtimeInit(36000-1,0,0XAC); 这是笔者使用的。函数第一个形参是PWM重装载值,第二个形参是PWM分频系数,第三个是死区时间的设置。0XAC表示死区时间是3us。笔者使用的配置的意思是:不分频、计时器到(36000-1)会重新开始计数、由分频系数和重装载值可算出PWM频率是2kHz。 第四点是如何更改PWM的占空比,和普通PWM更改的方式一样。使用 void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare1);函数更改比较值就可以了。 由于该互补PWM是用来驱动IR2110S的,笔者已经在IR2110S上进行了实验,死区时间和频率都没有任何问题。 接下来是IR2110S如何使用的问题了。IR2110S目前集成好的模块产品并不是很多,笔者所知野火有一款直流无刷电机驱动板,里面的H桥电路是用IR2110S驱动的。一般来说,使用IR2110S都需要自己设计PCB。当然,不需要知道原理的情况下IR2110S的使用十分简单。 那么IR2110S怎么控制电机的正反转呢。其实只需要两个这样的电路,分别把输出接口接到电机的两端就可以了。驱动其中一个电路,让另一个电路和地连接的场效应管一直导通,是一个方向的电压。反过来驱动另外一个电路是反方向的电压。这样就实现了H桥电路。 二、我要懂原理 1.IR2110S的优势IR2110S具有集成度高,响应速度快等诸多优势。最重要的是,驱动N多个芯片只需要一路电源,大大的减少了设计的难度。这一切都要归功于自举电路。下面将介绍自举电路的原理。 2.IR2110S自举电路
请多多关注,接下来笔者可能更新一波如何使用PID算法做简单的自动驾驶。 笔者已经尽可能的理清逻辑,但是难免会有些地方不容易理解,所以欢迎大家多多留言提问和指教呀。技术问题,有问必回!!! |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |