欧美极品高清xxxxhd,国产日产欧美最新,无码AV国产东京热AV无码,国产精品人与动性XXX,国产传媒亚洲综合一区二区,四库影院永久国产精品,毛片免费免费高清视频,福利所导航夜趣136
標題:
STC單片機關于舵機pwm控制源程序(單個與多個速度控制都有)
[打印本頁]
作者:
k.leonard
時間:
2019-12-21 20:28
標題:
STC單片機關于舵機pwm控制源程序(單個與多個速度控制都有)
具體內容見附件
51hei.png
(7.33 KB, 下載次數: 30)
下載附件
2019-12-21 20:33 上傳
單片機源程序如下:
/*****************************************************************************
** 文件 : main.c
** 作者 : Zheng23
** 日期 :
** 功能 : 產生8路PWM輸出控制8路舵機,方法:將20毫秒分成8個2500微秒,
即8個單元,先計算出第一個單元的舵機PWM控制線的脈沖寬度,因
為控制舵機的脈沖寬度最大為2500微秒,剩余的(20000 - 2500)
毫秒就是剩下的7個單元時間,第一個單元的舵機PWM控制線全部為
低電平了,這時就可以安心的處理剩下的7個單元的事情了,同理
第二個單元也是一樣,這樣循環下去就可以控制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; //調試用
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脈寬發生變化時,每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毫秒
* 入口參數: ms 毫秒
* 出口參數: 無
* 說 明:
/**********************************************************/
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初始化
* 入口參數:無
* 出口參數:無
* 說 明:12M晶振,12分頻,所以計數器每遞增一個數就是1微秒,完全滿足舵機控制的精度要求
因為定時器是TH0,TL0都要全部計數到0xFF后在計1個數就會產生中斷,所以要想產生
x毫秒的中斷,那么TH0,TL0就應該賦值(0xFFFF-x) 從這個值開始計數產生定時中斷
/**********************************************************/
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計數器賦值產生定時中斷
* 入口參數:pwm 控制舵機的PWM脈沖寬度值(范圍:500~2500)
* 出口參數:無
* 說 明:12M晶振,12分頻,所以計數器每遞增一個數就是1微秒,完全滿足舵機控制的精度要求
因為定時器是TH0,TL0都要全部計數到0xFF后在計1個數就會產生中斷,所以要想產生
pwm毫秒的中斷,那么TH0,TL0就應該賦值(0xFFFF-pwm) 從這個值開始計數產生定時中斷
/**********************************************************/
void Timer0Value(uint16 pwm)
{
uint16 value;
value=0xffff-pwm;
TR0 = 0;
TL0=value; //16位數據給8位數據賦值默認將16位數據的低八位直接賦給八位數據
TH0=value>>8; //將16位數據右移8位,也就是將高8位移到低八位,再賦值給8位數據
TR0 = 1;
}
/***********************************************************
* 名 稱: ServoPwmDutyCompare()
* 功 能: 脈寬變化比較及速度控制
* 入口參數: 無
* 出口參數: 無
* 說 明:
/**********************************************************/
void ServoPwmDutyCompare()
{
uint8 i;
static uint16 ServoPwmDutyIncTimes; //需要遞增的次數
static bool ServoRunning = 0; //舵機正在以指定速度運動到指定的脈寬對應的位置
if(ServoRunning == 0 && ServoPwmDutyHaveChange)//停止運動并且脈寬發生變化時才進行計算
{
ServoPwmDutyHaveChange = 0;
// ServoPwmDutyIncTimes = ServoTime*2/5; //ServoTime/(20/8) //當每2.5ms調用一次ServoPwmDutyCompare()函數時用此句
ServoPwmDutyIncTimes = ServoTime/20; //當每20ms調用一次ServoPwmDutyCompare()函數時用此句
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()
* 功 能: 入口函數
* 入口參數: 無
* 出口參數: 無
* 說 明:
/**********************************************************/
void main(void)
{
uint8 i;
uint16 Time;
InitTimer0(); //定時器0初始化
EA = 1; //開總中斷
while(1) //大循環
{
if(Flag_20ms) // Flag_2_5ms 2.5毫秒調用一次ServoPwmDutyCompare()或20毫秒調用一次
{
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中斷處理
* 入口參數: 無
* 出口參數: 無
* 說 明:
/**********************************************************/
void Timer0_isr(void) interrupt 1 using 1
{
static uint16 i = 1; //靜態變量:每次調用函數時保持上一次所賦的值,
//跟全局變量類似,不同是它只能用于此函數內部
switch(i)
{
case 1:
SERVO0 = 1; //PWM控制腳高電平
//給定時器0賦值,計數Pwm0Duty個脈沖后產生中斷,下次中斷會進入下一個case語句
Timer0Value(ServoPwmDuty[0]);
Flag_20ms = 1;
Flag_2_5ms = 1;
break;
case 2:
SERVO0 = 0; //PWM控制腳低電平
//此計數器賦值產生的中斷表示下一個單元要進行任務的開始
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++;
}
復制代碼
/*****************************************************************************
** 文件 : main.c
** 作者 : Zheng23
** 日期 :
** 功能 :
/*****************************************************************************/
//#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 LED=P2^7; //調試用
uint16 ServoPwmDuty=1500; //PWM脈沖寬度
uint16 ServoPwmDutySet=1500;
double ServoPwmDutyInc;
bool Flag_20ms = 0; //20毫秒標識位,在定時中斷里面置位
bool ServoPwmDutyHaveChange = 0; //脈寬有變化標志位
uint16 ServoTime = 2000;
/***********************************************************
* 名 稱: DelayMs(uint16 ms)
* 功 能: 延時ms毫秒
* 入口參數: ms 毫秒
* 出口參數: 無
* 說 明:
/**********************************************************/
void DelayMs(uint16 ms)
{
uint16 i,j;
for(i=0;i<85;i++) //89單片機用85,12系列單片機用800
for(j=0;j<ms;j++);
}
/***********************************************************
* 名 稱:InitTimer0()
* 功 能:時鐘0初始化
* 入口參數:無
* 出口參數:無
* 說 明:12M晶振,12分頻,所以計數器每遞增一個數就是1微秒,完全滿足舵機控制的精度要求
因為定時器是TH0,TL0都要全部計數到0xFF后在計1個數就會產生中斷,所以要想產生
x毫秒的中斷,那么TH0,TL0就應該賦值(0xFFFF-x) 從這個值開始計數產生定時中斷
/**********************************************************/
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計數器賦值產生定時中斷
* 入口參數:pwm 控制舵機的PWM脈沖寬度值(范圍:500~2500)
* 出口參數:無
* 說 明:12M晶振,12分頻,所以計數器每遞增一個數就是1微秒,完全滿足舵機控制的精度要求
因為定時器是TH0,TL0都要全部計數到0xFF后在計1個數就會產生中斷,所以要想產生
pwm毫秒的中斷,那么TH0,TL0就應該賦值(0xFFFF-pwm) 從這個值開始計數產生定時中斷
/**********************************************************/
void Timer0Value(uint16 pwm)
{
uint16 value;
value=0xffff-pwm;
TR0 = 0;
TL0=value; //16位數據給8位數據賦值默認將16位數據的低八位直接賦給八位數據
TH0=value>>8; //將16位數據右移8位,也就是將高8位移到低八位,再賦值給8位數據
TR0 = 1;
}
/***********************************************************
* 名 稱: ServoPwmDutyCompare()
* 功 能: 脈寬變化比較及速度控制
* 入口參數: 無
* 出口參數: 無
* 說 明:
/**********************************************************/
void ServoPwmDutyCompare()
{
static uint16 ServoPwmDutyIncTimes; //需要遞增的次數
static bool ServoRunning = 0; //舵機正在以指定速度運動到指定的脈寬對應的位置
if(ServoRunning == 0 && ServoPwmDutyHaveChange)//停止運動并且脈寬發生變化時才進行計算
{
ServoPwmDutyHaveChange = 0;
ServoPwmDutyIncTimes = ServoTime/20;
if(ServoPwmDutySet > ServoPwmDuty)
{
ServoPwmDutyInc = ServoPwmDutySet - ServoPwmDuty;
ServoPwmDutyInc = -ServoPwmDutyInc;
}
else
{
ServoPwmDutyInc = ServoPwmDuty - ServoPwmDutySet;
}
ServoPwmDutyInc /= ServoPwmDutyIncTimes;//每次遞增的脈寬
ServoRunning = 1; //舵機開始動作
}
if(ServoRunning)
{
ServoPwmDutyIncTimes--;
if(ServoPwmDutyIncTimes == 0)
{ //最后一次遞增就直接將設定值賦給當前值
ServoPwmDuty = ServoPwmDutySet;
ServoRunning = 0; //到達設定位置,舵機停止運動
}
else
{
ServoPwmDuty = ServoPwmDutySet +
(signed short int)(ServoPwmDutyInc * ServoPwmDutyIncTimes);
}
}
}
/***********************************************************
* 名 稱: main()
* 功 能: 入口函數
* 入口參數: 無
* 出口參數: 無
* 說 明:
/**********************************************************/
void main(void)
{
uint16 Time;
InitTimer0(); //定時器0初始化
EA = 1; //開總中斷
while(1) //大循環
{
if(Flag_20ms)
{
Time++;
Flag_20ms = 0;
ServoPwmDutyCompare();
}
if(Time > 110)
{
Time = 0;
LED = ~LED;
if(ServoPwmDutySet == 500)
{
ServoPwmDutySet = 2500; //脈沖寬度在2500微秒,對應90°
}
else
{
ServoPwmDutySet = 500; //脈沖寬度在500微秒,對應-90°
}
ServoPwmDutyHaveChange = 1;
}
}
}
/***********************************************************
* 名 稱: Timer0_isr() interrupt 1 using 1
* 功 能: 時鐘0中斷處理
* 入口參數: 無
* 出口參數: 無
* 說 明:
/**********************************************************/
void Timer0_isr(void) interrupt 1 using 1
{
static uint16 i = 1; //靜態變量:每次調用函數時保持上一次所賦的值,
//跟全局變量類似,不同是它只能用于此函數內部
switch(i)
{
case 1:
SERVO0 = 1; //PWM控制腳高電平
//給定時器0賦值,計數Pwm0Duty個脈沖后產生中斷,下次中斷會進入下一個case語句
Timer0Value(ServoPwmDuty);
Flag_20ms = 1;
break;
case 2:
SERVO0 = 0; //PWM控制腳低電平
//高脈沖結束后剩下的時間(20000-Pwm0Duty)全是低電平了,Pwm0Duty + (20000-Pwm0Duty) = 20000個脈沖正好為一個周期20毫秒
Timer0Value(20000-ServoPwmDuty);
i = 0;
break;
}
i++;
}
復制代碼
所有資料51hei提供下載:
STC單片機舵機PWM控制教程.zip
(284.19 KB, 下載次數: 113)
2019-12-21 20:27 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
作者:
你消失的蹤跡
時間:
2019-12-21 22:05
求詳細控制多舵機程序
作者:
yang305228226
時間:
2020-2-24 15:47
看看,多謝分享!!!!
作者:
yang305228226
時間:
2020-2-24 15:48
多謝分享!!!!!!!!!!!
作者:
y123chiang
時間:
2020-2-26 19:28
謝謝大大無私分享.....
作者:
快樂眼淚
時間:
2020-2-27 07:44
正在學習,謝謝樓主無私奉獻!
作者:
獨行者stc
時間:
2020-2-27 10:54
要是能用在機器狗上面多好啊!謝謝樓主分享。
作者:
你消失的蹤跡
時間:
2020-3-8 08:13
感謝樓主分享
作者:
gdatgb
時間:
2020-6-3 16:21
看看,多謝分享!!!
作者:
nhwhg
時間:
2020-6-5 15:33
學習中,感謝樓主無私奉獻!
歡迎光臨 (http://m.raoushi.com/bbs/)
Powered by Discuz! X3.1