找回密码
 立即注册

QQ登录

只需一步,快速开始

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

基于单片机的模拟PWM信号调光源码与详解

[复制链接]
跳转到指定楼层
楼主
                                

        89C51芯片没有自带PWM发生器,如果要用51来产生PWM波就必须要用软件编程的方法来模拟。方法大概可以分为软件延时和定时器产生两种方法。下面将逐一介绍。

        1 软件延时法

        利用软件延时函数,控制电平持续的时间,达到模拟pwm的效果。

        程序如下:

        #include sbit pwm=P1^0; main() { while(1) { pwm=1; delayus(60);//置高电平后延时60us,占空比60% pwm=0; delayus(40); } } void delayus(uint x) { while(x--); }

        proteus软件仿真结果如下:

        

        可见,用这种延时函数的方法就能简单地模拟出pwm输出。但是这种方法的缺点也相当明显。当程序除了要输出pwm波还要执行其他操作比如键盘扫描、显示等操作时,需要占用CPU一定的机器周期,这样就会影响pwm的准确度。现在很少会用到这种方法,接下来要介绍的是比较常用的方法。

        2 定时器产生pwm

        这种方法利用了定时器溢出中断,在中断服务程序改变电平的高低,在程序较复杂、多操作时仍能输出较准确的pwm波形。

        2.1 注意事项

        2.2.1中断服务程序的内容。

        一般来说中断服务程序只完成改变标志位、转换高低电平的功能,如果中断服务程序中有太多的操作会影响pwm波的输出,尤其是除法、取余、浮点数运算会占用大量的机器周期,应在中断外完成运算。2.2.2定时器装入初值的问题。

        装入初值不能太接近于定时器的溢出值。如我们使用定时器方式1,最多能计65536个数,假设我们转入的初值为65534,那么定时器计两个数就会进入中断,这样会使程序紊乱而其他功能无法正常地执行,所以一般要留50-100个数的裕量。

        2.2 定时器工作方式

        在定时器工作方式的选择上,可以选择定时器的工作方式0、1、2都可以,本文采用的是工作方式1,即16位定时器,这样可以获得较宽的调频范围。

        2.3 定时器初值的计算

        设占空比为α,频率为f

        产生高电平时装入定时器高8位的值应为

        产生高电平时装入定时器低8位的值应为

        显然,产生低电平时的公式只要把α换成(1-α)就行了。

        然而在51单片机中,浮点数运算需要消耗cpu很长的时间,为了提高程序效率,通常用100倍的占空比来计算。同时,要注意数据类型,避免超出范围,影响计算结果。关于C51的乘除法问题,可以看以下这篇文章:http://www.51hei.com/bbs/dpj-33628-1.html

        修改后的公式如下:a为100倍占空比,fr为0.01倍频率TH0 = (65535-a*100/fr)/256; //高位初值TL0 = (65535-a*100/fr)%256;同样,低电平的公式只需把a换成(100-a)即可。

        2.4 例程

        本例程采用定时器T0在工作方式1下产生一路PWM,用独立键盘控制频率、占空比的加减,频率可调范围100Hz-10kHz,占空比0-100%(均为理论值,实际值略低)部分代码如下:

        

        注:T0_H , T0_L , T1_H , T1_L 均用于暂时存储初值,进入中断服务程序后直接给寄存器TH0、TL0赋值,避免了在中断中计算。

        

        注:flag为pwm输出标志,flag=1输出高电平,flag=0输出低电平

        2.5 软件仿真结果

        2.5.1 频率为100Hz

        a.占空比约15%

        

        b.占空比95%

        

        2.5.2 频率为10KHz

        a.占空比15%

        

        b.占空比90%

        

                        


单片机源程序如下:
  1. /*-----------------------------------------------
  2. 功能:通过PWM(脉宽调制)调节LED的亮度
  3. ------------------------------------------------*/
  4. #include //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义

  5. sbit LED0=P0^0;// 用sbit 关键字 定义 LED到P0.0端口,LED是自己任意定义且容易记忆的符号


  6. void Delay(unsigned int t); //函数声明
  7. /*------------------------------------------------
  8.                     主函数
  9. ------------------------------------------------*/
  10. void main (void)
  11. {
  12.                   
  13. unsigned int CYCLE=600,PWM_LOW=0;//定义周期并赋值
  14. while (1)         //主循环
  15.   {
  16. LED0=1;
  17. Delay(60000);        //特意加延时,可以看到熄灭的过程
  18. for(PWM_LOW=1;PWM_LOW<cycle;pwm_low++){ pwm_low表示低
  19. //电平时间,这个循环中低电平时长从1累加到CYCLE(周期)的值,即600次

  20.                    LED0=0;        //点亮LED  
  21.                    Delay(PWM_LOW);//延时长度,600次循环中从1加至599
  22.                    LED0=1;        //熄灭LED
  23.               Delay(CYCLE-PWM_LOW);//延时长度,600次循环中从599减至1
  24.      
  25.    }
  26. LED0=0;
  27. for(PWM_LOW=CYCLE-1;PWM_LOW>0;PWM_LOW--){ //与逐渐变亮相反的过程

  28.                    LED0=0;
  29.                    Delay(PWM_LOW);
  30.                    LED0=1;
  31.               Delay(CYCLE-PWM_LOW);
  32.      
  33.    }
  34.                      //主循环中添加其他需要一直工作的程序
  35.   }
  36. }
  37. /*------------------------------------------------
  38. 延时函数,含有输入参数 unsigned int t,无返回值
  39. unsigned int 是定义无符号整形变量,其值的范围是
  40. 0~65535
  41. ------------------------------------------------*/
  42. void Delay(unsigned int t)
  43. {
  44. while(--t);
  45. }
复制代码

所有资料51hei提供下载:
模拟PWM调亮度.zip (10.18 KB, 下载次数: 68)


评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

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

使用道具 举报

沙发
ID:447334 发表于 2019-4-26 13:32 | 只看该作者
不是用定时器实现 文不对题 骗积分
回复

使用道具 举报

板凳
ID:713781 发表于 2020-3-31 14:30 | 只看该作者
为什么我照你的方式做却没有波形呢
回复

使用道具 举报

地板
ID:761059 发表于 2020-5-29 19:39 | 只看该作者
一点都不好
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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