单片机交流
直播中

李志静

7年用户 1403经验值
私信 关注
[问答]

如何让智能小车动起来?怎样去编写其程序?

如何让智能小车动起来?怎样去编写其程序?
怎样去选择智能小车的硬件?智能小车的硬件是如何进行连接的?
如何从零开始用51单片机去实现智能小车的控制?

回帖(1)

武妹

2021-7-14 12:19:34
  从本文开始,在之后的一段时间里,我会通过本系列文章,详细介绍如何从零开始用51单片机去实现智能小车的控制,本文作为本系列的第一篇文章,主要介绍如何让小车动起来。
  一、硬件的选择
  1、底盘和电机
  底盘的形状呢,大家可以按照自己的需要自主选取,至于电机关注一下工作电压,转速,电机类型就差不多,对于新手,可以尝试以下样式(4WD智能小车底盘,附带4个直流减速电机,电机接线需要自己焊接),也就是本文例子采用的底盘和电机,组装简单,使用方便,特别适合新手。
  2、电机驱动模块
  L298N电机驱动模块,绝对是新手的首选,但是此系列也包含了很多类型,本文采用的是L298N双H桥驱动 红色版 ,除了性能外,我选择它是因为它具备了5v的输出接口,可以用来给单片机供电。大家可以用两个这种驱动,也可以用一个,另一个用个便宜点的。
  由于家中有一个如下式样的L298N驱动,所以为了不让资源浪费,另一个,我就用如下型号的L298N驱动。
  3、单片机最小系统
  关于最小系统,大家只要选用自己熟悉的就行了,没什么特别的讲究,我采用的样式如下(芯片采用的是STC89C52)
  4、电源
  这一部分大家根据需要自己选择即可,选的时候注意一下电压和容量就行,我选用的是常见的 9v 650mAh(容量不是很大,但是这种电池比较常见,充一次电跑2~3小时应该不是问题),我选的是USB充电款,充电很方便,电池盒我选用的是如下的这种拆卸方便的款式,缺点就是不附带电源开关。
  5、杜邦线
  这是必备的辅件,就不多说了,公对公,母对母,公对母(这一种一般用的多一些)都要买一些,家里常备物品。
  二、硬件的连接
  本文涉及到的硬件连接为单片机、电源、 电机、 两个电机驱动L298N之间的连接,在这里我介绍一种参考的连接方式,大家可以自己设计连接方案
  四个电机的正负极分别接两个L298N的绿色电机接口,至于到底哪个接正极,哪个接负极,根据你电机安装的方式而定,建议先把电机的两根线焊上,然后把底盘安装起来,这样电机的安装方式就确定了,先随便把两个L298N的4个绿色电机接口跟电机相接,等到把其他信号线接好后,再判断对错并调节,调节方法如下:在程序中让小车往前跑,观察车轮的转向,往前转的车轮的线不用变,把往后转的电机对应的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为例,由于本次设计的小车控制并不复杂,所以我把工程中用到的所有头文件、函数的定义、***it定义的位变量都放到了一个头文件中,取名为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中)
  ***it Left_moto_pwm=P1^6 ;***it Right_moto_pwm=P1^7;***it p34=P3^4;***it p35=P3^5; ***it p36=P3^6;***it 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; //给定时器赋初值,定时1msTL0=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 《car.h》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 《car.h》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; //给定时器赋初值,定时1msTL0=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 《reg52.h》#include 《intrins.h》***it Left_moto_pwm=P1^6 ;***it Right_moto_pwm=P1^7;***it p34=P3^4;***it p35=P3^5; ***it p36=P3^6;***it 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);
       
举报

更多回帖

发帖
×
20
完善资料,
赚取积分