搜索
bottom↓
回复: 22

IO口模拟PWM输出

[复制链接]

出0入0汤圆

发表于 2012-3-27 23:37:29 | 显示全部楼层 |阅读模式
用的是STC89C52RC  有兴趣的可以看看
  1. #include <reg52.h>
  2. sbit PWM=P3^7;
  3. unsigned char a=1,b,c;
  4. void init()
  5. {
  6.     TMOD= 0x11;//打开定时器0,定时器1
  7.     IE =0x8A;  //打开总中断,定时器0中断,定时器1中断
  8.         TH0 = 0xFF;//定时器0赋初值  时间为200MS
  9.         TL0 = 0x38;
  10.         TR0 = 1;   //定时器
  11.         TH1 =(65535-(a*200))/256;
  12.         TL1 =(65535-(a*200))%256;
  13.         TR1=1;
  14. }
  15. void main()
  16. {
  17.         P3=0x80;
  18.         init();
  19.         while(1)
  20.         {
  21.                 if(TR1==0)PWM=1;
  22.                 else PWM=0;
  23.         }
  24. }

  25. /*************************************
  26. 利用定时器产生PWM波形,128个点采集          两个定时器互相控制 来达到产生PWM
  27. *************************************/
  28. void T0zd(void) interrupt 1  
  29. {
  30.         TH0 = 0xFF; //12MHz
  31.         TL0 = 0x38;
  32.         c++;
  33.         if(c==(129-a))
  34.         {       
  35.                 c=0;
  36.                 if(b==0)a++;
  37.                 if(a==128)b=1;
  38.                 if(b==1)a--;
  39.                 if(a==0)b=0;
  40.                 TR0=0;
  41.                 TR1=1;
  42.         }         
  43. }
  44. void T1zd()interrupt 3
  45. {
  46.         TH1 =(65535-a*200)/256;
  47.         TL1 =(65535-a*200)%256;
  48.         TR1=0;
  49.         TR0=1;               
  50. }

复制代码

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

阿莫论坛20周年了!感谢大家的支持与爱护!!

你熬了10碗粥,别人一桶水倒进去,淘走90碗,剩下10碗给你,你看似没亏,其实你那10碗已经没有之前的裹腹了,人家的一桶水换90碗,继续卖。说白了,通货膨胀就是,你的钱是挣来的,他的钱是印来的,掺和在一起,你的钱就贬值了。

出90入0汤圆

发表于 2012-3-28 21:51:26 | 显示全部楼层
请问楼主加了限流电阻没?

出0入0汤圆

发表于 2012-3-28 22:35:59 | 显示全部楼层

出0入0汤圆

 楼主| 发表于 2012-3-29 07:52:17 | 显示全部楼层
xuyapple 发表于 2012-3-28 21:51
请问楼主加了限流电阻没?

没有  面包板上面随便玩玩

出0入0汤圆

 楼主| 发表于 2012-3-29 07:53:20 | 显示全部楼层
shanyan 发表于 2012-3-28 22:35

新手求教

出0入0汤圆

发表于 2012-3-29 08:18:53 | 显示全部楼层
......

出0入0汤圆

发表于 2012-3-29 08:30:58 | 显示全部楼层
here is the two-timer version.
  1. #include <regx51.h>
  2. sbit PWM=P2^1;
  3. //unsigned char a=1,b,c;
  4. unsigned short pwm_dc=0;                                //pwm duty cycle
  5. unsigned short pwm_pr=0xff00;                        //pwm period, 16-bit

  6. /*************************************
  7. ???????PWM??,128????          ????????? ?????PWM
  8. *************************************/
  9. //for pwm period
  10. void T0zd(void) interrupt TF0_VECTOR
  11. {
  12.         PWM = 1;                                                        //set pwm output pin
  13.         TR1 = 1;                                                        //turn on tmr1 for duty cycle
  14.         TH0 += (-pwm_pr)>> 8;                                //set the msb
  15.         TL0 += (-pwm_pr);                                        //set the lsb
  16. }

  17. //for dc
  18. void T1zd()interrupt TF1_VECTOR
  19. {
  20.     PWM = 0;                                                        //clear pwm output pin
  21.         TR1 = 0;                                                        //stop tmr1
  22.         TH1 += (-pwm_dc) >> 8;                                //set the msb
  23.         TL1 += (-pwm_dc);                                        //set the lsb
  24. }

  25. //set pwm parameters
  26. void pwm_init(unsigned short period, unsigned short dc)
  27. {
  28.     pwm_pr = period;                                        //update pwm_pr
  29.         pwm_dc = dc;                                                //update pwm_dc
  30.        
  31.         TR0 = 0, TR1 = 0;                                        //stop the timers
  32.         TMOD= 0x11;                                                        //use tmr0/1
  33.     //IE =0x8A;  //?????,???0??,???1??
  34.    
  35.         //tmr0 sets the priod
  36.         TH0 = (-pwm_pr)>> 8;                                //get the msb
  37.         TL0 = (-pwm_pr);                                        //get the lsb
  38.         ET0 = 1;                                                        //enable interrupt on tmr0
  39.        
  40.         //tmr1 sets the duty cycle
  41.         TH1 = (-pwm_dc) >> 8;                                //get the msb
  42.         TL1 = (-pwm_dc);                                        //get the lsb
  43.         ET1 = 1;                                                        //enable interrupt on tmr1

  44.     TR0 = 1;                                                           //turn on tmr0
  45.     TR1 = 1;                                                        //turn on tmr1

  46.         PWM = 0;                                                        //pwm output pin starts high
  47. }

  48. void main(void)
  49. {
  50.         //P3=0x80;
  51.         pwm_init(2000, 100);                        //initialize pwm to 1000 dc and 2000 period
  52.                 EA = 1;                                                        //enable interrupt
  53.         while(1)
  54.         {
  55.                 //if(TR1==0)PWM=1;
  56.                 //else PWM=0;
  57.         }
  58. }
