——用程序來控制輪子
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文件,就可以收功了,后面只需要調用一下這里面的函數,就可以相應的來控制小車的電機了。