- 大家好哇!我是小光,嵌入式爱好者,一个想要成为系统架构师的普通大学生。
- 进入正题,最近在做小车,目前已经可以跑起来了,然后就是加入各种各样的传感器,使得她的功能更加丰富。
- 本次就谈谈做小车中的第一步,也是最重要的一步:PWM驱动直流减速电机,也是就让小车跑起来。
- 非常感谢大家的阅读,如果有不对的地方欢迎指正
一、硬件连接
1.器件清单:
1.STM32F103C8T6最小系统板 2.直流减速电机 3.TB6612FNG驱动模块
2.接线:
接线方式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就可以了。
3.驱动电机
现在就说说为什么这样接线吧: 我们只需要让四个IO输出相应的高低电平,然后通过PWM调速,就可以让小车动起来了,是不是很简单(狗头保命),好了,下面开始讲解软件部分。
二、软件驱动代码编写
1.初始化代码
代码示例:
void Motor_Init(u16 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
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;
GPIO_Init(GPIOB, &GPIO_InitStructure);
PWM_Init(arr,psc);
}
这就是很简单的GPIO初始化啦,然后就是PWM初始化:
void PWM_Init(u16 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2|GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
TIM_TimeBaseStructure.TIM_Period = arr;
TIM_TimeBaseStructure.TIM_Prescaler =psc;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 0;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC4Init(TIM1, &TIM_OCInitStructure);
TIM_CtrlPWMOutputs(TIM1,ENABLE);
TIM_OC4PreloadConfig(TIM1, TIM_OCPreload_Enable);
TIM_ARRPreloadConfig(TIM1, ENABLE);
TIM_Cmd(TIM1, ENABLE);
TIM_TimeBaseStructure.TIM_Period = arr;
TIM_TimeBaseStructure.TIM_Prescaler =psc;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 0;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC3Init(TIM2, &TIM_OCInitStructure);
TIM_CtrlPWMOutputs(TIM2,ENABLE);
TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Enable);
TIM_ARRPreloadConfig(TIM2, ENABLE);
TIM_Cmd(TIM2, ENABLE);
}
大家可以仔细看看注释,这里我用的是PA11(TIM1 CH4)和 PA2(TIM2 CH3),这样我们就初始化完了。
2.电机驱动代码
.h文件:
#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))
#define GPIOA_ODR_Addr (GPIOA_BASE+12)
#define GPIOB_ODR_Addr (GPIOB_BASE+12)
#define GPIOA_IDR_Addr (GPIOA_BASE+8)
#define GPIOB_IDR_Addr (GPIOB_BASE+8)
#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
#define AIN2 PBout(15)
#define AIN1 PBout(14)
#define BIN1 PBout(13)
#define BIN2 PBout(12)
#define PWMB TIM1->CCR4
void Set_Pwm(int moto1,int moto2);
int myabs(int a);
这里我用了PB12-15作为输入的引脚,大家也可以用其他的引脚,只是需要把宏定义改一下就可以了 .c文件:
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 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); 就可以了,是不是很简单呢?(狗头保命);
总结
本文仅仅简单介绍了TB6612控制直流电机的原理和驱动代码的编写,这样就完成了智能小车的第一步,后面会加上更多传感器如:超声波,红外避障,红外遥控,超声波,手势传感器等等,去实现更多的功能,感谢阅读,如果觉得我的文章对你有帮助的话,就点个赞吧!爱了爱了
|