找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 19496|回复: 18
打印 上一主题 下一主题
收起左侧

关于51单片机输出频率和占空比可调的PWM波程序问题

  [复制链接]
跳转到指定楼层
楼主
前日看到一篇很好的代码。有好代码就要拿出来与坛友分享嘛
程序可以利用51单片机输出频率和占空比可调的PWM波程序。作者写的很详细,程序写的很漂亮!!!但我还是有地方不明白
现在咱们大家来探讨探讨吧!!!


我有三个问题,恳求网友不吝赐教。
1.  频率计算函数,当频率变化,计算出定时器0初值;      
2.  脉宽计算函数,脉宽变化时,计算出定时器1初值;
3.  关定时器1,一定要这一步,因为定时器1的定时短于定时器0;


  1. <div>//------------------------------------------------------------------------------------
  2. //程序功能简介:本程序产生15HZ~~~50KHZ的方波,并且实现频率和脉宽的独立调制,即可
  3. //在改变频率的同时不改变脉宽,再改变脉宽的同时不改变频率;同时设置
  4. //两个调节步长------在KEY键按下时,粗调,没有按下时,细调;
  5. //程序思路: 本程序用到两个定时器------定时器0和定时器1,其中定时器0工作在定时方式下,
  6. //决定方波的频率;定时器1,同样工作在定时方式下,用于设定脉宽;
  7. //------------------------------------------------------------------------------------ </div><div>
  8. </div><div> #include <reg52.h>
  9. #include <math.h></div><div>
  10. </div><div> #define  uchar unsigned char
  11. #define  uint unsigned int
  12. #define  ALL  65536                              //定时器工作方式1时,最大基数长度 65536;
  13. #define  F_osc 12000000                       //晶振频率12M;</div><div>
  14. </div><div> sbit KEY_F_UP=P0^2;                       //频率上调按钮;
  15. sbit KEY_F_DOWN=P0^3;                  //频率下调按钮;
  16. sbit KEY_W_UP=P0^4;                     //脉宽上调按钮;
  17. sbit KEY_W_DOWN=P0^5;                //脉宽下调按钮;
  18. sbit KEY=P0^6;                               //粗细调节按钮-----按下为粗调,否则为细调;
  19. sbit OUTPUT=P1^0;                         //波形输出;</div><div>
  20. </div><div> uchar TIMER0_H,TIMER0_L,TIMER1_H,TIMER1_L;         //定时器0和定时器1的初值设置;
  21. uchar PERCENT=50;                                                    //初始占空比;
  22. uchar FLAG_F=0,FLAG_W=0;                                      //频率调节标志和脉宽调制标志;
  23. uint  FREQ=50000;                                                     //初始频率;
  24. float temp;                                                                 //临时全局变量,用于数据传递;</div><div>
  25. </div><div> void delay(uchar t);         //延时函数,用于按键去抖;
  26. void init();                      //初始化函数,用于定时器的初始化;
  27. void calculate_F();          //<font style="background-color: red;">频率计算函数,当频率变化,计算出定时器0初值;</font>
  28. void calculate_W();         //<font style="background-color: red;">脉宽计算函数,脉宽变化时,计算出定时器1初值;</font>
  29. void key_scan();             //按键扫描函数;
  30. void timer0();                //定时器0中断函数;
  31. void timer1();                //定时器1中断函数;</div><div>
  32. </div><div> void delay(uchar t)
  33. {
  34.     uchar i,j;</div><div>
  35. </div><div>    while(t--)             //每个脉冲为1us
  36.      {
  37.       for(i=0;i<100;i++)
  38.        for(j=0;j<100;j++);
  39.      }
  40.   }</div><div>
  41. </div><div> void calculate_F()
  42. {
  43.    <font color="red"> temp = ALL - F_osc/12.0/FREQ;</font></div><div>
  44. </div><div>    TIMER0_H = (uint)temp/256;
  45.     TIMER0_L = (uint)temp%256;
  46. }</div><div>
  47. </div><div> void calculate_W()
  48. {
  49.     float TEMP;</div><div>
  50. </div><div>    <font color="red">TEMP = (1 - PERCENT/100.0)*ALL + temp*PERCENT/100.0;</font></div><div>
  51. </div><div>    TIMER1_H = (uint)TEMP/256;
  52.     TIMER1_L = (uint)TEMP%256;
  53.   }</div><div>
  54. </div><div>  void key_scan()
  55.   {
  56.     delay(4);</div><div>
  57. </div><div>    if(!KEY_F_UP)     //频率上调键按下;
  58.     {
  59.       FLAG_F=1;    //置标志位;</div><div>
  60. </div><div>      if(!KEY)
  61.         FREQ+=10;</div><div>
  62. </div><div>      else
  63.         FREQ++;</div><div>
  64. </div><div>      if(FREQ>50000)
  65.         FREQ=1;
  66.     }</div><div>
  67. </div><div>    else if(!KEY_F_DOWN)   //频率下调键按下;
  68.     {
  69.       FLAG_F=1;    //置标志位;</div><div>
  70. </div><div>      if(!KEY)
  71.         FREQ-=10;</div><div>
  72. </div><div>      else
  73.         FREQ--;</div><div>
  74. </div><div>      if(FREQ<1)
  75.         FREQ=50000;
  76.      }</div><div>
  77. </div><div>     else if(!KEY_W_UP)    //脉宽上调键按下;
  78.      {
  79.        FLAG_W=1;    //置标志位;</div><div>
  80. </div><div>       if(!KEY)
  81.          PERCENT+=5;</div><div>
  82. </div><div>       else
  83.          PERCENT++;</div><div>
  84. </div><div>       if(PERCENT>49)
  85.          PERCENT=1;
  86.       }</div><div>
  87. </div><div>     else if(!KEY_W_DOWN)   //脉宽下调键按下;
  88.      {
  89.        FLAG_W=1;    //置标志位;</div><div>
  90. </div><div>       if(!KEY)
  91.          PERCENT-=5;</div><div>
  92. </div><div>       else
  93.          PERCENT--;</div><div>
  94. </div><div>       if(PERCENT<1)
  95.          PERCENT=49;
  96.       } </div><div>
  97. </div><div>      else ;</div><div>
  98. </div><div>      }</div><div>
  99. </div><div>  void timer0() interrupt 1      //决定频率
  100.    {
  101.      TH0=TIMER0_H;
  102.      TL0=TIMER0_L;
  103.      TR1=1;           //开定时器1;
  104.      OUTPUT=1;
  105.    }</div><div>
  106. </div><div>   void timer1() interrupt 3     //决定脉宽
  107.    {
  108.      TH1=TIMER1_H;
  109.      TL1=TIMER1_L;
  110.      TR1=0;         <font style="background-color: red;"> //关定时器1,一定要这一步,因为定时器1的定时短于定时器0;</font>
  111.      OUTPUT=0;
  112.    }</div><div>
  113. </div><div>   void init()
  114.    {
  115.      TMOD=0x11;      //定时器0和定时器1都工作在方式1,16位计数器;
  116.      calculate_F();  //初始为1KHZ,占空比为50%;
  117.      calculate_W();</div><div>
  118. </div><div>     TH0=TIMER0_H;
  119.      TL0=TIMER0_L;</div><div>
  120. </div><div>     TH1=TIMER1_H;
  121.      TL1=TIMER1_L;</div><div>
  122. </div><div>     ET0=1;
  123.      ET1=1;</div><div>
  124. </div><div>     EA=1;</div><div>
  125. </div><div>     TR0=1;
  126.      TR1=1;
  127.      
  128.    }</div><div>
  129. </div><div> main()
  130. {
  131.     init();</div><div>
  132. </div><div>    while(1)
  133.     {
  134.        key_scan();
  135.        if(FLAG_F)     //改变频率时要注意要进行脉宽的重新设置;
  136.        {
  137.          calculate_F();
  138.          calculate_W();
  139.          FLAG_F=0;
  140.        }</div><div>
  141. </div><div>       if(FLAG_W)     // 脉宽改变,频率不改变;
  142.        {
  143.          calculate_W();
  144.          FLAG_W=0;
  145.        }
  146.      }
  147. }
  148. </div>
