智能小车的初认识---1

硬件介绍

小车:

 面包板:

用于扩展接线,由于小车可以扩展许多模块,所以使用面包板增加容错性

L9110s:

电机的驱动模块,接通VCC,GND模块电源指示灯亮;下图中集成了两个L9110s。

B-1A -> P3.2B-1B -> P3.3; A-1A -> P3.4; A-1B -> P3.5;

正转时:B_1A = 0; B_1B = 1; A_1A = 0; A_1B = 1;

反转时:B_1A = 1; B_1B = 0; A_1A = 1; A_1B = 0;

初步接线图:

PS:面包板,开关和单片机均采用热熔胶固定,电机及其驱动模块均由电池供电,除了上面提到L9110s和单片机的控制接线和电源之外,注意要有一根杜邦线让单片机和L9110s共地

让小车动起来

将小车组装完成后,首先就是要让小车动起来,由刚刚对于电机驱动模块的讲解可以很容易实现让电机正反转,基于此,前进后退,左转右转的代码就都能写出来了:

void move_backward() //后退
{
	B_1A_le = 1;
	B_1B_le = 0;
	
	A_1A_ri = 1;
	A_1B_ri = 0;
}

void move_forward() //前进
{
	B_1A_le = 0;
	B_1B_le = 1;
	
	A_1A_ri = 0;
	A_1B_ri = 1;
}

void move_leftturn() //左转
{
	B_1A_le = 0; //左轮不动
	B_1B_le = 0;
	
	A_1A_ri = 0; //右轮往前
	A_1B_ri = 1;
}

void move_rightturn() //右转
{
	B_1A_le = 0; //左轮往前
	B_1B_le = 1;
	
	A_1A_ri = 0; //右轮不动
	A_1B_ri = 0;
}

void move_stop() //停止
{
	B_1A_le = 0;
	B_1B_le = 0;
	
	A_1A_ri = 0;
	A_1B_ri = 0;
}

让小车前进的 实现效果:

 代码封装

由于小车代码肯定会巨长无比,所以养成良好的习惯,习惯性的完成一个模块之后就封装,方法和上节DHT11的末尾方法一样, 创建motor的c和h文件。

小车的控制

在熟悉了小车如何进行移动之后,就要开始学习如何控制小车,在之前已经学习过各种模块了,其中就有很多可以用来控制小车:

1. 串口/蓝牙控制小车

依然采用封装函数的方法:

UART.c:

#include "reg52.h"
#include "delay.h"
#include "motor.h"
#include <string.h>

sfr AUXR = 0x8E; //配置了这句话,才可以在UART的初始化里写AUXR寄存器,原因见STC89系列的手册
static int i = 0; //此时这句命令只会被执行一次。避免每次发生中断i都会清0
char cmd[12];

void UartInit(void)		//9600bps@11.0592MHz
{
	PCON &= 0x7F;		//波特率不倍速
	SCON = 0x50;		//8位数据,可变波特率
	AUXR &= 0xBF;		//定时器1时钟为Fosc/12,即12T
	AUXR &= 0xFE;		//串口1选择定时器1为波特率发生器
	TMOD &= 0x0F;		//清除定时器1模式位
	TMOD |= 0x20;		//设定定时器1为8位自动重装方式
	TL1 = 0xFD;		//设定定时初值
	TH1 = 0xFD;		//设定定时器重装值
	ET1 = 0;		//禁止定时器1中断
	TR1 = 1;		//启动定时器1
}

void printSTR(char *msg)
{
	while(*msg != '\0'){
		SBUF = *msg; //往发送缓冲器里写入数据,就完成了数据的发送
		while(TI == 0); //只有当TI为1时,才往下走,根据手册,TI只有在发送完8位数据后才会硬件自动置1
		TI = 0;
		msg++;
	}
	
}

void Dealstr()
{
	  if(cmd[0] == 'M' && cmd[1] == '1'){ //前进
			move_forward();
			memset(cmd,'\0',12); //将字符串清空
		}
		
		if(cmd[0] == 'M' && cmd[1] == '2'){ //后退
			move_backward();
			memset(cmd,'\0',12); //将字符串清空
		}
		
		if(cmd[0] == 'M' && cmd[1] == '3'){ //左转
			move_leftturn();
			memset(cmd,'\0',12); //将字符串清空
		}
		
		if(cmd[0] == 'M' && cmd[1] == '4'){ //右转
			move_rightturn();
			memset(cmd,'\0',12); //将字符串清空
		}
		
		if(cmd[0] == 'M' && cmd[1] == '5'){ //停止
			move_stop();
			memset(cmd,'\0',12); //将字符串清空
		}
						
}

void UARTinter() interrupt 4 //由于不管TI还是RI置1时,中断都会发生,所以为了逻辑严谨,可以在中断处理函数中添加判断
{
	if(RI == 1){ //如果是RI引起的中断
		char tmp;
		
		tmp = SBUF;
		
		if(tmp == 'M'|| i == 12){ //M1=前进;M2=后退;M3=左转;M4=右转; M5=停止
			i = 0;
		}
		
		cmd[i] = tmp; //从SBUF里面读发来的数据
		i++;
		
		Dealstr();
		RI = 0;//软件复位
	
  }
	
}