复制代码
you can easily make it to a one-timer version.

出0入0汤圆

 楼主| 发表于 2012-3-29 08:31:11 | 显示全部楼层
1148729990 发表于 2012-3-29 08:18
......

这位是……  应该认识吧

出0入0汤圆

发表于 2012-3-29 08:32:18 | 显示全部楼层
慢慢学习中……

出0入0汤圆

 楼主| 发表于 2012-3-29 08:32:45 | 显示全部楼层
millwood0 发表于 2012-3-29 08:30
here is the two-timer version.you can easily make it to a one-timer version.

这个方法貌似不错,领教了

出0入0汤圆

发表于 2012-3-29 15:28:07 来自手机 | 显示全部楼层
怎么个模拟法,

出0入0汤圆

 楼主| 发表于 2012-3-29 19:06:37 | 显示全部楼层
jjj2012 发表于 2012-3-29 15:28
怎么个模拟法,

模拟输出PWM波形,用定时器的。

出0入0汤圆

发表于 2012-3-29 19:09:00 | 显示全部楼层
第一次用这种方法在51上模拟串口通迅,效果非常不错

出0入0汤圆

发表于 2012-3-29 20:29:10 | 显示全部楼层
wubingqp 发表于 2012-3-29 19:06
模拟输出PWM波形,用定时器的。

刚刚那个信息我是在手机上发的,没有看到图片,当时还纳闷,后来发现这个程序我也做过;
差不多,我当时也是在做呼吸灯,也是在面包板上,我加了限流电阻

出0入0汤圆

发表于 2012-3-30 03:10:54 | 显示全部楼层
这个方法貌似不错


your original code will never work in real life, because it requires short main loop.

It has to be either multi-threaded or via interrupt.

出0入0汤圆

发表于 2012-3-30 05:58:45 | 显示全部楼层
here is the single tmr version. much easier to implement and saves one timer/isr.
  1. //pwm using one single timer (tmr0)
  2. #include <regx51.h>
  3. sbit PWM=P2^1;
  4. //unsigned char a=1,b,c;
  5. unsigned short pwm_dc=0;                                //pwm duty cycle
  6. unsigned short pwm_pr=0xff00;                        //pwm period, 16-bit

  7. /*************************************
  8. ???????PWM??,128????          ????????? ?????PWM
  9. *************************************/
  10. //for pwm period
  11. void T0zd(void) interrupt TF0_VECTOR
  12. {
  13.         if (PWM == 1) {                                                //pwm on period has finished
  14.                 PWM = 0;                                                //clear pwm output pin
  15.                 TH0 += (-pwm_pr)>> 8;                        //set the msb
  16.                 TL0 += (-pwm_pr);                                //set the lsb
  17.         } else {
  18.                 PWM = 1;                                                //set pwm output pin
  19.                 TH0 += (-pwm_dc)>> 8;                        //set the msb
  20.                 TL0 += (-pwm_dc);                                //set the lsb
  21.         }
  22. }

  23. //for dc
  24. /*
  25. void T1zd()interrupt TF1_VECTOR
  26. {
  27.     PWM = 0;                                                        //clear pwm output pin
  28.         TR1 = 0;                                                        //stop tmr1
  29.         TH1 += (-pwm_dc) >> 8;                                //set the msb
  30.         TL1 += (-pwm_dc);                                        //set the lsb
  31. }
  32. */

  33. //set pwm parameters
  34. void pwm_init(unsigned short period, unsigned short dc)
  35. {
  36.     pwm_pr = period - dc;                        //update pwm_pr
  37.         pwm_dc = dc;                                                //update pwm_dc
  38.        
  39.         TR0 = 0;                                                        //, TR1 = 0;                                        //stop the timers
  40.         TMOD= (TMOD & 0xf0) | 0x01;                        //use tmr0 in mode 1
  41.     //IE =0x8A;  //?????,???0??,???1??
  42.    
  43.         //tmr0 sets the priod
  44.         TH0 = (-pwm_dc)>> 8;                                //get the msb
  45.         TL0 = (-pwm_dc);                                        //get the lsb
  46.         ET0 = 1;                                                        //enable interrupt on tmr0
  47.        
  48.         //tmr1 sets the duty cycle
  49.         //TH1 = (-pwm_dc) >> 8;                                //get the msb
  50.         //TL1 = (-pwm_dc);                                        //get the lsb
  51.         //ET1 = 1;                                                        //enable interrupt on tmr1

  52.     TR0 = 1;                                                           //turn on tmr0
  53.     //TR1 = 1;                                                        //turn on tmr1

  54.         PWM = 1;                                                        //pwm output pin starts high
  55. }

  56. void main(void)
  57. {
  58.         //P3=0x80;
  59.         pwm_init(2000, 1000);                        //initialize pwm to 1000 dc and 2000 period
  60.                 EA = 1;                                                        //enable interrupt
  61.         while(1)
  62.         {
  63.                 //if(TR1==0)PWM=1;
  64.                 //else PWM=0;
  65.         }
  66. }
