单片机学习小组
直播中

h1654155275.5748

7年用户 877经验值
私信 关注

stc15系列T0和T2同时使用,PWM输出没有变化

用T0解码红外键码一切正常,用T2单独软件模拟PWM输出也是正常(用两个按键控制占空大小也是正常的),但是将两段代码结合后PWM输出就没有变化了,红外解码一切正常,请教高手
完整代码如下:
#include       //包含单片机寄存器的头文件
//#define byte unsigned char
//#define word unsigned int
#define     MAIN_Fosc       24000000UL      //定义主时钟
#define     PWM_DUTY        6000            //定义PWM的周期,数值为时钟周期数,假如使用24.576MHZ的主频,则PWM频率为6000HZ。
#define     PWM_HIGH_MIN    32              //限制PWM输出的最小占空比。用户请勿修改。
#define     PWM_HIGH_MAX    (PWM_DUTY-PWM_HIGH_MIN) //限制PWM输出的最大占空比。用户请勿修改。
typedef     unsigned char   u8;
typedef     unsigned int    u16;
typedef     unsigned long   u32;
sfr TL2   = 0xD7;
sfr TH2   = 0xD6;
sfr IE2   = 0xAF;   //STC12C5A60S2系列
sfr P3M1  = 0xB1;   //P3M1.n,P3M0.n     =00--->Standard,    01--->push-pull
sfr P3M0  = 0xB2;   //                  =10--->pure input,  11--->open drain
sfr AUXR  = 0x8E;
sfr INT_CLKO = 0x8F;
***it    P_PWM = P3^0;       //定义PWM输出引脚。
***it IR=P3^2;           //将IR 位定义为 P3.2引脚
//***it P30=P3^0;
***it P33=P3^3;
***it P31=P3^1;
***it P34=P3^4;
***it P35=P3^5;
bit k1,k2;
u8 a[4];    //储存用户码、用户反码与键数据码、键数据反码
u16 Lowtime,HighTime; //储存高、低电平的宽度
u16     pwm;                //定义PWM输出高电平的时间的变量。用户操作PWM的变量。
u16     PWM_high,PWM_low;   //中间变量,用户请勿修改。
void    delay_ms(u8 ms);
void    LoadPWM(u16 i);
/************************************************************
函数功能:reset
*************************************************************/
void reset(void)
{
  P33=1;
  P31=1;
  P34=1;
  P35=1;   
}
/************************************************************
函数功能:delay
*************************************************************/
void delay(u8 n)
{
    u16 x;
    while (n--)
    {
        x = 0;
        while (++x);
    }
}
/************************************************************
函数功能:对 4个字节的用户码和键数据码进行解码
说明:解码正确,返回 1,否则返回 0
出口参数:dat
*************************************************************/
bit DeCode(void)         
{
   u8  i,j;
  u8 temp;    //储存解码出的数据
  for(i=0;i<4;i++)      //连续读取4 个用户码和键数据码
    {
     for(j=0;j<8;j++)  //每个码有 8 位数字
       {
           temp=temp>>1;  //temp 中的各数据位右移一位,因为先读出的是高位数据         
         TH0=0;         //定时器清 0
         TL0=0;         //定时器清 0
         TR0=1;         //开启定时器 T0
          while(IR==0)   //如果是低电平就等待
                 ;        //低电平计时
           TR0=0;         //关闭定时器 T0
         LowTime=TH0*256+TL0;    //保存低电平宽度
         TH0=0;         //定时器清 0
         TL0=0;         //定时器清 0
         TR0=1;         //开启定时器 T0
         while(IR==1)   //如果是高电平就等待
             ;         
         TR0=0;        //关闭定时器 T0
         HighTime=TH0*256+TL0;   //保存高电平宽度
         if((LowTime<370)||(LowTime>640))
                return 0;        //如果低电平长度不在合理范围,则认为出错,停止解码  
         if((HighTime>420)&&(HighTime<620))   //如果高电平时间在560微秒左右,即计数560/1次
                 temp=temp&0x7f;       //(520-100=420, 520+100=620),则该位是 0
         if((HighTime>1300)&&(HighTime<1800)) //如果高电平时间在 1680微秒左右,即计数 1680 1.085=1548 次
                                  temp=temp|0x80;       //(1550-250=1300,1550+250=1800),则该位是 1
         }                     
     a=temp;  //将解码出的字节值储存在 a                     
    }               
  if(a[2]=~a[3])  //验证键数据码和其反码是否相等,一般情况下不必验证用户码
   return 1;     //解码正确,返回 1
}
/************************************************************
函数功能:执行遥控功能
*************************************************************/
void Function(void)
{
  //EA=0;
  if(a[2]==0xEE)
  {
      //k1=0;
          //delay(15);
      //while(pwm < (PWM_HIGH_MAX-8)&&k1==0)
          //{  
                 pwm += 16;       //PWM逐渐加到最大
         LoadPWM(pwm);
         delay_ms(2);
                 //}
                // k1=1;
  }
  if(a[2]==0x99)
  {
           //k2=0;
         //delay(15);      
//        while(pwm > (PWM_HIGH_MAX-8)&&k2==0)
        //{               
                        pwm -= 16;   //PWM逐渐减到最小
            LoadPWM(pwm);
            delay_ms(2);
                //        }
                //        k2=1;   
  }
  if(a[2]==0xAA)
  {
  delay(2);
  P33=0;
  P31=1;
  P34=0;
  P35=1;
  delay(15);
  reset();  
  }
  if(a[2]==0xCC)
  {
  delay(2);
  P33=1;
  P31=0;
  P34=0;
  P35=1;
   delay(3);
   reset();  
  }
  if(a[2]==0x22)
  {
  delay(2);
  P33=0;
  P31=1;
  P34=1;
  P35=0;
   delay(3);
   reset();
  }
  if(a[2]==0x66)
  {
  delay(2);
  P33=1;
  P31=0;
  P34=1;
  P35=0;
   delay(15);
   reset();  
  }
//EA=1;  
}
/************************************************************
函数功能:主函数
*************************************************************/
void main()
{      
  EA=1;        //开启总中断
   EX0=1;       //开外中断 0
   ET0=1;       //定时器 T0中断允许
   IT0=1;       //外中断的下降沿触发   
  TMOD=0x01;   //使用定时器 T0的模式 1
  TR0=0;       //定时器T0 关闭
  P_PWM = 1;        
    P3M1 &= ~1; //P3.0 设置为推挽输出
    P3M0 |=  1;
    AUXR &= ~(1<<4);    //停止计数
    IE2  |=  (1<<2);    //允许中断
    AUXR |=  (1<<2);    //1T
    AUXR &= ~(1<<3);    //定时
    INT_CLKO |=  0x04;  //输出时钟
    TH2 = 0;
    TL2 = 0;
    AUXR |=  (1<<4);    //开始运行
    pwm = PWM_DUTY / 10;    //给PWM一个初值,这里为10%占空比
   //pwm = 32;
    LoadPWM(pwm);           //计算PWM重装值
   while(1)    //等待红外信号产生的中断
    ;      
}
//========================================================================
// 函数: void  delay_ms(u8 ms)
// 描述: 延时函数。
// 参数: ms,要延时的ms数, 这里只支持1~255ms. 自动适应主时钟.
// 返回: none.
// 版本: VER1.0
// 日期: 2013-4-1
// 备注:
//========================================================================
void  delay_ms(u8 ms)
{
     unsigned int i;
     do{
          i = MAIN_Fosc / 13000;
          while(--i)    ;
     }while(--ms);
}
/**************** 计算PWM重装值函数 *******************/
void    LoadPWM(u16 i)
{
    u16 j;
    if(i > PWM_HIGH_MAX)        i = PWM_HIGH_MAX;   //如果写入大于最大占空比数据,则强制为最大占空比。
    if(i < PWM_HIGH_MIN)        i = PWM_HIGH_MIN;   //如果写入小于最小占空比数据,则强制为最小占空比。
    j = 65536UL - PWM_DUTY + i; //计算PWM低电平时间
    i = 65536UL - i;            //计算PWM高电平时间
    EA = 0;
    PWM_high = i;   //装载PWM高电平时间
    PWM_low  = j;   //装载PWM低电平时间
    EA = 1;
}
/************************************************************
函数功能:红外线触发的外中断处理函数
*************************************************************/
void Int0(void) interrupt 0 using 0
  {
     EX0=0;      //关闭外中断 0,不再接收二次红外信号的中断,只解码当前红外信号
    TH0=0;      //定时器T0 的高 8位清 0
    TL0=0;      //定时器T0 的低 8位清 0
    TR0=1;      //开启定时器 T0   
    while(IR==0)          //如果是低电平就等待,给引导码低电平计时
         ;      
    TR0=0;                //关闭定时器T0      
    LowTime=TH0*256+TL0;  //保存低电平时间
    TH0=0;      //定时器T0 的高 8位清 0
    TL0=0;      //定时器T0 的低 8位清 0
    TR0=1;      //开启定时器 T0
    while(IR==1)  //如果是高电平就等待,给引导码高电平计时
      ;
    TR0=0;        //关闭定时器 T0
    HighTime=TH0*256+TL0; //保存引导码的高电平长度
     if((LowTime>7800)&&(LowTime<8800)&&(HighTime>3600)&&(HighTime<4700))
     {
        //如果是引导码,就开始解码,否则放弃,引导码的低电平计时
         //次数=9000us/1.085=8294, 判断区间:8300-500=7800,8300+500=8800.
         if(DeCode()==1)   
         Function();    //如果满足条件,执行遥控功能
                 //EA=0;
     }
    EX0=1;   //开启外中断 EX0
  }
/********************* Timer2中断函数************************/
void timer2_int (void) interrupt 12
{
    if(P_PWM)
    {        
            //P34=P_PWM ;
        TH2 = (u8)(PWM_low >> 8);   //如果是输出高电平,则装载低电平时间。
        TL2 = (u8)PWM_low;
    }
    else
    {
        //P34=P_PWM;
                TH2 = (u8)(PWM_high >> 8);  //如果是输出低电平,则装载高电平时间。
        TL2 = (u8)PWM_high;
    }
}

回帖(16)

李婷婷

2019-10-17 05:49:29
中断程序里面死等 高低电平,
你这是独占CPU资源的方式编程
只适合单任务教学使用.
实践中,不可取.
只可以完成解码任务,只他的事情都做不了.
举报

顾鸿兰

2019-10-17 05:55:02
两段代码结合后,原本想用0xEE和0x99控制占空比的大小,但是输出一直没有变化
这个程序本来想用来控制遥控小车的,之前没用PWM直接控制输出的话也可以完成小车的前进后退左转右转,但是启动停止惯性太大,所以想引入PWM加减速,结果研究了几天都无果
举报

付华一

2019-10-17 06:10:41
你解码程序有点问题.
你可以在论坛找一下我的一个红外解码程序.参考一下.
也是51的程序.
希望能对你有用.
举报

陈斌

2019-10-17 06:18:42
好的,谢谢,但是我的红外部分一直在正常使用,看有没有改进空间
举报

更多回帖

发帖
×
20
完善资料,
赚取积分