原创 51单片机软模PWM误差率之研究--基于Keil、Proteus仿真调试

2007-1-25 07:24 7438 9 12 分类: MCU/ 嵌入式

    普通型51单片机一般不集成PWM硬件发生器,要想实现PWM输出必须采用软件模拟的方式。根据具体应用的不同,PWM波形频率也高低不一;就直流电机控制而言,PWM波的频率一般建议在10kHz~40kHz,20kHz为典型值,输出频率过低,则输出电流不够平缓,电机运行不平稳。


    软模PWM输出一般有两种方式:利用定时器0控制PWM频率输出,结合定时器1控制占空比,这是其一;第二种方式,仅使用一个定时器,工作于16bit手工装载模式,同时控制输出频率和占空比,这种方式不占用太多资源,而且实现起来也不失其灵活性,俺本人就建议采用这样方式,建议剔除第一种方式。本文的研究也是基于方式二展开的。


    网络上常见MCS-51软模输出PWM波的文章,而至于对这种方式实现的可行性或者说局限性,却无一例外的被小觑了。本文就51单片机模拟PWM波输出的劣根性进行了探讨,不正之处,欢迎大家提点。


    1、产生PWM波的子模块例程(PWM.C):


#include "Includes.h"   //文件包含


/*******************************************************************************
*** 函 数 名:   extern void PWM_Init(void)
*** 功能描述:   PWM参数初始化;
*** 全局变量:   NO !
*** 输        入:   NO !
*** 输        出:   NO !
*** 创 建 人:huangtiexiong     日期:2006-11-28
*** 修 改 人:                             日期:2006-11-28
*** 函数说明:  外部函数;
/******************************************************************************/
extern void PWM_Init(void)
{
 TMOD &= 0x0f; TMOD |= 0x10;   //定时器1方式1,16位手动装载模式;
 
 TH1 = (65536 - PWM_HIGH) / 256 ;
 TL1 = (65536 - PWM_HIGH) % 256 ;
 
 PWM_PIN = 1;   //初始化先输出高电平;
 ET1   = 1;   //开定时器1中断;
 EA    = 1; TR1   = 1;   //启动定时器1;
 }
/*******************************************************************************
*** 函 数 名:   extern void Timer1_ISR(void) interrupt 3
*** 功能描述:   定时器1中断服务例程;
*** 全局变量:   NO !
*** 输        入:   NO !
*** 输        出:   NO !
*** 创 建 人:huangtiexiong     日期:2006-11-28
*** 修 改 人:                             日期:2006-11-28
*** 函数说明:  中断服务函数;
       PWM_LOW:   低电平持续时间us;
       PWM_HIGH: 高电平持续时间us;
       PWM_PIN:      PWM波输出引脚,接P1.7;
/******************************************************************************/
extern void Timer1_ISR(void) interrupt 3
{
 if(PWM_PIN)  {PWM_PIN = 0;
   TH1 = (65536 - PWM_LOW) / 256 ;
   TL1 = (65536 - PWM_LOW) % 256 ; }
 else   {PWM_PIN = 1;
   TH1 = (65536 - PWM_HIGH) / 256 ;
   TL1 = (65536 - PWM_HIGH) % 256 ; }  
 }
/*******************************************************************************
****                              End Of File
*******************************************************************************/
    其中断服务例程在Keil C中编译后的汇编代码如下(默认8级代码优化):


             ; FUNCTION Timer1_ISR (BEGIN)
                                           ; SOURCE LINE # 43
                                           ; SOURCE LINE # 45
0000 309709            JNB     PWM_PIN,?C0002
                                           ; SOURCE LINE # 46
                                           ; SOURCE LINE # 47
0003 C297              CLR     PWM_PIN
                                           ; SOURCE LINE # 48
0005 758DFF            MOV     TH1,#0FFH
                                           ; SOURCE LINE # 49
0008 758BB5            MOV     TL1,#0B5H
                                           ; SOURCE LINE # 50