复制代码
again, the code is fully implemented in the isr so you are free to do whatever you want in the main loop.

出0入0汤圆

 楼主| 发表于 2012-3-30 07:58:05 | 显示全部楼层
millwood0 发表于 2012-3-30 03:10
your original code will never work in real life, because it requires short main loop.

It has to b ...

我应该把while里面的两个语句放到中断里面去

出0入0汤圆

发表于 2012-3-30 08:16:24 | 显示全部楼层
本帖最后由 笑笑我笑了 于 2012-3-30 08:18 编辑

以前做的一个呼吸灯的,没用定时器
  1. /*         L.120216             */
  2. /*         pwm_led m8           */
  3. #define F_CPU 8000000UL
  4. #include<avr/io.h>
  5. #include<util/delay.h>

  6. int pwm(unsigned int val)
  7. {  
  8.    unsigned int i;

  9.    PORTD|=_BV(PD0);
  10.    for(i = 0; i < val; i++)
  11.       _delay_us(10);
  12.    PORTD&= ~_BV(PD0);
  13.    for(i = 0; i < (1024-val); i++)
  14.       _delay_us(10);
  15.    
  16.    return 0;
  17. }

  18. int main()
  19. {
  20.    DDRD|=_BV(PD0);
  21.    unsigned char dir;
  22.    unsigned int  val;
  23.    dir = 0;

  24. while(1)
  25. {
  26.      
  27.     if(dir == 1)
  28.       {
  29.           val = 1024;
  30.         while(val)
  31.          {
  32.             pwm(val);
  33.             val--;
  34.          }
  35.         
  36.          dir = 0;
  37.       }
  38.     else
  39.       {
  40.          val = 0;
  41.          while(val < 1024)
  42.           {
  43.              pwm(val);
  44.              val++;
  45.           }
  46.    
  47.           dir = 1;  
  48.       }
  49. }
  50.   
  51.   return 0;
  52. }
复制代码

出0入0汤圆

 楼主| 发表于 2012-3-30 08:25:32 | 显示全部楼层
笑笑我笑了 发表于 2012-3-30 08:16
以前做的一个呼吸灯的,没用定时器

应该还可以更简单。

出50入4汤圆

发表于 2012-4-12 23:01:08 | 显示全部楼层
貌似应该是65536-a*200

出0入0汤圆

发表于 2012-4-13 14:23:39 | 显示全部楼层
正学习,下来好好看看.

出0入0汤圆

发表于 2012-7-6 19:24:07 | 显示全部楼层
会有点闪烁哦

出0入0汤圆

发表于 2012-7-14 21:18:45 | 显示全部楼层
millwood0 发表于 2012-3-30 05:58
here is the single tmr version. much easier to implement and saves one timer/isr.again, the code is  ...

PWM = 0;                                                //clear pwm output pin
TH0 += (-pwm_pr)>> 8;                        //set the msb
TL0 += (-pwm_pr);                                //set the lsb
} else {
PWM = 1;                                                //set pwm output pin
TH0 += (-pwm_dc)>> 8;                        //set the msb
TL0 += (-pwm_dc);                                //set the lsb


这里似乎没有考虑到加法溢出的情况,应该会对 PWM 的精度有影响。

不过单纯通过单片机的定时器配合软件实现 PWM 很难实现较高的精度。这个例子里没有其他更高优先的中断,可以考虑把进入定时中断需要的时钟周期预先计算好,把加载到 TL0 TH0 的数值以常量的形式存储起来。这样不需要每次都重新计算,减少冗余的运算量。这样可以使得这样的软件模拟的 PWM 可以达到更高的工频。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-10-3 18:26

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

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