单片机源程序如下:
/*****************************************************************************
** 文件: main.c
** 作者: Zheng23
** 日期:
** 功能:产生8路PWM输出控制8路舵机,方法:将20毫秒分成8个2500微秒,
即8个单元,先计算出第一个单元的舵机PWM控制线的脉冲宽度,因
为控制舵机的脉冲宽度最大为2500微秒,剩余的(20000 - 2500)
毫秒就是剩下的7个单元时间,第一个单元的舵机PWM控制线全部为
低电平了,这时就可以安心的处理剩下的7个单元的事情了,同理
第二个单元也是一样,这样循环下去就可以控制8路PWM输出了。
/*****************************************************************************/
//#include
//#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
}
/***********************************************************
* 名 称: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] = -ServoPwmDu
『本文转载自网络,版权归原作者所有,如有侵权请联系删除』