000B 32                RETI   
000C         ?C0002:
                                           ; SOURCE LINE # 52
                                           ; SOURCE LINE # 53
000C D297              SETB    PWM_PIN
                                           ; SOURCE LINE # 54
000E 758DFF            MOV     TH1,#0FFH
                                           ; SOURCE LINE # 55
0011 758BE7            MOV     TL1,#0E7H
                                           ; SOURCE LINE # 56
                                           ; SOURCE LINE # 57
0014         ?C0004:
0014 32                RETI   
             ; FUNCTION Timer1_ISR (END)


    2、主入口模块(BootLoader.c):在主模块main函数中,首先清零PWM_PIN引脚,接着调用PWM_Init()例程,然后就是一个简单的空循环,其经由Keil C编译后的汇编代码为:


             ; FUNCTION main (BEGIN)

0000 C297              CLR     PWM_PIN
                                           ; SOURCE LINE # 31
0002 120000      E     LCALL   PWM_Init
0005         ?C0001:
                                           ; SOURCE LINE # 32
0005 80FE              SJMP    ?C0001
             ; FUNCTION main (END)


    3、另外还有两个重要的参数宏,定义在在PWM模块的头文件PWM.H中:


#define PWM_CYCLE  100    //100us,则PWM波的频率为10kHz;
#define PWM_HIGH     25      //高电平持续时间,占空比1/4;
#define PWM_LOW      75      //低电平持续时间;


    4、首先取PWM_CYCLE, PWM_HIGH, PWM_LOW分别为100、25、75,则设定的PWM波频率为10kHz,占空比0.25。编译连接正确后在Proteus中仿真(单片机晶振频率设置为12.0mHz),抓出一个周期的波形图如下:


点击看大图


可计算:高电平持续时间为810us-773us=37us,低电平持续时间897us-810us=87us,实际输出PWM波的占空比为:37/(37+87)=0.298387,占空比误差率为(0.298387-0.25)/0.25=19.35%;一般工程实践要求的误差率不超过5%,显然这19.35%的误差率是不符合要求的。(注-Proteus的图形仿真精度:对模拟量的采样最小间隔为1e-18s,典型值为1e-09,参见Proteus使用手册。)


    5、接着取PWM_CYCLE, PWM_HIGH, PWM_LOW分别为10、2、8,则设定的PWM波频率为100kHz,占空比0.2。编译连接正确后在Proteus中仿真(12.0mHz晶振)后抓出的单个周期波形图如下:


点击看大图


由图可计算得:实际输出的PWM_HIGH, PWM_LOW分别为15、19,占空比0.4412,占空比误差率120.59%,也就是说,实际输出的PWM波占空比翻番了。


    6、继续取PWM_CYCLE, PWM_HIGH, PWM_LOW分别为1000、250、750,则设定的PWM波频率为1kHz,占空比0.25。编译连接正确后在Proteus中仿真(12.0mHz晶振)后抓出的单个周期波形图如下:


点击看大图


由图可计算:实际输出的PWM_HIGH, PWM_LOW分别为262、762,占空比0.2558,占空比误差率2.34%(<5%)。


    7、综上,本文得出的结论为:在51单片机上采用软件模拟的方式输出PWM波,其频率越大,占空比误差越不可收拾;在PWM波形频率不是很高的情况下(比如小于1kHz),采用软模方式输出PWM是完全可行的。


    8、为什么会出现这种情况呢 ?首先将每次仿真调试,程序中设定的PWM_HIGH, PWM_LOW值及实际输出值列表如下:


点击看大图


比较发现实际输出的PWM波形时间参数总比我们当然中预期的多约12个us,也就是本仿真单片机的12个机器周期。再次查看中断服务函数的汇编代码:


             ; FUNCTION Timer1_ISR (BEGIN)
                                           ; SOURCE LINE # 43
                                           ; SOURCE LINE # 45
0000 309709            JNB     PWM_PIN,?C0002        ;;;2us
                                           ; SOURCE LINE # 46
                                           ; SOURCE LINE # 47
0003 C297              CLR     PWM_PIN                        ;;;1us
                                           ; SOURCE LINE # 48
0005 758DFF            MOV     TH1,#0FFH                 ;;;2us
                                           ; SOURCE LINE # 49
0008 758BB5            MOV     TL1,#0B5H                  ;;;2us
                                           ; SOURCE LINE # 50
000B 32                RETI                                                  ;;;2us
000C         ?C0002:
                                           ; SOURCE LINE # 52
                                           ; SOURCE LINE # 53
000C D297              SETB    PWM_PIN                      ;;1us
                                           ; SOURCE LINE # 54
000E 758DFF            MOV     TH1,#0FFH                 ;;2us
                                           ; SOURCE LINE # 55
0011 758BE7            MOV     TL1,#0E7H                   ;;2us
                                           ; SOURCE LINE # 56
                                           ; SOURCE LINE # 57
0014         ?C0004:
0014 32                RETI                                                   ;;2us
             ; FUNCTION Timer1_ISR (END)


这次把每条指令的执行时间注释了在后,考虑指令流进入了定时器中断,执行CLR     PWM_PIN指令完成,则经4us的PWM_HIGH计时参数装载,2us的中断返回操作,运行main流程中的SJMP    ?C0001空转指令至定时器再次溢出中断(Xus,X为程序设定PWM_HIGH取值),CPU中断响应再次转入中断服务例程(可计算中断响应时间为3~4us),执行JNB     PWM_PIN,?C0002跳转指令2us,接着完成SETB    PWM_PIN操作1us……时间累加计算式:4us+2us+Xus+3~4us+2us+1us=Xus+12~13us


    9、到这里,单片机软模PWM波在高频输出下占空比误差率变得不可收拾的原因终于毕露原形。实际输出占空比计算式为:(PWM_HIGH+12)/(PWM_HIGH+PWM_LOW+24)

文章评论3条评论)

登录后参与讨论

用户789033 2010-7-19 09:06

你好!您的计算很精确,也找到了产生误差的原因,请问是否可以加补偿来校正指令产生的时间误差.如果想继续探讨请联系QQ396191655。 我现在也要用51模拟PWM,不知道行不行

用户54384 2009-4-13 23:05

好啊   搜藏了哈

jizzll_617398179 2008-4-27 17:53

谢谢哈

用户1109764 2007-4-2 16:36

兄弟的文章言之有物,有理有据,不错,我顶了。

相关推荐阅读
用户68356 2007-06-10 09:23
canopen
我申请了恒润科技的试用光盘(VectorDemoCDV8.3),里边coe_canopen.exe因损坏无效,是不是每张光盘都这样?...
用户68356 2007-05-19 03:39
本博公告
本博暂停更新,稍后就回。欢迎访问:canopen.onlyblog.com...
用户68356 2007-03-14 22:17
ARM7TDMI-S后缀解释
T:Thumb代码支持,16bits指令结构;D:Debug硬件调试模块支持;M:加强的乘法操作支持(硬件乘法器),64位乘法结果;I:EmbededICE Logic,支持片上断点和调试点;S:sy...
用户68356 2007-03-14 04:44
老子-道德经
老子道德经--白话文注解:http://www.xet.cn/_game/lib/01_laozi/...
用户68356 2007-03-08 00:56
ARM完整定义
     ARM是英国一家电子公司的名字,全名的意思是Advanced RISC Machine。ARM首创了chipless的生产模式,即该公司既不生产芯片,也不设计芯片,而是设计出高效的IP内核,...
用户68356 2007-03-08 00:24
CPU基本概念
1.主频       主频也叫时钟频率,单位是MHz,用来表示CPU的运算速度。CPU的主频=外频×倍频系数。很多人认为主频就决定着CPU的运行速度,这不仅是个片面的,而且对于服务器来讲,这个认识也出...
我要评论
3
9
关闭 站长推荐上一条 /2 下一条