赞
踩
1.STM32F103C8T6最小系统板
2.直流减速电机
3.TB6612FNG驱动模块
接线方式1(PWM驱动电机):
PWMA----PA11:接板子可设置PWM的IO口,
PWMA----PA2:接板子可设置PWM的IO口;
STBY------3.3v:使能;
AIN1-------PB12:普通IO口;
AIN2-------PB13:普通IO口;
BIN1-------PB14:普通IO口;
BIN2-------PB15:普通IO口;
VM---------12V电源正极:供电;
GND-------电源负极;
VCC--------板子5V;
GND--------板子GND;
A1(AO1)————电机1(无正负)
A2(AO2)————电机1(无正负,和正传反转有关)
B1(BO1)————电机2(无正负)
B2(BO2)————电机2(无正负,和正传反转有关)
注意:TB6612一定要和板子共地;
接线方式2(不空速):
不用接PWMA和PWMB就可以了。
现在就说说为什么这样接线吧:
我们只需要让四个IO输出相应的高低电平,然后通过PWM调速,就可以让小车动起来了,是不是很简单(狗头保命),好了,下面开始讲解软件部分。
代码示例:
void Motor_Init(u16 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能PB端口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15; //端口配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //50M
GPIO_Init(GPIOB, &GPIO_InitStructure); //根据设定参数初始化GPIOB
PWM_Init(arr,psc);
}
这就是很简单的GPIO初始化啦,然后就是PWM初始化:
/************************************************************************** 函数功能:控制电机的两路PWM初始化 入口参数:无 返回 值:无 **************************************************************************/ void PWM_Init(u16 arr,u16 psc) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; //使能GPIO和定时器时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE); // RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE); //使能GPIO外设时钟使能 //设置该引脚为复用输出功能,输出TIM1 CH4和TIM2 CH3的PWM脉冲波形 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2|GPIO_Pin_11; //TIM_CH1 //TIM_CH4 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化定时器arr、psc 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(TIM1, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位 //初始化比较参数 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式1 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能 TIM_OCInitStructure.TIM_Pulse = 0; //设置待装入捕获比较寄存器的脉冲值 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高 TIM_OC4Init(TIM1, &TIM_OCInitStructure); //根据TIM_OCInitStruct中指定的参数初始化外设TIMx //MOE 主输出使能 TIM_CtrlPWMOutputs(TIM1,ENABLE); //CH4预装载使能 TIM_OC4PreloadConfig(TIM1, TIM_OCPreload_Enable); //使能TIMx在ARR上的预装载寄存器 TIM_ARRPreloadConfig(TIM1, ENABLE); //使能TIM1 TIM_Cmd(TIM1, ENABLE); //TIM2_CH3 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(TIM2, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式1 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能 TIM_OCInitStructure.TIM_Pulse = 0; //设置待装入捕获比较寄存器的脉冲值 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高 TIM_OC3Init(TIM2, &TIM_OCInitStructure); //根据TIM_OCInitStruct中指定的参数初始化外设TIMx TIM_CtrlPWMOutputs(TIM2,ENABLE); //MOE 主输出使能 TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Enable); //CH3预装载使能 TIM_ARRPreloadConfig(TIM2, ENABLE); //使能TIMx在ARR上的预装载寄存器 TIM_Cmd(TIM2, ENABLE); //使能TIM2 }
大家可以仔细看看注释,这里我用的是PA11(TIM1 CH4)和 PA2(TIM2 CH3),这样我们就初始化完了。
.h文件:
//位带操作,实现51类似的GPIO控制功能 //具体实现思想,参考<<CM3权威指南>>第五章(87页~92页). //IO口操作宏定义 #define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2)) #define MEM_ADDR(addr) *((volatile unsigned long *)(addr)) #define BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum)) //IO口地址映射 #define GPIOA_ODR_Addr (GPIOA_BASE+12) //0x4001080C #define GPIOB_ODR_Addr (GPIOB_BASE+12) //0x40010C0C #define GPIOA_IDR_Addr (GPIOA_BASE+8) //0x40010808 #define GPIOB_IDR_Addr (GPIOB_BASE+8) //0x40010C08 //IO口操作,只对单一的IO口! //确保n的值小于16! #define PAout(n) BIT_ADDR(GPIOA_ODR_Addr,n) //输出 #define PAin(n) BIT_ADDR(GPIOA_IDR_Addr,n) //输入 #define PBout(n) BIT_ADDR(GPIOB_ODR_Addr,n) //输出 #define PBin(n) BIT_ADDR(GPIOB_IDR_Addr,n) //输入 #define PWMA TIM2->CCR3 //PA2 #define AIN2 PBout(15) #define AIN1 PBout(14) #define BIN1 PBout(13) #define BIN2 PBout(12) #define PWMB TIM1->CCR4 //PA11 void Set_Pwm(int moto1,int moto2); int myabs(int a);
这里我用了PB12-15作为输入的引脚,大家也可以用其他的引脚,只是需要把宏定义改一下就可以了
.c文件:
/************************************************************************** 函数功能:赋值给PWM寄存器 入口参数:左轮PWM、右轮PWM 返回 值:无 **************************************************************************/ void Set_Pwm(int motorLeft,int motorRight) { if(motorLeft>0) AIN2=0, AIN1=1; else if(motorLeft == 0) AIN2=0, AIN1=0; else AIN2=1, AIN1=0; PWMA=myabs(motorLeft); if(motorRight>0) BIN1=0, BIN2=1; else if(motorRight == 0) BIN1=0, BIN2=0; else BIN1=1, BIN2=0; PWMB=myabs(motorRight); } /************************************************************************** 函数功能:绝对值函数 入口参数:int 返回 值:unsigned int **************************************************************************/ int myabs(int a) { int temp; if(a<0) temp=-a; else temp=a; return temp; }
这个函数void Set_Pwm(int motorLeft,int motorRight)
就是根据TB6612驱动电机的原理编写的代码,方便我们控制电机。
我们调用时直接SetPwm(LeftSpeed,RightSpeed);
就可以了,是不是很简单呢?(狗头保命);
奉上视频:
你见过会说话的小车吗
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。