复制代码



分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏3 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:140769 发表于 2016-10-26 22:01 | 只看该作者
不知为什么显示的这么乱呢?
回复

使用道具 举报

板凳
ID:39386 发表于 2016-10-29 07:39 | 只看该作者
请重新上传吧。想看看!
回复

使用道具 举报

地板
ID:88606 发表于 2017-5-5 15:21 | 只看该作者
//------------------------------------------------------------------------------------
//程序功能简介:本程序产生15HZ~~~50KHZ的方波,并且实现频率和脉宽的独立调制,即可
//在改变频率的同时不改变脉宽,再改变脉宽的同时不改变频率;同时设置
//两个调节步长------在KEY键按下时,粗调,没有按下时,细调;
//程序思路: 本程序用到两个定时器------定时器0和定时器1,其中定时器0工作在定时方式下,
//决定方波的频率;定时器1,同样工作在定时方式下,用于设定脉宽;
//------------------------------------------------------------------------------------
  #include <reg52.h>
#include <math.h>
#define  uchar unsigned char
#define  uint unsigned int
#define  ALL  65536             //定时器工作方式1时,最大基数长度 65536;
#define  F_osc 12000000         //晶振频率12M;

sbit KEY_F_UP=P0^2;             //频率上调按钮;
sbit KEY_F_DOWN=P0^3;           //频率下调按钮;
sbit KEY_W_UP=P0^4;             //脉宽上调按钮;
sbit KEY_W_DOWN=P0^5;           //脉宽下调按钮;
sbit KEY=P0^6;                  //粗细调节按钮-----按下为粗调,否则为细调;
sbit OUTPUT=P1^0;               //波形输出;

