具體內(nèi)容見附件
51hei.png (7.33 KB, 下載次數(shù): 30)
下載附件
2019-12-21 20:33 上傳
單片機源程序如下:
- /*****************************************************************************
- ** 文件 : main.c
- ** 作者 : Zheng23
- ** 日期 :
- ** 功能 : 產(chǎn)生8路PWM輸出控制8路舵機,方法:將20毫秒分成8個2500微秒,
- 即8個單元,先計算出第一個單元的舵機PWM控制線的脈沖寬度,因
- 為控制舵機的脈沖寬度最大為2500微秒,剩余的(20000 - 2500)
- 毫秒就是剩下的7個單元時間,第一個單元的舵機PWM控制線全部為
- 低電平了,這時就可以安心的處理剩下的7個單元的事情了,同理
- 第二個單元也是一樣,這樣循環(huán)下去就可以控制8路PWM輸出了。
- /*****************************************************************************/
- //#include <STC15.h>
- //#include"STC89C5xRC.H"
- //一定要用12M的晶振
- //一定要用12M的晶振
- //一定要用12M的晶振
- //一定要用12M的晶振
- //一定要用12M的晶振
- //一定要用12M的晶振
- #include "reg51.h"
- #define bool bit
- #define uint8 unsigned char
- #define uint16 unsigned short int
- #define uint32 unsigned long
- sbit SERVO0=P0^0; //控制舵機的PWM輸出口
- sbit SERVO1=P0^1;
- sbit SERVO2=P0^2;
- sbit SERVO3=P0^3;
- sbit SERVO4=P0^4;
- sbit SERVO5=P0^5;
- sbit SERVO6=P0^6;
- sbit SERVO7=P0^7;
- sbit LED=P2^7; //調(diào)試用
- uint16 ServoPwmDuty[8] = {1500,1500,1500,1500,1500,1500,1500,1500}; //PWM脈沖寬度
- uint16 ServoPwmDutySet[8] = {1500,1500,1500,1500,1500,1500,1500,1500}; //PWM脈沖寬度
- double ServoPwmDutyInc[8]; //為了速度控制,當PWM脈寬發(fā)生變化時,每2.5ms或20ms遞增的PWM脈寬
- bool Flag_20ms = 0; //20毫秒標識位,在定時中斷里面置位
- bool Flag_2_5ms = 0; //2.5毫秒標識位,在定時中斷里面置位
- bool ServoPwmDutyHaveChange = 0; //脈寬有變化標志位
- uint16 ServoTime = 2000; //舵機從當前角度運動到指定角度的時間,也就是控制速度
- /***********************************************************
- * 名 稱: DelayMs(uint16 ms)
- * 功 能: 延時ms毫秒
- * 入口參數(shù): ms 毫秒
- * 出口參數(shù): 無
- * 說 明:
- /**********************************************************/
- void DelayMs(uint16 ms)
- {
- uint16 i,j;
- for(i=0;i<800;i++) //89單片機用85,12系列單片機用800
- for(j=0;j<ms;j++);
- }
- /***********************************************************
- * 名 稱:InitTimer0()
- * 功 能:時鐘0初始化
- * 入口參數(shù):無
- * 出口參數(shù):無
- * 說 明:12M晶振,12分頻,所以計數(shù)器每遞增一個數(shù)就是1微秒,完全滿足舵機控制的精度要求
- 因為定時器是TH0,TL0都要全部計數(shù)到0xFF后在計1個數(shù)就會產(chǎn)生中斷,所以要想產(chǎn)生
- x毫秒的中斷,那么TH0,TL0就應該賦值(0xFFFF-x) 從這個值開始計數(shù)產(chǎn)生定時中斷
- /**********************************************************/
- void InitTimer0(void)
- {
- // AUXR &= 0x7F; //定時器時鐘12T模式
- // AUXR |= 0x00; //T0,T1工作在12T
- TMOD &= 0xF0; //設置定時器模式
- TMOD |= 0x01; //設置定時器模式
- TL0 = 0x00; //設置定時初值
- TH0 = 0x00; //設置定時初值
- TF0 = 0; //清除TF0標志
- TR0 = 1; //定時器0開始計時
- ET0 = 1; //開定時器0中斷
- }
- /***********************************************************
- * 名 稱:Timer0Value(uint16 pwm)
- * 功 能:給定時器0計數(shù)器賦值產(chǎn)生定時中斷
- * 入口參數(shù):pwm 控制舵機的PWM脈沖寬度值(范圍:500~2500)
- * 出口參數(shù):無
- * 說 明:12M晶振,12分頻,所以計數(shù)器每遞增一個數(shù)就是1微秒,完全滿足舵機控制的精度要求
- 因為定時器是TH0,TL0都要全部計數(shù)到0xFF后在計1個數(shù)就會產(chǎn)生中斷,所以要想產(chǎn)生
- pwm毫秒的中斷,那么TH0,TL0就應該賦值(0xFFFF-pwm) 從這個值開始計數(shù)產(chǎn)生定時中斷
- /**********************************************************/
- void Timer0Value(uint16 pwm)
- {
- uint16 value;
- value=0xffff-pwm;
- TR0 = 0;
- TL0=value; //16位數(shù)據(jù)給8位數(shù)據(jù)賦值默認將16位數(shù)據(jù)的低八位直接賦給八位數(shù)據(jù)
- TH0=value>>8; //將16位數(shù)據(jù)右移8位,也就是將高8位移到低八位,再賦值給8位數(shù)據(jù)
- TR0 = 1;
- }
- /***********************************************************
- * 名 稱: ServoPwmDutyCompare()
- * 功 能: 脈寬變化比較及速度控制
- * 入口參數(shù): 無
- * 出口參數(shù): 無
- * 說 明:
- /**********************************************************/
- void ServoPwmDutyCompare()
- {
- uint8 i;
-
- static uint16 ServoPwmDutyIncTimes; //需要遞增的次數(shù)
- static bool ServoRunning = 0; //舵機正在以指定速度運動到指定的脈寬對應的位置
- if(ServoRunning == 0 && ServoPwmDutyHaveChange)//停止運動并且脈寬發(fā)生變化時才進行計算
- {
- ServoPwmDutyHaveChange = 0;
- // ServoPwmDutyIncTimes = ServoTime*2/5; //ServoTime/(20/8) //當每2.5ms調(diào)用一次ServoPwmDutyCompare()函數(shù)時用此句
- ServoPwmDutyIncTimes = ServoTime/20; //當每20ms調(diào)用一次ServoPwmDutyCompare()函數(shù)時用此句
- for(i=0;i<8;i++)
- {
- //if(ServoPwmDuty[i] != ServoPwmDutySet[i])
- {
- if(ServoPwmDutySet[i] > ServoPwmDuty[i])
- {
- ServoPwmDutyInc[i] = ServoPwmDutySet[i] - ServoPwmDuty[i];
- ServoPwmDutyInc[i] = -ServoPwmDutyInc[i];
- }
- else
- {
- ServoPwmDutyInc[i] = ServoPwmDuty[i] - ServoPwmDutySet[i];
-
- }
- ServoPwmDutyInc[i] /= ServoPwmDutyIncTimes;//每次遞增的脈寬
- }
- }
- ServoRunning = 1; //舵機開始動作
- }
- if(ServoRunning)
- {
- ServoPwmDutyIncTimes--;
- for(i=0;i<8;i++)
- {
- if(ServoPwmDutyIncTimes == 0)
- { //最后一次遞增就直接將設定值賦給當前值
- ServoPwmDuty[i] = ServoPwmDutySet[i];
- ServoRunning = 0; //到達設定位置,舵機停止運動
- }
- else
- {
- ServoPwmDuty[i] = ServoPwmDutySet[i] +
- (signed short int)(ServoPwmDutyInc[i] * ServoPwmDutyIncTimes);
- }
- }
-
- }
- }
- /***********************************************************
- * 名 稱: main()
- * 功 能: 入口函數(shù)
- * 入口參數(shù): 無
- * 出口參數(shù): 無
- * 說 明:
- /**********************************************************/
- void main(void)
- {
- uint8 i;
- uint16 Time;
- InitTimer0(); //定時器0初始化
- EA = 1; //開總中斷
- while(1) //大循環(huán)
- {
- if(Flag_20ms) // Flag_2_5ms 2.5毫秒調(diào)用一次ServoPwmDutyCompare()或20毫秒調(diào)用一次
- {
- Flag_20ms = 0;
- Flag_2_5ms = 0;
- Time++;
- ServoPwmDutyCompare();
- }
- if(Time > 110)
- {
- Time = 0;
- LED = ~LED;
- if(ServoPwmDutySet[0] == 500)
- {
- ServoPwmDutySet[0] = 2500; //脈沖寬度在2500微秒,對應90°
- for(i = 1;i<8;i++)
- ServoPwmDutySet[i] = 500; //脈沖寬度在500微秒,對應-90°
- }
- else
- {
- ServoPwmDutySet[0] = 500; //脈沖寬度在500微秒,對應-90°
- for(i = 1;i<8;i++)
- ServoPwmDutySet[i] = 1500; //脈沖寬度在1500微秒,對應0°
- }
- ServoPwmDutyHaveChange = 1;
- }
- }
- }
- /***********************************************************
- * 名 稱: Timer0_isr() interrupt 1 using 1
- * 功 能: 時鐘0中斷處理
- * 入口參數(shù): 無
- * 出口參數(shù): 無
- * 說 明:
- /**********************************************************/
- void Timer0_isr(void) interrupt 1 using 1
- {
- static uint16 i = 1; //靜態(tài)變量:每次調(diào)用函數(shù)時保持上一次所賦的值,
- //跟全局變量類似,不同是它只能用于此函數(shù)內(nèi)部
- switch(i)
- {
- case 1:
- SERVO0 = 1; //PWM控制腳高電平
- //給定時器0賦值,計數(shù)Pwm0Duty個脈沖后產(chǎn)生中斷,下次中斷會進入下一個case語句
- Timer0Value(ServoPwmDuty[0]);
- Flag_20ms = 1;
- Flag_2_5ms = 1;
- break;
- case 2:
- SERVO0 = 0; //PWM控制腳低電平
- //此計數(shù)器賦值產(chǎn)生的中斷表示下一個單元要進行任務的開始
- Timer0Value(2500-ServoPwmDuty[0]);
- break;
- case 3:
- SERVO1 = 1;
- Timer0Value(ServoPwmDuty[1]);
- Flag_2_5ms = 1;
- break;
- case 4:
- SERVO1 = 0; //PWM控制腳低電平
- Timer0Value(2500-ServoPwmDuty[1]);
- break;
- case 5:
- SERVO2 = 1;
- Timer0Value(ServoPwmDuty[2]);
- Flag_2_5ms = 1;
- break;
- case 6:
- SERVO2 = 0; //PWM控制腳低電平
- Timer0Value(2500-ServoPwmDuty[2]);
- break;
- case 7:
- SERVO3 = 1;
- Timer0Value(ServoPwmDuty[3]);
- Flag_2_5ms = 1;
- break;
- case 8:
- SERVO3 = 0; //PWM控制腳低電平
- Timer0Value(2500-ServoPwmDuty[3]);
- break;
- case 9:
- SERVO4 = 1;
- Timer0Value(ServoPwmDuty[4]);
- Flag_2_5ms = 1;
- break;
- case 10:
- SERVO4 = 0; //PWM控制腳低電平
- Timer0Value(2500-ServoPwmDuty[4]);
- break;
- case 11:
- SERVO5 = 1;
- Timer0Value(ServoPwmDuty[5]);
- Flag_2_5ms = 1;
- break;
- case 12:
- SERVO5 = 0; //PWM控制腳低電平
- Timer0Value(2500-ServoPwmDuty[5]);
- break;
- case 13:
- SERVO6 = 1;
- Timer0Value(ServoPwmDuty[6]);
- Flag_2_5ms = 1;
- break;
- case 14:
- SERVO6 = 0; //PWM控制腳低電平
- Timer0Value(2500-ServoPwmDuty[6]);
- break;
- case 15:
- SERVO7 = 1;
- Timer0Value(ServoPwmDuty[7]);
- Flag_2_5ms = 1;
- break;
- case 16:
- SERVO7 = 0; //PWM控制腳低電平
- Timer0Value(2500-ServoPwmDuty[7]);
- i = 0;
- break;
- }
- i++;
- }
復制代碼
所有資料51hei提供下載:
STC單片機舵機PWM控制教程.zip
(284.19 KB, 下載次數(shù): 113)
2019-12-21 20:27 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
|