——用程序来控制轮子
PWM控制电路完工了,接下来得把电路接到单片机,由单片机进行控制了。回想电路图:
这个图中,输入有3根组,A,B,C,其中,A入口,我们可以当成PWM控制线,B,C为正反转、停止控制线,整个状态可以罗列为下面表格:
A控制 |
B控制 |
C控制 |
Q1 |
Q2 |
Q3 |
Q4 |
电机状态 |
X |
0 |
0 |
0/导通 |
0/导通 |
0/截止 |
0/截止 |
刹车 |
PWM |
1 |
0 |
1/截止 |
0/导通 |
PWM |
0/截止 |
正转 |
PWM |
0 |
1 |
0/导通 |
1/截止 |
0/截止 |
PWM |
反转 |
0 |
1 |
1 |
1/截止 |
1/截止 |
0/截止 |
0/截止 |
惰行 |
1 |
1 |
1 |
1/截止 |
1/截止 |
1/导通 |
1/导通 |
刹车 |
?
为了方便代码管理,我们在工程中建一个car.c和car.h文件,专门编写控制小车的程序:
?
程序开始,引入相应头文件:
#include<reg52.h>
#include "common.h"
#include "car.h"
?
定义好PWM电路的接入引脚:
sbit Ctl_R1=P2^4;
//右轮控制端1
sbit Ctl_R2=P2^5;
//右轮控制端2
sbit PWM_R=P2^3;
//右轮PWM端
?
sbit Ctl_L1=P2^2;
//左轮控制端1
sbit Ctl_L2=P2^1;
//左轮控制端2
sbit PWM_L=P2^0;
//左轮PWM端
?
为了代码清楚,我们将car这个(对象),整成2个函数:
void InitCar()
{
}
?
void CarGo(int left,int right)
{
}
将两个函数的函数体写入到car.c中,将函数的定义,写入到car.h中。
两个函数分别意义为:InitCar为小车初使化,CarGo为小车控制,参数left、right分别代表左右轮,然后值为-100~100,当为0时,则停止,当为负数时,则反转,数值大小代表转动速度,值越大越快。
好了,测试工作总是逐步的,而不是一步到位,我们先来试一下基本的正反转及停,调速的后面再来。
void InitCar()
{
CarGo(0,0);
PWM_R =
1;
PWM_L =
1;
}
void CarGo(int left,int right)
{
if
( right >0)
{
Ctl_R1=0;
Ctl_R2=1;
}
else
if
(right ==0)
{
Ctl_R1=0;
Ctl_R2=0;
}
else
if
(right<0)
{
Ctl_R1=1;
Ctl_R2=0;
}
?
if
( left >0)
{
Ctl_L1=0;
Ctl_L2=1;
}
else
if
(left ==0)
{
Ctl_L1=0;
Ctl_L2=0;
}
else
if
(left<0)
{
Ctl_L1=1;
Ctl_L2=0;
}
}
好了,简单的程序,应该很容易能看懂,测试么,得写个main函数咯。
#include "car.h"
#include "common.h"
?
void main()
{
//小车初使化
InitCar();
CarGo(100,0);
Delay(2000);
CarGo(0,100);
Delay(2000);
CarGo(-100,0);
Delay(2000);
CarGo(0,-100);
Delay(2000);
CarGo(0,0);
}
经常会用到一些通用函数,如里面的delay之类的,所以我们又建一个common.c和common.h文件,将一些通用的方法写入,比如这里的:
/*****************************************************
* 函数功能:延时若干毫秒
* 入口参数:n
***************************************************/
void Delay(unsigned
int i)
{
unsigned
int j;
for(;i>0;i--)
//变量i由实际参数传入一个值,因此i不能赋初值
for(j=0;j<125;j++)
{;}
}
?
整个程序也容易看清的,每隔2秒后,可以看到电机会变换一个状态。将程序烧写到单片机中,运行,观察吧。
如果发现状态不对,那就得debug了。
- 如果发现某个状态不对,可以把程序单独调这个状态,然后跟据上面的表格,从单片机输出,到场效管引脚,用万用表一步步量,就可以看到哪步上有问题。
- 如果发现正反转不对,反了。那就简单,可以把CarGo函数控制0和1的地方反写一下即可。
?
一切调通后,就剩下PWM了,上一章中,我们知道速度通过占空比来实现的。
换句话说,我们要针对PWM引脚要连续的输出0和1变换值。所以这里我们得引入单片的计数器和中断。
TH0和TL0是计数器0的高8位和低8位计数器,计算办法:TL0=(65536-C)%256;TH0=(65536-C)/256,其中C为所要计数的次数即多长时间产生一次中断;TMOD是计数器工作模式选择,0X01表示选用模式1,它有16位计数器,最大计数脉冲为65536,最长时间为1ms*65536=65.536ms
#define V_TH0 0XFE
#define V_TL0 0XF6
#define V_TMOD 0X01
unsigned
char ZKB1,ZKB2;
void InitCar()
{
CarGo(0,0);
?
/*定时器初始化 */
TMOD=V_TMOD;
TH0=V_TH0;
TL0=V_TL0;
TR0=1;
ET0=1;
EA=1;
?
ZKB1 =
0;
ZKB2 =
0;
}
?
?
/*中断函数 */
void timer0(void) interrupt 1 using 2
{
static uchar click=0;
//中断次数计数器变量
TH0=V_TH0;
//恢复定时器初始值
TL0=V_TL0;
++click;
if
(click>=100)
click=0;
?
if
(click<=ZKB1)
//当小于占空比值时输出低电平,高于时是高电平,从而实现占空比的调整
PWM_R=0;
else
PWM_R=1;
?
if
(click<=ZKB2)
//当小于占空比值时输出低电平,高于时是高电平,从而实现占空比的调整
PWM_L=0;
else
PWM_L=1;
}
?
说明:iitcar中对定时器进行初使化。timer0函数中不对的计数,当click计值到ZKB1时,把PWM值反转一下。这个ZKB1在就是在CarGo中赋值的left,right值的绝对值。
OK,到此,这个Car.c文件,就可以收功了,后面只需要调用一下这里面的函数,就可以相应的来控制小车的电机了。
?
?