uchar TIMER0_H,TIMER0_L,TIMER1_H,TIMER1_L;//定时器0和定时器1的初值设置;
uchar PERCENT=50;               //初始占空比;
uchar FLAG_F=0,FLAG_W=0;//频率调节标志和脉宽调制标志;
uint  FREQ=50000;               //初始频率;
float temp;                     //临时全局变量,用于数据传递;
void delay(uchar t);           //延时函数,用于按键去抖;
void init();                      //初始化函数,用于定时器的初始化;
void calculate_F();     
//频率计算函数,当频率变化,计算出定时器0初值;
void calculate_W();     
//脉宽计算函数,脉宽变化时,计算出定时器1初值;
void key_scan();             //按键扫描函数;
void timer0();                //定时器0中断函数;
void timer1();                //定时器1中断函数;
void delay(uchar t)
{
    uchar i,j;
    while(t--)             //每个脉冲为1us
     {
      for(i=0;i<100;i++)
       for(j=0;j<100;j++);
     }
  }
void calculate_F()
{
    TIMER0_H = (uint)temp/256;
    TIMER0_L = (uint)temp%256;
}
void calculate_W()
{
    float TEMP;
    TEMP = (1 - PERCENT/100.0)*ALL + temp*PERCENT/100.0;
    TIMER1_H = (uint)TEMP/256;
    TIMER1_L = (uint)TEMP%256;
  }
  void key_scan()
  {
    delay(4);
    if(!KEY_F_UP)     //频率上调键按下;
    {
      FLAG_F=1;    //置标志位;
      if(!KEY)
        FREQ+=10;
      else
        FREQ++;
      if(FREQ>50000)
        FREQ=1;
    }
    else if(!KEY_F_DOWN)   //频率下调键按下;
    {
      FLAG_F=1;    //置标志位;
      if(!KEY)
        FREQ-=10;
      else
        FREQ--;
      if(FREQ<1)
        FREQ=50000;
     }
     else if(!KEY_W_UP)    //脉宽上调键按下;
     {
       FLAG_W=1;    //置标志位;
       if(!KEY)
         PERCENT+=5;
       else
         PERCENT++;
       if(PERCENT>49)
         PERCENT=1;
      }
     else if(!KEY_W_DOWN)   //脉宽下调键按下;
     {
       FLAG_W=1;    //置标志位;
       if(!KEY)
         PERCENT-=5;
       else
         PERCENT--;
       if(PERCENT<1)
         PERCENT=49;
      }
      else ;
      }
  void timer0() interrupt 1      //决定频率
   {
     TH0=TIMER0_H;
     TL0=TIMER0_L;
     TR1=1;           //开定时器1;
     OUTPUT=1;
   }
   void timer1() interrupt 3     //决定脉宽
   {
     TH1=TIMER1_H;
     TL1=TIMER1_L;
     TR1=0; //关定时器1,一定要这一步,因为定时器1的定时短于定时器0;
     OUTPUT=0;
   }
   void init()
   {
     TMOD=0x11;      //定时器0和定时器1都工作在方式1,16位计数器;
     calculate_F();  //初始为1KHZ,占空比为50%;
     calculate_W();
     TH0=TIMER0_H;
     TL0=TIMER0_L;
     TH1=TIMER1_H;
     TL1=TIMER1_L;
     ET0=1;
     ET1=1;
     EA=1;
     TR0=1;
     TR1=1;
     
   }
