您的位置:首页 > 编程语言

STM32F103RCT6 实验代码之舵机+超声波避障小车(一)杂谈+电机+L298N

2020-04-23 09:08 886 查看

STM32 舵机+超声波避障

寒假由于时间较长,自己就想做一个智能车玩玩,第一个做的是蓝牙小车,不过比较简单,我就不打算具体另开一个部分,到时候挑一些与避障小车不一样的部分说一下。我这个小车行走速度比较慢,还是存在一定瑕疵,线也比较凌乱,大体功能可以实现。
先贴小车的图片:

小车主要分为几个部分:
1.STM32F103RCT6,当然用来执行各种命令的,因为用的是学习板,占地比较大,以后有时间改成C8T6的核心板,这样占地小一些。
2.L298N电机驱动模块,主要用来驱动左右两个电机,这个模块下面介绍。
3.电池,这里我买的是一款航模电池 1800mah 20c 焊接好T插头的电池,输出的是12V电压
4.分电板,主要是把电池的12V分成一个12V和一个5V输出
5.舵机,用的是SG90模拟舵机,这个舵机是花费时间最多的,因为总和我想要的结果不太一样
6.超声波测距模块,用的是HC-SR04模块,具体使用我上一篇说过了
7.蓝牙模块,用的HC-05这个蓝牙模块主要是用在蓝牙小车,后来放在避障小车上用来输出前方障碍物数据
8.小车底盘+电机,这个在某宝上一搜就有,而且驱动方法都差不多。我这里用的是直流电机。还有步进电机,但是我没有采用

这一篇我主要来说一下怎样让小车跑起来,就是电机怎么动。
想让小车跑起来,最重要的就是电机,电机驱动主要是需要两个接口。

一.直流电机


这个是我用的小车电机的说明,其中我们想要驱动电机就是在“电机线-”和“电机线+”一个高电压一个低电压,就会实现电机的转动,这里高低电压的接法没有要求接法不同只是影响正反转而已。至于其他的与编码器相关的可以不用连线,这些是测量电机转速的。在电压一定的情况下,电流越大,相应的转速也应该越快。
正常用L298N模块可以驱动电机并达到很高的转速,我这里尝试了一下直接用单片机驱动,发现也可以使电机转起来但是速度相比较用模块来说要慢很多,我猜测应该和电流有很大关系。

二.L298N模块


这个就是L298N驱动模块的样子
其中前面三个端子 ,中间的接地,注意要与单片机共地,否则将无法正常驱动电机,左面的端子是+12V输入,用来给L298N模块供电,就是电源输出的+12V电压,右面的端子是+5V输出,注意不要把这5V当作输入,建议不要用这个5V做为单片机的供电端。
左右两边各有两个端子,分别是OUT1,OUT2和OUT3,OUT4,用来驱动两路电机,这里只需要把OUT与电机的的电机线连接到一起即可完成。
在前面三个端子旁边有四个排针,这四个排针是用来控制左右两边的OUT,这四个排针分别是IN1 IN2 IN3 IN4 ,排针左右两边有两个用跳帽盖上的排针,分别是ENA ENB目的是使能那四个IN。用跳帽连接默认是已经使能,拔下跳帽另外加信号就可以继续使用。

这是不同情况下的电机转动情况,后期可以用两种方法调节电机速度:
一.给EN使能,之后调节IN1 IN2 之间的电压差(通过调节PWM波占空比的方式实现)来控制速度。
二.是控制EN的电压也是通过条件PWM占空比来实现。我这里采用的就是这种方法。
这里我初始化四个IO口分别来控制四个IN端,来控制其正转反转。

void gpio_Init(void)
{

GPIO_InitTypeDef  GPIO_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB, ENABLE);	 //使能PA,PB端口时钟

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;				 //PA.4 端口配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 //IO口速度为50MHz
GPIO_Init(GPIOA, &GPIO_InitStructure);					 //根据设定参数初始化GPIOA.4
// GPIO_SetBits(GPIOA,GPIO_Pin_4);						 //PA.4 输出高

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;	    		 //PA.5 端口配置, 推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure);	  				 //推挽输出 ,IO口速度为50MHz
//GPIO_SetBits(GPIOA,GPIO_Pin_5); 						 //PA.5 输出高

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;	    		 //PB.10端口配置, 推挽输出
GPIO_Init(GPIOB, &GPIO_InitStructure);	  				 //推挽输出 ,IO口速度为50MHz

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;	    		 //PB.11 端口配置, 推挽输出
GPIO_Init(GPIOB, &GPIO_InitStructure);	  				 //推挽输出 ,IO口速度为50MHz

}

