2. 电机驱动模块 L298N 电机驱动模块绝对是初学者的首选,但这个系列也包括很多类型。本文使用 L298N 双 H 桥驱动器红色版本。除了性能之外,我选择它是因为它有一个 5v 输出接口,可以用来给单片机供电。你可以使用两个这样的驱动器,也可以使用一个,另一个使用更便宜的。
由于我家里有以下型号的L298N驱动程序,为了不浪费资源,另一个我将使用以下型号的L298N驱动程序。
3. MCU最小系统关于最小系统,选择自己熟悉的就行,没有特殊要求,我用的样式如下(使用的芯片是STC89C52)
4.电源这部分大家可以根据需求选择,选择的时候注意电压和容量就行,我选的是常见的9v 650mAh(容量不是很大,但是这种电池比较常见,充一次电跑2~3个小时应该没问题)。我选的是USB充电的,充电很方便。电池盒我选的是下图这种,拆卸方便,缺点就是没有自带电源开关。
5.杜邦线。这个是必备配件,就不多说了。需要买一些公对公,母对母,公对母的(这种一般用得比较多),家里常用的物品。
2.硬件连接本文涉及的硬件连接是单片机、电源、电机、两个电机驱动器L298N的连接,这里我介绍一种参考连接方法,大家可以自行设计连接方案
如上图,四个电机的正负极分别接在L298N的两个绿色电机接口上,至于哪个接正极,哪个接负极,就看你电机的安装方式了,建议先把电机的两根线焊接好,再装底盘,这样电机的安装方式就确定了,先把两个L298N的四个绿色电机接口随意接在电机上,其他信号线接好后判断对错再进行调整,调整方法如下:在程序中让小车向前跑,观察车轮转动的方向,车轮向前转的线不用改,只要把L298N绿色接口对应电机向后转的两根线改一下就可以了。如上图,L298N左边第一个蓝色口是5V输出,把一个L298N的接口接到单片机的5v接口上即可。 另外一个L298N的接口可以空着,左边第二个蓝色口是GND,需要同时接单片机的GND和电源负极,左边第三个蓝色口是L298N的电源输入口,接电源正极,我用的是9v电源。剩下的就是L298N的信号线和单片机的连接。如上图我这里用的是双驱动接法,也就是左边两个点击器用同一个信号控制,右边两个电机用同一个信号控制。单片机的I/O口可以自己选择,和程序配合,我选择的是ENA接P16,ENB接P17,IN1接P34,IN2接P35,IN3接P36,IN4接P37,如果改成4驱动的话,需要的I/O就翻倍了。 有些读者表示对这部分连接还是不太明白,所以我简单画了如下草图,方便大家理解上面的内容(字迹不好看还请见谅)
实际图片如下:
三、程序编写 1、工程建立 编译环境可以根据自己的习惯和需要选择,本文以KEIL C51为例。由于本次设计的小车控制不复杂,所以我把工程中用到的头文件、函数定义、sbit定义的位变量都放到一个头文件中,命名为car.h(大家可以随意命名)。至于C文件,我建议大家把每一部分写在不同的文件中,比如我把电机驱动相关的函数放在motor_control.c(随意命名)文件中,控制方案、延时函数、中断函数放在主函数main.c(随意命名)文件中。随着以后函数的增加,还会添加其他的C文件,只要所有的C文件都包含上述的公共头文件car.h,它们之间就建立了联系。 2、按照L298N与单片机的连接,编写电机控制函数。 虽然本文所选的车辆模型的四个电机都可以独立控制,但是为了简单方便,我们让左边两个电机和右边两个电机使用一个公共信号控制。如果需要,可以将其改为4个独立信号控制。根据本文第二部分-硬件连接部分的介绍,我们选定单片机的P34 P35 I/O口作为左电机的方向控制信号,单片机的P36 P37 I/O口作为右电机的方向控制信号,单片机的P16 I/O口作为左电机的PWM输出控制信号,单片机的P17 I/O口作为右电机的PWM输出控制信号。以上6个I/O口的位定义如下(为了方便各个文件的调用,我们将其放在统一的h文件car.h中)
sbit Left_moto_pwm=P1^6 ;
sbit Right_moto_pwm=P1^7;
sbit p34=P3^4;
sbit p35=P3^5;
sbit p36=P3^6;
sbit p37=P3^7;
左右电机的状态控制功能如下:
void Left_moto_go() //左电机正转
{p34=0;p35=1;}
void Left_moto_back() //左电机反转
{p34=1;p35=0;}
void Left_moto_stp() //左电机停转
{p34=1;p35=1;}
void Right_moto_go() //右电机正转
{p36=0;p37=1;}
void Right_moto_back() //右电机反转
{p36=1;p37=0;}
void Right_moto_stp() //右电机停转
{p36=1;p37=1;}
4、编写PWM调速输出函数:对于新手来说,如果对下面两个函数不了解,只需要知道怎么用就可以了。即通过修改push_val_left的值可以调节左边电机的转速,通过修改push_val_right的值可以调节右边电机的转速。push_val_left和push_val_right的值都在1~10之间,值越大电机转速越快。
bit Left_moto_stop =1;
bit Right_moto_stop =1;
unsigned char pwm_val_left =0;
unsigned char push_val_left =0;
unsigned char pwm_val_right =0;
unsigned char push_val_right=0;
void pwm_out_left_moto(void) //左电机调速
{
if(Left_moto_stop)
{
if(pwm_val_left<=push_val_left)
Left_moto_pwm=1;
else
Left_moto_pwm=0;
if(pwm_val_left>=10)
pwm_val_left=0;
}
else
Left_moto_pwm=0;
}
void pwm_out_right_moto(void) //右电机调速
{
if(Right_moto_stop)
{
if(pwm_val_right<=push_val_right)
Right_moto_pwm=1;
else
Right_moto_pwm=0;
if(pwm_val_right>=10)
pwm_val_right=0;
}
else
Right_moto_pwm=0;
}
5.编写小车姿态控制函数:了解了左右电机的状态控制函数之后,编写小车姿态控制函数就很简单了。只要想一想小车左右轮的状态,小车会怎么跑,就明白了。比如说,如果左右电机都在正转,那么小车肯定是往前走的。每个函数的前两行是左右电机转速的设置。
unsigned char Left_Speed_Ratio; //左电机转速的设定值
unsigned char Right_Speed_Ratio; //右电机转速的设定值
void run(void) //小车前行
{
push_val_left =Left_Speed_Ratio;
push_val_right =Right_Speed_Ratio;
Left_moto_go();
Right_moto_go();
}
void back(void) //小车后退
{
push_val_left =Left_Speed_Ratio;
push_val_right =Right_Speed_Ratio;
Left_moto_back();
Right_moto_back();
}
void left(void) //小车左转
{
push_val_left =Left_Speed_Ratio;
push_val_right =Right_Speed_Ratio;
Right_moto_go();
Left_moto_stp();
}
void right(void) //小车右转
{
push_val_left =Left_Speed_Ratio;
push_val_right =Right_Speed_Ratio;
Right_moto_stp();
Left_moto_go();
}
void stop(void) //小车停止
{
push_val_left =Left_Speed_Ratio;
push_val_right =Right_Speed_Ratio;
Left_moto_stp();
Right_moto_stp();
}
void rotate(void) //小车原地转圈
{
push_val_left =Left_Speed_Ratio;
push_val_right =Right_Speed_Ratio;
Left_moto_back();
Right_moto_go();
}
6.编写定时器中断相关的函数
void Timer0Init() //定时器初始化函数
{
TMOD|=0X01;//选择为定时器0模式,工作方式1,仅用TR0打开启动。
TH0=0XFC; //给定时器赋初值,定时1ms
TL0=0X18;
ET0=1;//打开定时器0中断允许
EA=1;//打开总中断
TR0=1;//打开定时器
}
void timer0()interrupt 1 using 2 //定时器中断函数,此处配置为1ms产生一次中断,对PWM的输出进行控制
{
TH0=0XFC; //给定时器赋初值,定时1ms
TL0=0X18;
time++;
pwm_val_left++;
pwm_val_right++;
pwm_out_left_moto();
pwm_out_right_moto();
}
7.延时函数的编写至于延时函数,大家只要会用就行,可以用单片机精灵等辅助软件来生成,下面是一个延时1秒的函数
void delay1s(void)
{
unsigned char a,b,c;
for(c=167;c>0;c--)
for(b=171;b>0;b--)
for(a=16;a>0;a--);
_nop_();
}
8.编写主函数关于主函数,首先我们需要调用定时器中断初始化函数,然后设置左右电机的速度参数。本文主要内容是让小车动起来,所以主函数需要调用本部分第5步编写的小车姿态控制函数来测试一下。为了方便观察,在两个状态之间加入了5秒的延时。代码如下:
void main()
{
Timer0Init();
Left_Speed_Ratio=5; //设置左电机车速为最大车速的50%
Right_Speed_Ratio=5; 设置右电机车速为最大车速的50%
while(1)
{
run();
delay1s(); delay1s(); delay1s(); delay1s(); delay1s();
back();
delay1s(); delay1s(); delay1s(); delay1s(); delay1s();
left();
delay1s(); delay1s(); delay1s(); delay1s(); delay1s();
right();
delay1s(); delay1s(); delay1s(); delay1s(); delay1s();
stop();
delay1s(); delay1s(); delay1s(); delay1s(); delay1s();
rotate();
delay1s(); delay1s(); delay1s(); delay1s(); delay1s();
}
}
四、本文实例完整的C文件和H文件代码1、motor_control.c文件完整代码如下:
#include
unsigned char pwm_val_left =0;
unsigned char push_val_left =0;
unsigned char pwm_val_right =0;
unsigned char push_val_right=0;
unsigned char Left_Speed_Ratio;
unsigned char Right_Speed_Ratio;
bit Left_moto_stop =1;
bit Right_moto_stop =1;
void Left_moto_go() //左电机正转
{p34=0;p35=1;}
void Left_moto_back() //左电机反转
{p34=1;p35=0;}
void Left_moto_stp() //左电机停转
{p34=1;p35=1;}
void Right_moto_go() //右电机正转
{p36=0;p37=1;}
void Right_moto_back() //右电机反转
{p36=1;p37=0;}
void Right_moto_stp() //右电机停转
{p36=1;p37=1;}
void pwm_out_left_moto(void) //左电机PWM
{
if(Left_moto_stop)
{
if(pwm_val_left<=push_val_left)
Left_moto_pwm=1;
else
Left_moto_pwm=0;
if(pwm_val_left>=10)
pwm_val_left=0;
}
else
Left_moto_pwm=0;
}
void pwm_out_right_moto(void) //右电机PWM
{
if(Right_moto_stop)
{
if(pwm_val_right<=push_val_right)
Right_moto_pwm=1;
else
Right_moto_pwm=0;
if(pwm_val_right>=10)
pwm_val_right=0;
}
else
Right_moto_pwm=0;
}
void run(void) //小车前行
{
push_val_left =Left_Speed_Ratio;
push_val_right =Right_Speed_Ratio;
Left_moto_go();
Right_moto_go();
}
void back(void) //小车后退
{
push_val_left =Left_Speed_Ratio;
push_val_right =Right_Speed_Ratio;
Left_moto_back();
Right_moto_back();
}
void left(void) //小车左转
{
push_val_left =Left_Speed_Ratio;
push_val_right =Right_Speed_Ratio;
Right_moto_go();
Left_moto_stp();
}
void right(void) //小车右转
{
push_val_left =Left_Speed_Ratio;
push_val_right =Right_Speed_Ratio;
Right_moto_stp();
Left_moto_go();
}
void stop(void) //小车停止
{
push_val_left =Left_Speed_Ratio;
push_val_right =Right_Speed_Ratio;
Left_moto_stp();
Right_moto_stp();
}
void rotate(void) //小车原地转圈
{
push_val_left =Left_Speed_Ratio;
push_val_right =Right_Speed_Ratio;
Left_moto_back();
Right_moto_go();
}
2、main.c文件完整代码如下:
#include
extern unsigned char Left_Speed_Ratio;
extern unsigned char Right_Speed_Ratio;
unsigned int time=0;
extern unsigned char pwm_val_left;
extern unsigned char pwm_val_right;
void delay1s(void)
{
unsigned char a,b,c;
for(c=167;c>0;c--)
for(b=171;b>0;b--)
for(a=16;a>0;a--);
_nop_();
}
void Timer0Init()
{
TMOD|=0X01;//选择为定时器0模式,工作方式1,仅用TR0打开启动。
TH0=0XFC; //给定时器赋初值,定时1ms
TL0=0X18;
ET0=1;//打开定时器0中断允许
EA=1;//打开总中断
TR0=1;//打开定时器
}
void timer0()interrupt 1 using 2
{
TH0=0XFC; //给定时器赋初值,定时1ms
TL0=0X18;
time++;
pwm_val_left++;
pwm_val_right++;
pwm_out_left_moto();
pwm_out_right_moto();
}
void main()
{
Timer0Init();
Left_Speed_Ratio=5; //设置左电机车速为最大车速的50%
Right_Speed_Ratio=5; 设置右电机车速为最大车速的50%
while(1)
{
run();
delay1s(); delay1s(); delay1s(); delay1s(); delay1s();
back();
delay1s(); delay1s(); delay1s(); delay1s(); delay1s();
left();
delay1s(); delay1s(); delay1s(); delay1s(); delay1s();
right();
delay1s(); delay1s(); delay1s(); delay1s(); delay1s();
stop();
delay1s(); delay1s(); delay1s(); delay1s(); delay1s();
rotate();
delay1s(); delay1s(); delay1s(); delay1s(); delay1s();
}
}
3、car.h文件完整代码如下:
#ifndef __car_H
#define __car_H
#include
#include
sbit Left_moto_pwm=P1^6 ;
sbit Right_moto_pwm=P1^7;
sbit p34=P3^4;
sbit p35=P3^5;
sbit p36=P3^6;
sbit p37=P3^7;
void Left_moto_go() ;
void Left_moto_back() ;
void Left_moto_stp() ;
void Right_moto_go();
void Right_moto_back();
void Right_moto_stp();
void delay(unsigned int k) ;
void delay1s(void) ;
void pwm_out_left_moto(void) ;
void pwm_out_right_moto(void);
void run(void);
void back(void);
void left(void);
void right(void);
void stop(void);
void rotate(void);
5.本文示例的视频演示 视频演示链接 点击上方链接,可以查看本文介绍内容的视频演示,内容如下(即main函数中程序内容):前进5秒,后退5秒,左转5秒,右转5秒,停止5秒,绕圈5秒。 附视频网址:
本文就到此结束,我会把本文的完整项目文件放在附件里,需要的可以拿去,我放上去的时候是免费的,过一段时间就会涨价了……欢迎继续阅读本系列的后续文章《从零开始制作51单片机控制的智能小车详解(下)——超声波模块、漫反射光电管、4路红外传感器的介绍及使用》
本系列文章的附件均可单独下载,附件获取方式如下(建议通过Gitee免费下载):
欢迎大家积极交流。本文未经允许,禁止转载。