找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1833|回复: 0
收起左侧

单片机使用两个定时器实现PWM(脉宽调制)呼吸灯源程序

[复制链接]
ID:832215 发表于 2020-10-24 18:56 | 显示全部楼层 |阅读模式
PWM(脉宽调制)大家可以上网查查,其原理讲解很多。为了更好的学习PWM,我特意参照别人写的文章,自己也写了一份代码来实现PWM。单片机代码如下:
  1. #include <stc12c5a60s2.h>

  2. unsigned long cnt;
  3. unsigned int cnt_T1;
  4. unsigned int high;
  5. unsigned int low;
  6. unsigned char TH0_high;
  7. unsigned char TL0_high;
  8. unsigned char TH0_low;
  9. unsigned char TL0_low;
  10. unsigned char T1H1;
  11. unsigned char T1L1;
  12. unsigned char flag=0;

  13. unsigned char duty[19] = {5,10,15,20,25,30,35,40,45,50,55,60,65,70,75,80,85,90,95};
  14. unsigned char index=0;

  15. void config_Fy_and_dy(unsigned char fy, unsigned char dy);
  16. void config_Timer1(unsigned char ms);
  17. void modify_duty(unsigned char dy);

  18. sbit PWM_OUT = P2^5;

  19. void main()
  20. {
  21.     TMOD = 0X11;    //  定时器0/1都工作在方式1,是2^16计数
  22.     EA=1;
  23.     config_Fy_and_dy(100, 20);
  24.     config_Timer1(50);
  25.     while(1);
  26. }

  27. void config_Fy_and_dy(unsigned char fy, unsigned char dy) // 输入频率fy,占空比dy
  28. {
  29.     cnt =  (11059200/fy)/12;    //  要产生频率为fy,定时器0所要计的数值
  30.     high = (cnt*dy)/100;        //  计算出高电平所要计的数值
  31.     low = cnt - high;   //  计算出低电平所要计的数值
  32.     high = 65536 - high;  //  确定定时器0,从哪个初值开始计时,记录的是高电平
  33.     low = 65536 - low;  //  确定定时器0,从哪个初值开始计时,记录的是低电平
  34.     TH0_high = (unsigned char)(high>>8);    //  高电平,给TH0预备重装初值
  35.     TL0_high = (unsigned char)high;         //  高电平,给TL0预备重装初值
  36.     TH0_low = (unsigned char)(low>>8);      //  低电平,给TH0预备重装初值
  37.     TL0_low = (unsigned char)low;           //  低电平,给TL0预备重装初值
  38.     TH0 = TH0_high;
  39.     TL0 = TL0_high;
  40.     PWM_OUT = 1;               
  41.     ET0 = 1;
  42.     TR0 = 1;
  43. }

  44. void config_Timer1(unsigned char ms)
  45. {
  46.     unsigned long temp;
  47.     temp =  11059200/1000;
  48.     temp = (temp*ms)/12;
  49.     cnt_T1 = 65536 - temp;
  50.     T1H1 = (unsigned char)(cnt_T1>>8);
  51.     T1L1 = (unsigned char)cnt_T1;
  52.     TH1 = T1H1;
  53.     TL1 = T1L1;
  54.     ET1=1;
  55.     TR1=1;
  56. }

  57. void modify_duty(unsigned char dy)
  58. {
  59.     high = (cnt*dy)/100;
  60.     low = cnt - high;
  61.     high = 65536 - high;
  62.     low  = 65536 - low;
  63.     TH0_high = (unsigned char)(high>>8);    //  高电平,给TH0预备重装初值
  64.     TL0_high = (unsigned char)high;         //  高电平,给TL0预备重装初值
  65.     TH0_low = (unsigned char)(low>>8);      //  低电平,给TH0预备重装初值
  66.     TL0_low = (unsigned char)low;           //  低电平,给TL0预备重装初值
  67. }

  68. void T0_Timer0() interrupt 1
  69. {
  70.     if(PWM_OUT==0)  //  准备产生高电平
  71.     {
  72.         TH0 = TH0_high;         //  高电平产生  初值重装
  73.         TL0 = TL0_high;
  74.         PWM_OUT = 1;
  75.     }
  76.     else
  77.     {
  78.         TH0 = TH0_low;         //  低电平产生  初值重装
  79.         TL0 = TL0_low;
  80.         PWM_OUT = 0;
  81.     }
  82. }

  83. void T1_Timer1() interrupt 3
  84. {
  85.     TH1 = T1H1;
  86.     TL1 = T1L1;
  87.     modify_duty(duty[index]);
  88.     if(0 == flag)   //  flag=0时,表示呼吸灯由暗变亮
  89.     {
  90.         index++;
  91.         if(index >=18)
  92.         {
  93.             flag = 1;
  94.         }
  95.     }
  96.     else
  97.     {
  98.         index--;
  99.         if(index <=0)
  100.         {
  101.             flag=0;
  102.         }
  103.     }
  104. }
复制代码

其实,PWM这种实现方法并不适合编程,因为它占用了两个定时器中断口,会影响程序的执行效率。

我是通过两个定时器来更好的掌握PWM的调制原理。


回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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