main.c:

#include "reg52.h"
#include "intrins.h" //这个库加了,delay函数里面的nop()才不会报错
#include "motor.h"
#include "delay.h"
#include "UART.h"


sbit D5 = P3^7;


void main()
{
	
	UartInit();
	ES = 1;
	EA = 1; //打开中断!
	
	while(1){
		printSTR("mjm");
		Delay1000ms();
	}
	
	
}

 实现效果:

 可以不断接受心跳指令的同时,写下M1,M2,M3,M4,M5电机会做出对应的动作。

实现了串口,就相当于实现了蓝牙,因为蓝牙模块也使用了串口:

同样, 可以不断接受心跳指令的同时,写下M1,M2,M3,M4,M5电机会做出对应的动作。

  PS: 连一根杜邦线接面包板的正极和单片机的VCC,加上之前连的共地线,就可以实现电池给单片机的供电,从而实现小车的无线控制。并且,这种方式不是点动,比如左转一点点我要输入M3,然后再输入M5停下,但是现实生活中的遥控车,按下左转的时候左转,不按就不会左转,即现实中的遥控车是点动的,而我以上实现的并不是。

同时注意到虽然我输入的是M1是前进的意思,但是车子并没有笔直往前,说明小车两边的电机输出可能存在一定的差异。

2.使用无线遥控器遥控

我同样尝试了使用做电瓶车遥控器时用过的433M无线收发模块:

 

 433M.c:

#include "reg52.h"
#include "motor.h"
#include "delay.h"

sbit D0 = P0^0;
sbit D1 = P0^1;
sbit D2 = P0^2;
sbit D3 = P0^3;

void statusCheck()
{
	if(D0 == 1){ //D0(A)为前进
		move_forward();
	}else if(D1 == 1){ //D1(B)为右转
		move_rightturn();
	}else if(D2 == 1){ //D2(C)为左转
		move_leftturn();
	}else if(D3 == 1){ //D3(D)为后退
		move_backward();
	}else{
		move_stop();
	}
}

 main.c:

#include "reg52.h"
#include "intrins.h" //这个库加了,delay函数里面的nop()才不会报错
#include "motor.h"
#include "delay.h"
#include "433M.h"


void main()
{
		
	while(1){
		statusCheck();
	}
	
	
}

PS:这种实现方式虽然可以实现点动,但是太“点”了,即我按一下按钮,电机只会微弱的转一下,而如果我长按,电机也只会不停的一抽一抽的微弱转动没法连续转动。。。

小车的PWM调速

在刚刚的控制中,实现了上下左右的控制,但是小车的速度无法控制,所以需要用PWM波来对小车的速度来进行控制:已知,对于电机,写1就是全速前进,那么比如在20ms内,如果一半的时间写1,一半的时间写0,那就会比20ms一直是1来的速度慢一半,基于这种思路就可以用PWM波,通过调整占空比来控制小车的速度:

timer0.c:

#include "reg52.h"
#include "motor.h"

sfr AUXR = 0x8E; //配置了这句话,才可以在UART的初始化里写AUXR寄存器,原因见STC89系列的手册
int cnt = 0;
char speed;

void Timer0Init(void)		//0.5毫秒@11.0592MHz
{
	AUXR &= 0x7F;		//定时器时钟12T模式
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;		//设置定时器模式
	TL0 = 0x33;		//设置定时初值
	TH0 = 0xFE;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	
	ET0 = 1;
	EA = 1;   //打开中断!
}

//timer0的中断处理程序 //中断程序一般写在main函数的后面 //定时器0溢出时将触发这个中断函数
void timer0_inter() interrupt 1 
{
	cnt++;
	TL0 = 0x33;		//重新给初值!!
	TH0 = 0xFE;
	
	if(cnt < speed){ //cnt =1 时,爆表了一次,过了0.5ms,speed的值越大,属于动的代码就占比越大,速度就越快
		//动
		move_forward();
	}else{
		//停止
		move_stop();
	}
 
	if(cnt == 39){//每经过(40*0.5毫秒 = )20毫秒,PWM波经过一个周期
		cnt = 0;
	}
	
}

main.c:

#include "reg52.h"
#include "intrins.h" //这个库加了,delay函数里面的nop()才不会报错
#include "motor.h"
#include "delay.h"
#include "UART.h"
#include "433M.h"
#include "timer0.h"

extern char speed;

void main()
{
	
	UartInit();
	
	Timer0Init();
	
	
	while(1){
		speed = 10; //10/40 = 1/4的时间全速前进
		Delay1000ms();
		Delay1000ms();
		
		speed = 30; //30/40 = 3/4的时间全速前进
		Delay1000ms();
		Delay1000ms();
		
	}
	
	
}

实现效果: 

可以看到,小车每隔两秒就会在慢速和快速之间切换:

左右轮的分别调速:

要实现这个效果,首先要在motor.c中添加单独控制左右轮前进后退的代码:

void move_backward_left() //左轮后退
{
	B_1A_le = 1;
	B_1B_le = 0;
}

void move_backward_right() //右轮后退
{
	A_1A_ri = 1;
	A_1B_ri = 0;
}

void move_forward_left() //左轮前进
{
	B_1A_le = 0;
	B_1B_le = 1;
}

void move_forward_right() //右轮前进
{
	A_1A_ri = 0;
	A_1B_ri = 1;
}

void move_stop_left() //左轮停止
	B_1A_le = 0;
	B_1B_le = 0;
}

void move_stop_right() //右轮停止
{
	A_1A_ri = 0;
	A_1B_ri = 0;
}

然后在timer0.c中进行修改,我名字起的不太好,要是要实现左右轮的控制,就需要两个timer,一个控制左轮一个控制右轮:

#include "reg52.h"
#include "motor.h"

sfr AUXR = 0x8E; //配置了这句话,才可以在UART的初始化里写AUXR寄存器,原因见STC89系列的手册
int cnt1 = 0;
int cnt2 = 0;
char speed_left;
char speed_right;

void Timer0Init(void)		//timer0控制左轮
{
	AUXR &= 0x7F;		//定时器时钟12T模式
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;		//设置定时器模式
	TL0 = 0x33;		//设置定时初值
	TH0 = 0xFE;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	
	ET0 = 1;
	EA = 1;   //打开中断!
}

void Timer1Init(void)		//timer1控制右轮
{
	AUXR &= 0xBF;		//定时器时钟12T模式
	TMOD &= 0x0F;		//设置定时器模式
	TMOD |= 0x10;		//设置定时器模式
	TL1 = 0x33;		//设置定时初值
	TH1 = 0xFE;		//设置定时初值
	TF1 = 0;		//清除TF1标志
	TR1 = 1;		//定时器1开始计时
	
	ET1 = 1;
	EA = 1;   //打开中断!
}


//timer0的中断处理程序 //中断程序一般写在main函数的后面 //定时器0溢出时将触发这个中断函数
void timer0_inter() interrupt 1 
{
	cnt1++;
	TL0 = 0x33;		//重新给初值!!
	TH0 = 0xFE;
	
	if(cnt1 < speed_left){ //cnt =1 时,爆表了一次,过了0.5ms,speed的值越大,属于动的代码就占比越大,速度就越快
		//动
		move_forward_left();
	}else{
		//停止
		move_stop_left();
	}
 
	if(cnt1 == 39){//每经过(40*0.5毫秒 = )20毫秒,PWM波经过一个周期
		cnt1 = 0;
	}
	
}

//timer1的中断处理程序 //中断程序一般写在main函数的后面 //定时器1溢出时将触发这个中断函数
void timer1_inter() interrupt 3 
{
	cnt2++;
	TL1 = 0x33;		//重新给初值!!
	TH1 = 0xFE;
	
	if(cnt2 < speed_right){ //cnt =1 时,爆表了一次,过了0.5ms,speed的值越大,属于动的代码就占比越大,速度就越快
		//动
		move_forward_right();
	}else{
		//停止
		move_stop_right();
	}
 
	if(cnt2 == 39){//每经过(40*0.5毫秒 = )20毫秒,PWM波经过一个周期
		cnt2 = 0;
	}
	
}

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
淘宝买了几个4g舵机,3.2一个,价格便宜,但是不带电路板和摆臂。 样子如下图,带5根线,2根电机线,3根电位器线。 拆开后,大概就是这个样子,可见棕色和白色两根线接电位器的两端,黄线接电位器中间。 我这里用的图,都是淘宝卖家拍的,下面的拆开图,是6g舵机的,但是接线是一样的。 万用表测量了一下,这个电位器是4.9K的,也就当5K吧。 这个舵机是萝莉群的群友推荐的,希望我能做个舵机的电路板出来驱动它。 一直拖了一个多星期吧,硬件电路是几天前就搭好了,今天下午大概写了一下代码,本来想用一下PID算法,显得高大上一点,不过后来看了看,这种东西比较简单,单纯的比例算法就可以了,不需要PID这么复杂。 思路大概解释一下。 电路板用了3个元件,一个STC15W408AS DIP16的单片机。 这个单片机带10位精度的ADC,刚好测量舵机里面电位器的位置。 然后电机驱动用的L9110 DIP8。 L9110最大电流0.8A,对于4g舵机的小空心杯电机来说,足够了。 而且L9110的电路也非常简单。 最后一个元件就是加了个47uf的电容。如果是改贴片元件,大概10uf和0.1uf两个贴片电容就差不多了。 L9110的基本应用电路如下: STC15W408AS DIP16 的引脚图如下: 顺便说一下,我用直插元件和洞洞板搭了一个驱动电路,没有采用贴片元件和打板子。 因为重点还是单片机的电路设计和编程,而不是做一个比较完美的成品。 4g舵机驱动板程序部分截图:

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值