找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3713|回复: 10
收起左侧

51单片机用PMW做呼吸灯,灯却闪烁的很厉害

[复制链接]
ID:601140 发表于 2019-8-18 11:39 | 显示全部楼层 |阅读模式
新人发帖 如有不足 请各位批评指正~
本人想实现用PWM做一个呼吸灯 让灯暗-亮-暗地循环 但是实际效果是灯的亮度变化不明显 而且闪烁得很厉害 请各位帮忙看看我的程序哪里出了问题 谢谢各位!!
  1. #include<reg52.h>

  2. typedef unsigned int u16;
  3. typedef unsigned char u8;

  4. sbit LED=P0^0;

  5. bit output=1;

  6. u8 TRH_H,TRH_L,TRL_H,TRL_L;

  7. //这两个是沟通主程序和T1中断的
  8. u8 T1RL,T1RH;


  9. u8 freq;
  10. u16 Period;//一个信号周期所需要的机器周期数

  11. u8 index=0;
  12. u8 code Brightness[]={51, 54, 58, 62, 65, 69, 73, 77, 81, 86, 90, 93, 95};

  13. void SetTimer0();
  14. void SetTimer1(u16);
  15. void AdjustBrightness(u8);


  16. void main()
  17. {
  18.         

  19.    EA=1;
  20.    freq=100;
  21.    Period=12000000/(12*freq);//一个信号的周期也就是中断周期
  22.   
  23.    AdjustBrightness(Brightness[index]);

  24.    SetTimer0();
  25.    SetTimer1(50);

  26.    while(1);
  27. }

  28. void SetTimer0()
  29. {
  30.         ET0=1;
  31.         TMOD=(TMOD&0xF0)|0x01;
  32.         TR0=1;
  33.         TH0=TRH_H;
  34.         TL0=TRL_H;
  35. }



  36. void SetTimer1(u16 interval)
  37. {
  38.         u16 temp=0;//记录一个间隔=多少机器周期
  39.         temp=interval*1000;//这个间隔以毫秒为单位 而一个机器周期又为1us 正好是一千倍的关系        

  40.         T1RH=(unsigned char)((65536-temp)>>8);
  41.         T1RL=(unsigned char)(65536-temp);


  42.         TMOD &= 0x0F;   //清零T1的控制位
  43.     TMOD |= 0x10;   //配置T1为模式1         
  44.         TL1=T1RL;
  45.         TH1=T1RH;
  46.         ET1=1;
  47.         TR1=1;//打开定时器1的中断
  48. }

  49. void AdjustBrightness(u8 dr)//dr=占空比
  50. {
  51.         static u16 hightime,lowtime;//传送一个信号需要多少个机器周期
  52.         

  53.         //下面计算高电平和低电平所需要的时间
  54.         //并算出对应的TRL和TRH

  55.         hightime=Period*dr/100;
  56.         lowtime=Period-hightime;

  57.         TRH_H=(unsigned char)((65536-hightime)>>8);
  58.         TRL_H= (unsigned char)(65536-hightime);//注意这里只取了低八位 高八位溢出了

  59.         TRH_L=(unsigned char)((65536-lowtime)>>8);
  60.         TRL_L=(unsigned char)(65536-lowtime);

  61. }


  62. void InterruptTimer0()interrupt 1
  63. {
  64.         if(output==1)//如果此时输出的是高电平
  65.         {
  66.           LED=output;
  67.          
  68.           TH0=TRH_L;
  69.           TL0=TRL_L;
  70.                
  71.           output=0;
  72.         }

  73.         else if(output==0)//如果此时输出的是高电平
  74.         {
  75.           LED=output;
  76.          
  77.           TH0=TRH_H;
  78.           TL0=TRL_H;
  79.                
  80.           output=1;
  81.         }

  82. }

  83. void InterruptTimer1() interrupt 3
  84. {

  85.         static bit dir=0;//表示灯现在是往变大的方向变化还是往小的方向变化
  86.         TH1=T1RH; //重装
  87.         TL1=T1RL;


  88.         AdjustBrightness(Brightness[index]);

  89.         if(dir==0)
  90.         {
  91.                 index++;
  92.                 if(index>=12)
  93.                 {dir=1;}  
  94.             
  95.         }
  96.         else if(dir==1)
  97.         {
  98.                 index--;
  99.                 if(index==0)
  100.                 {dir=0;}
  101.         }
  102. }
复制代码




回复

使用道具 举报

ID:96682 发表于 2019-8-18 13:07 | 显示全部楼层
同一个程序使用不同型号的单片机会产生不同的视觉效果,不满意只能修改程序了
回复

使用道具 举报

ID:123289 发表于 2019-8-18 13:22 | 显示全部楼层
写出你的设计思路看看。
回复

使用道具 举报

ID:601140 发表于 2019-8-18 14:24 | 显示全部楼层
yzwzfyz 发表于 2019-8-18 13:22
写出你的设计思路看看。

设计思路是:定时器1定时切换占空比,也就是切换亮度  定时器0按照对应的占空比控制灯的亮灭  这些都在中断里面完成 主程序只是设定定时器的初值和频率之类的
回复

使用道具 举报

ID:601140 发表于 2019-8-18 14:26 | 显示全部楼层
wc86110 发表于 2019-8-18 13:07
同一个程序使用不同型号的单片机会产生不同的视觉效果,不满意只能修改程序了

单片机型号是STC89C516 应该不是单片机的问题 应该是我的程序本身有问题 可是不知道究竟是哪里不对呢...
回复

使用道具 举报

ID:598942 发表于 2019-8-18 20:44 | 显示全部楼层
可以把周期调长一点
回复

使用道具 举报

ID:388197 发表于 2019-8-18 23:37 | 显示全部楼层
现在新款的都有硬件的PWM,如果自己写软件的...也不用两个定时器,1个就足够了
比如10u一次的定时器T0中断.
u16 Cycle_Time = 100;         //这个数字乘以定时器中断时间就是周期.
u16 Duty          =  40;          //占空比.
u16 T0_Cnt =         0           //计数器变量,用以跟上面两个变量比较,决定输出电平.
sbit PWM_Out_Pin = Px^x;

void main()
{
    Init_XXX();                //IO输出模式之类的各种INIT.....
    ........
    ........
   Init_T0();                   //设置好定时器T0并使能.
    PWM_Out_Pin = 1;    // 将对应的IO口先拉高.
    while(1);
}
T0_ISR() interrupt 1    //10us
{
     TH0 = X;        //新款的51有16位自动重载,或者用8位的自动重载,这些就不用写了
     TL0 = X;
     T0_Cnt++;
     if(T0_Cnt<Duty)       //小于占空比则输出高.
    {
        PWM_IO_Pin = 1;
    }
    if(T0_Cnt >=Duty && T0_Cnt<Cycle_Time) //计数变量大于占空比了,当然要输出低.
   {
       PWM_IO_Pin = 0;
   }
   if(T0_Cnt >= Cycle_Time)   //如果计数变量超过周期时间了,就清0.下一个周期开始.
   {
      T0_Cnt = 0;
   }
}

你在MAIN的大循环里改变CYCLE_TIME   DUTY这两个变量,就可以实现周期,占空比的调整.
有段时间没写过51的程序了,不保证没BUG,参考参考就行.
回复

使用道具 举报

ID:299748 发表于 2019-8-19 00:38 | 显示全部楼层
增大频率试试
回复

使用道具 举报

ID:96857 发表于 2019-8-19 08:38 | 显示全部楼层
PWM调压要电流连续模式才与占空比成正比关系,你的闪烁与你的开关频率可能有关系。
回复

使用道具 举报

ID:601140 发表于 2019-8-19 09:30 | 显示全部楼层
cjm82 发表于 2019-8-18 23:37
现在新款的都有硬件的PWM,如果自己写软件的...也不用两个定时器,1个就足够了
比如10u一次的定时器T0中断.
...

非常感谢!!!我去试试!!!
回复

使用道具 举报

ID:601529 发表于 2019-8-19 11:44 | 显示全部楼层
哦  学到了,我去试试
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表