基於51單片機的高精度舵機控制程序PWM 定時器

摘    要

雖然舵機的控制原理比較簡單統一,但是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);
}


 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章