这里我把几种电机转动情况来分类用函数来调用

void stop()
{
PAout(4)=0;
PAout(5)=0;
PBout(10)=0;
PBout(11)=0;//停止

}

void front()

{
PBout(10)=0;
PBout(11)=1;//前进
PAout(4)=0;
PAout(5)=1;

}

void left()

{
PAout(4)=0;
PAout(5)=1;
PBout(10)=1;
PBout(11)=0;//左转

}

void right()
{
PAout(4)=1;
PAout(5)=0;
PBout(10)=0;
PBout(11)=1;//右转

}

void turnleft()

{

PAout(4)=0;
PAout(5)=1;
PBout(10)=0;
PBout(11)=0;//一电机停止 左转

}

void turnright()

{

PAout(4)=0;
PAout(5)=0;
PBout(10)=0;
PBout(11)=1;//一电机停止 右转

}

void back()

{

PAout(4)=1;
PAout(5)=0;
PBout(10)=1;
PBout(11)=0;//后退

}

这样就可以驱动轮胎转动,也就可以驱动小车任意方向运动。
下面是我设置了两路PWM波给两个EN信号,来控制电机速度,进而控制小车速度,我只用了普通的定时器来输出PWM波,没有用到高级定时器的刹车功能。
PWM1:

#include "pwm.h"

//PWM输出初始化
//arr:自动重装值
//psc:时钟预分频数
void TIM3_PWM4_Init(u16 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
TIM_OCInitTypeDef  TIM_OCInitStructure;

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);//
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE);  //使能GPIO外设时钟使能

//设置该引脚为复用输出功能,输出TIM3 CH4的PWM脉冲波形
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //TIM_CH4
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);

TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值	 80K
TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值  不分频
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位

TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //选择定时器模式:TIM脉冲宽度调制模式2
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
TIM_OCInitStructure.TIM_Pulse = 0; //设置待装入捕获比较寄存器的脉冲值
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
TIM_OC4Init(TIM3, &TIM_OCInitStructure);  //根据TIM_OCInitStruct中指定的参数初始化外设TIMx

TIM_CtrlPWMOutputs(TIM3,ENABLE);	//MOE 主输出使能

TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Enable);  //CH4预装载使能

TIM_ARRPreloadConfig(TIM3, ENABLE); //使能TIMx在ARR上的预装载寄存器

TIM_Cmd(TIM3, ENABLE);  //使能TIM3

}

PWM2:

#include "pwm2.h"

//PWM输出初始化
//arr:自动重装值
//psc:时钟预分频数
void TIM3_PWM3_Init(u16 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
TIM_OCInitTypeDef  TIM_OCInitStructure;

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);//
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE);  //使能GPIO外设时钟使能

//设置该引脚为复用输出功能,输出TIM1 CH1的PWM脉冲波形
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //TIM_CH1
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);

TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值	 80K
TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值  不分频
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位

TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //选择定时器模式:TIM脉冲宽度调制模式2
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
TIM_OCInitStructure.TIM_Pulse = 0; //设置待装入捕获比较寄存器的脉冲值
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
TIM_OC3Init(TIM3, &TIM_OCInitStructure);  //根据TIM_OCInitStruct中指定的参数初始化外设TIMx

TIM_CtrlPWMOutputs(TIM3,ENABLE);	//MOE 主输出使能

TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable);  //CH3预装载使能

TIM_ARRPreloadConfig(TIM3, ENABLE); //使能TIMx在ARR上的预装载寄存器

TIM_Cmd(TIM3, ENABLE);  //使能TIM3

两路PWM控制占空比

TIM_SetCompare3(TIM3,2400);//左轮电机转速
TIM_SetCompare4(TIM3,2530);//右轮电机转速

控制占空比函数数值越大转速越慢,在实际中,会遇到小车两个轮转速不一样,这里我没有用算法来调整,我采用手动调整到大概可以走直线,硬件的缺陷用软件来弥补。

到现在就可以用单片机+L298N模块来驱动电机,可以实现小车的任意方向行驶啦
具体代码之后上传

  • 点赞 5
  • 收藏
  • 分享
  • 文章举报
Physics.k 发布了4 篇原创文章 · 获赞 6 · 访问量 1534 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: