摘 要
雖然舵機的控制原理比較簡單統一,但是PWM控制舵機的程序實現方式多種多樣,有的使用延時(delay(ms)),有的使用定時器(time),而網上搜到的大部分控制代碼卻質量一般,控制精度都需要提高,就要對單片機定時器有詳細的瞭解,否則延時將出現偏差。
本文使用單片機T2定時器,這個定時器大多數人很少使用它,而卻不知道它有一個非常優秀的功能就是定時自動重載功能。利用這個功能能夠更爲精確的對定時器進行設定,可控制精度在1個機器週期(12M晶振下就是1us),T0、T1都需要手動重載,其精度無法很好的控制。
關鍵詞:51單片機 舵機 精準控制 PWM T2定時器
本程序硬件需求
/*------------------------------
硬件需求: 12T系列單片機(8051內核)
擁有T2定時器
12M時鐘晶振
P2_0輸出控制
舵機角度範圍在0~180 高電平範圍0.5ms~2.5ms 20ms週期
--------------------------------*/
軟件仿真演示(精準的50Hz的PWM信號)
程序設計思想:
根據舵機對PWM的需求,我們可以得知在20ms的週期中,我們需要在輸出開始爲高電平,在高電平結束時觸發中斷改爲低電平,低電平結束後由觸發中斷將其設置爲輸出高電平,如此循環往復。
其中我們可以發現,我們的定時器是不斷根據角度的設定而變化的,而定時器的工作需要在計時高電平與低電平間來回切換,這個定時器定時下次時間是通過裝載在RCAP中的初始值決定了,於是我們完全可以通過設定RCAP2L,RCAP2H來改變下一次的定時時間,根據這個思想 定時器中斷中便如此設計。 if(SW)的分支語句 將20ms分爲高低電平的定時 而且可以確定兩者之和是20ms 也就是說完成了20ms的週期PWM波的輸出。
具體功能見代碼 ,註釋,有問題請在評論區留言
// Header:舵機控制程序
// File Name:
// Author:程濛濛(QQ1058515967)
// Date:2018年9月12日
//Description:基於12T系列單片機且有T2定時器的單片機舵機控制程序
//,本程序控制精度高(1us),定時器自動控制舵機轉動
/*------------------------------
硬件需求: 12T系列單片機(8051內核)
擁有T2定時器
12M時鐘晶振
P2_0輸出控制
舵機角度範圍在0~180 高電平範圍0.5ms~2.5ms 20ms週期
--------------------------------*/
#include <REGX52.H>
#define T2_PWMout P2_0 //舵機控制端
unsigned int PWMTimes=0;//高電平時間
unsigned char angle=0; //測試角度
void T2_Init();//初始化定時器2
void SetMotoangle(float angle);//設置舵機角度
void Delay100ms(); //@12.000MHz
void main()
{
bit SWdir=0;
T2_Init();//初始化定時器
while(1)//演示程序,舵機左右擺動
{
if(angle>180)SWdir=0;
else if(angle==0)SWdir=1;
SetMotoangle(SWdir?angle++:angle--);
Delay100ms();
}
}
void T2_Init()
{
unsigned int time=65536-20000;
RCAP2L = TL2 = time; //initial timer2 low byte
RCAP2H = TH2 = time >> 8; //initial timer2 high byte
TR2 = 1; //timer2 start running
ET2 = 1; //enable timer2 interrupt
EA = 1; //open global interrupt switch
}
void SetMotoangle(float angle)
{
//防止越界而損傷電機
if(angle > 175) angle = 175;
if(angle <5) angle = 5;
PWMTimes=500+angle*2000.0/180;//計算出高電平時間
}
/* Timer2 interrupt routine */
void tm2_isr() interrupt 5 using 1
{
static bit SW=0;
unsigned int T2count;
TF2 = 0;//標誌位清零
SW=~SW;//狀態取反
T2_PWMout=SW;//更新輸出
if(SW)//低電平時間
{
T2count=0xB1E0+PWMTimes;//0xB1E0即爲20ms中斷用時
RCAP2L=T2count;
RCAP2H=T2count>>8;
}
else//高電平時間
{
T2count=0-PWMTimes;
RCAP2L=T2count;
RCAP2H=T2count>>8;
}
}
void Delay100ms() //@12.000MHz
{
unsigned char i, j;
i = 195;
j = 138;
do
{
while (--j);
} while (--i);
}