89c52单片机不能用串口控制Pwm方波的占空比

2019-07-15 18:23发布

本帖最后由 asiavikin 于 2014-10-7 22:20 编辑

各位大能:

我想编写一个89c52下控制舵机运行的c程序,实现从串口逐次控制pwm方波占空比的功能。比如,从串口向单片机发送一次ff010aff后,方波的宽度就增大一点;发送多次ff010aff后,方波的宽度就可以增大到最多2毫秒。如果发送ff010bff,方波宽度就应该减小,发送多次ff010bff后,方波的宽度就可以减小到最少0.5毫秒。
我在网上找到了一个程序,把它修改了一下后用proteus仿真,但我发现并不能象我想的那样逐次控制pwm方波:从串口输出了命令ff010aff后,方波的宽度一下就变到2毫秒了,从串口输出了命令ff010bff后,方波的宽度一下就变到0.5毫秒了。
我想请教各位大能,为什么我的程序不能象一些51的按键控制程序那样逐次地控制pwm方波的宽度?如何修改才能达到目的呢?请各位不吝赐教。
下面是我的程序:附件里是我的proteus仿真文件。

#include<reg52.h>
#include<math.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
uchar Buffer =0;      //从串口接收的数据
uint i=0,j,URTAReceivedCount=0,n=1;
uchar flag=0;
uchar data Tempdatatable[4],CommandDatatable[4];//数据包
sbit servo0=P0^0;

uchar serVal[2];
uint pwm[]={1382,1382,1382,1382,1382,1382,1382,1382}; //初始90度,(实际是1382.4,取整得1382)
uchar pwm_flag=0;
uint code ms0_5Con=461; //0.5ms计数 (实际是460.8,取整得461)
uint code ms2_5Con=2304; //2.5ms计数

/********************************************************************
* 名称 : Delay_1ms()
* 功能 : 延时子程序,延时时间为 1ms * x
* 输入 : x (延时一毫秒的个数)
* 输出 : 无
***********************************************************************/
void Delay_1ms(uint i)//1ms延时
{
uchar x,j;
for(j=0;j<i;j++)
for(x=0;x<=148;x++);
}

/********************************************************************
* 名称 : Send_Data()
* 功能 : 向上位机传送字符
* 输入 : 无
* 输出 : 无
***********************************************************************/
void Send_Data(uchar data type,uchar data cmd)
{
  uchar data Buffer[4];
     //构建数据包
      uchar *p;
   uint Send_Count=0;
      p = Buffer;
   Buffer[0]=0XFF;
   Buffer[1]=type;
   Buffer[2]=cmd;
   Buffer[3]=0XFF;
     
  while(1){
     if(*p==0XFF){
     Send_Count++;  //0XFF标志统计位
   }
   SBUF = *p;  //发送
   while(!ti)  //如果发送完毕,硬件会置位TI,等待发送完毕
   {
     _nop_();
    }
   p++;
  
   TI = 0;
   if(Send_Count == 2)  //当统计到两次出现0XFF,则认为一个数据包发送完毕,跳出循环
   {
      TI = 0;
        break;
   }  
  }
}
/********************************************************************
* 名称 : Com_Int()
* 功能 : 串口中断子函数
* 输入 : 无
* 输出 : 无
***********************************************************************/
void Com_Int(void) interrupt 4
{
uchar temp;
ES=0; //关串口中断
    RI=0; //软件清除接收中断
temp=SBUF;
   if(temp==0XFF && URTAReceivedCount<2)
  {
   
  Tempdatatable[0]==0XFF;  //包头
  URTAReceivedCount++;
  }
  else
  {
     Tempdatatable[n]=temp;
   n++;   
  }
  if(URTAReceivedCount==2)//包尾
  {
     Tempdatatable[0]=0XFF;
     Tempdatatable[3]=0XFF;
   n=1;
     URTAReceivedCount=0;  //组包完毕
   temp="";
  //Send_Data(Tempdatatable[1],Tempdatatable[2]);  //发送组成的数据包回去
  }
  CommandDatatable[0]=Tempdatatable[0];
  CommandDatatable[1]=Tempdatatable[1];
  CommandDatatable[2]=Tempdatatable[2];
  CommandDatatable[3]=Tempdatatable[3];
  ES=1;//开串口中断
}
/********************************************************************
* 名称 : Com_Init()
* 功能 : 串口初始化,晶振11.0592,波特率9600,使能了串口中断
* 输入 : 无
* 输出 : 无
***********************************************************************/
void Com_Init(void)
{
     TMOD |= 0x20;
     PCON = 0x00;
     SCON = 0x50;   
     TH1 = 0xFd;    //设置波特率 9600
     TL1 = 0xFd;
     TR1 = 1;  //启动定时器1
  
   ES = 1;  //开串口中断
  EA = 1;  //开总中断
  IT0=0;
  EX0=1;
}