main()
{
    init();
    while(1)
    {
       key_scan();
       if(FLAG_F)     //改变频率时要注意要进行脉宽的重新设置;
       {
         calculate_F();
         calculate_W();
         FLAG_F=0;
       }
       if(FLAG_W)     // 脉宽改变,频率不改变;
       {
         calculate_W();
         FLAG_W=0;
       }
     }
}
回复

使用道具 举报

5#
ID:203412 发表于 2017-5-22 11:30 | 只看该作者
有proteus 仿真图吗
回复

使用道具 举报

6#
ID:153136 发表于 2018-4-14 20:16 | 只看该作者
我试了一下,没办法实现频率的改变
回复

使用道具 举报

7#
ID:153136 发表于 2018-4-14 20:48 | 只看该作者
对比截图中两个函数,我自己测试了,频率无法改变,可能跟程序中根据频率计算计时器初始值的函数没写好有关。

QQ截图20180414204620.png (11.55 KB, 下载次数: 78)

QQ截图20180414204620.png

QQ截图20180414204631.png (20.19 KB, 下载次数: 68)

QQ截图20180414204631.png
回复

使用道具 举报

8#
ID:300215 发表于 2018-4-14 21:23 | 只看该作者
//------------------------------------------------------------------------------------ //程序功能简介:本程序产生15HZ~~~50KHZ的方波,并且实现频率和脉宽的独立调制,即可 //在改变频率的同时不改变脉宽,再改变脉宽的同时不改变频率;同时设置 //两个调节步长------在KEY键按下时,粗调,没有按下时,细调; //程序思路: 本程序用到两个定时器------定时器0和定时器1,其中定时器0工作在定时方式下, //决定方波的频率;定时器1,同样工作在定时方式下,用于设定脉宽; //------------------------------------------------------------------------------------    #include <reg52.h> #include <math.h> #define  uchar unsigned char #define  uint unsigned int #define  ALL  65536             //定时器工作方式1时,最大基数长度 65536; #define  F_osc 12000000         //晶振频率12M;  sbit KEY_F_UP=P0^2;             //频率上调按钮; sbit KEY_F_DOWN=P0^3;           //频率下调按钮; sbit KEY_W_UP=P0^4;             //脉宽上调按钮; sbit KEY_W_DOWN=P0^5;           //脉宽下调按钮; sbit KEY=P0^6;                  //粗细调节按钮-----按下为粗调,否则为细调; sbit OUTPUT=P1^0;               //波形输出;  uchar TIMER0_H,TIMER0_L,TIMER1_H,TIMER1_L;//定时器0和定时器1的初值设置; uchar PERCENT=50;               //初始占空比; uchar FLAG_F=0,FLAG_W=0;//频率调节标志和脉宽调制标志; uint  FREQ=50000;               //初始频率; float temp;                     //临时全局变量,用于数据传递; void delay(uchar t);           //延时函数,用于按键去抖; void init();                      //初始化函数,用于定时器的初始化; void calculate_F();      //频率计算函数,当频率变化,计算出定时器0初值; void calculate_W();      //脉宽计算函数,脉宽变化时,计算出定时器1初值; void key_scan();             //按键扫描函数; void timer0();                //定时器0中断函数; void timer1();                //定时器1中断函数; void delay(uchar t) {     uchar i,j;     while(t--)             //每个脉冲为1us      {       for(i=0;i<100;i++)        for(j=0;j<100;j++);      }   } void calculate_F() {     TIMER0_H = (uint)temp/256;     TIMER0_L = (uint)temp%256; } void calculate_W() {     float TEMP;     TEMP = (1 - PERCENT/100.0)*ALL + temp*PERCENT/100.0;     TIMER1_H = (uint)TEMP/256;     TIMER1_L = (uint)TEMP%256;   }   void key_scan()   {     delay(4);     if(!KEY_F_UP)     //频率上调键按下;     {       FLAG_F=1;    //置标志位;       if(!KEY)         FREQ+=10;       else         FREQ++;       if(FREQ>50000)         FREQ=1;     }     else if(!KEY_F_DOWN)   //频率下调键按下;     {       FLAG_F=1;    //置标志位;       if(!KEY)         FREQ-=10;       else         FREQ--;       if(FREQ<1)         FREQ=50000;      }      else if(!KEY_W_UP)    //脉宽上调键按下;      {        FLAG_W=1;    //置标志位;        if(!KEY)          PERCENT+=5;        else          PERCENT++;        if(PERCENT>49)          PERCENT=1;       }      else if(!KEY_W_DOWN)   //脉宽下调键按下;      {        FLAG_W=1;    //置标志位;        if(!KEY)          PERCENT-=5;        else          PERCENT--;        if(PERCENT<1)          PERCENT=49;       }        else ;       }   void timer0() interrupt 1      //决定频率    {      TH0=TIMER0_H;      TL0=TIMER0_L;      TR1=1;           //开定时器1;      OUTPUT=1;    }    void timer1() interrupt 3     //决定脉宽    {      TH1=TIMER1_H;      TL1=TIMER1_L;      TR1=0; //关定时器1,一定要这一步,因为定时器1的定时短于定时器0;      OUTPUT=0;    }    void init()    {      TMOD=0x11;      //定时器0和定时器1都工作在方式1,16位计数器;      calculate_F();  //初始为1KHZ,占空比为50%;      calculate_W();      TH0=TIMER0_H;      TL0=TIMER0_L;      TH1=TIMER1_H;      TL1=TIMER1_L;      ET0=1;      ET1=1;      EA=1;      TR0=1;      TR1=1;          } main() {     init();     while(1)     {        key_scan();        if(FLAG_F)     //改变频率时要注意要进行脉宽的重新设置;        {          calculate_F();          calculate_W();          FLAG_F=0;        }        if(FLAG_W)     // 脉宽改变,频率不改变;        {          calculate_W();          FLAG_W=0;        }      } }
回复

