×
单片机 > 单片机程序设计 > 详情

STC单片机关于舵机pwm控制源程序(单个与多个速度控制都有)

发布时间:2020-08-25 发布时间:
|

单片机源程序如下:

/*****************************************************************************

** 文件: 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


『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多