/********************************************************************
* 功能 : 舵机PWM中断初始化
***********************************************************************/
void Timer0Init() {
//0度=0.5ms, 45度=1ms, 90度=1.5ms, 135度=2ms, 180度=2.5ms
//2.5 ms初始值 F700, (12n/11059200=2.5/1000, n=2304, X=65536-2304=63232 > F700)  
TMOD |= 0x01;  //使用模式1,16位定时器,使用"|"符号可以在使用多个定时器时不受影响
TH0=-ms2_5Con>>8;      //给定初值,17ms中断
TL0=-ms2_5Con;
EA=1;            //总中断打开
ET0=1;           //定时器0中断打开
TR0=1;           //定时器0开关打开                                   
}

/********************************************************************
* 功能 : 舵机PWM中断, //舵机控制函数 周期为20ms 一个循环20MS  = 8*2.5ms
***********************************************************************/
void SteeringGear() interrupt 1 {
    switch(pwm_flag)
    {
        case 1:  
   servo0=1;
   TH0=-pwm[0]>>8;
   TL0=-pwm[0];
   break;
        case 2:  
   servo0=0;
   TH0=-(ms2_5Con-pwm[0])>>8;
   TL0=-(ms2_5Con-pwm[0]);
   break;
  //...
  default:
   TH0=0xff;
   TL0=0x80;
   pwm_flag=0;         
  }
    pwm_flag++;
}

void SteeringGearUp(uchar i) {
    if(pwm>ms0_5Con)
  pwm=pwm-10;
}

void SteeringGearDown(uchar i) {
    if(pwm<ms2_5Con)
  pwm=pwm+10;
}

void main()
{   
  
    Delay_1ms(200);
    Com_Init();//串口初始化
    Timer0Init();//舵机初始化
   
  while(1)
  {
     if(CommandDatatable[0]==0XFF && CommandDatatable[3]==0XFF){

           switch (CommandDatatable[1])      //根据键值不同,执行不同的内容
           {
           case 0X01:    //类型位0X01,表明是舵机数据包,进入舵机case  
          switch(CommandDatatable[2]) {
             case 0X0A:
        SteeringGearUp(0);
                  break;
             case 0X0B:
         SteeringGearDown(0);
         break;
           }
           break;
       default :  TR0=0;TR2=0;
              break;
      }
    }
  }
}


drivertest01截图00.png
driverictest01.rar 下载积分: 积分 -1 分
26.89 KB, 下载次数: 41, 下载积分: 积分 -1 分
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
5条回答
发烧友之麒麟
1楼-- · 2019-07-15 22:21
 精彩回答 2  元偷偷看……
阿信509
2楼-- · 2019-07-16 03:35
在你的主程序中,当收到串口数据后进行处理,处理后要把CommandDatatable清零呀!
要不你就收到一次,但是你会处理若干次,直到升到最大值或降到最小值
你想想看...
asiavikin
3楼-- · 2019-07-16 07:51
太感谢了!我太粗心了。
asiavikin
4楼-- · 2019-07-16 10:59
此贴可以锁了。
vvdv123
5楼-- · 2019-07-16 14:30

谢谢分享,楼主真是好人啊啊啊 啊啊

一周热门 更多>