使用道具 举报

9#
ID:153136 发表于 2018-4-18 09:56 | 只看该作者
林木 发表于 2018-4-14 20:48
对比截图中两个函数,我自己测试了,频率无法改变,可能跟程序中根据频率计算计时器初始值的函数没写好有关 ...

若想实现频率改变,调频代码应这样修改

QQ截图20180418095602.jpg (22.11 KB, 下载次数: 72)

QQ截图20180418095602.jpg
回复

使用道具 举报

10#
ID:242952 发表于 2018-4-24 12:26 | 只看该作者
楼主解决了吗
回复

使用道具 举报

11#
ID:372402 发表于 2018-9-1 13:06 | 只看该作者
林木 发表于 2018-4-18 09:56
若想实现频率改变,调频代码应这样修改

试了你这个也不行啊~
回复

使用道具 举报

12#
ID:470545 发表于 2019-1-19 15:27 | 只看该作者
林木 发表于 2018-4-14 20:48
对比截图中两个函数,我自己测试了,频率无法改变,可能跟程序中根据频率计算计时器初始值的函数没写好有关 ...

把 P0^6 脚接地,频率可以实现增加,但是占空比和频率都无法减
回复

使用道具 举报

13#
ID:837631 发表于 2021-9-6 13:46 | 只看该作者
有大侠解决了频率改变的问题吗?
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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