如何用单片机的p0.0输出一个占空比可变的pwm信号

[复制链接]
7461|26
 楼主| 反孔精英 发表于 2008-11-12 17:18 | 显示全部楼层 |阅读模式
最近在用汇编写一个占空比可变的pwm信号,一直搞不定。<br />具体要求是p0.0输出一个pwm信号,要求pwm的频率是120hz,在5秒内,pwm的占空比由100%到0%,每次占空比减少1/256%<br />大家给点建议
ljm810010 发表于 2008-11-12 20:47 | 显示全部楼层

用这个就行啦

要5秒由100%变到0%,而PWM频率是120Hz,是不可能平滑过渡(5*120不能被256整除),所以这里不用5秒,用4.266秒(5秒内),就可实现脉宽从100%到0%的平滑递减,每次减1/256。下面是一示范程序,标准8051核,晶体11.0592MHz,两个PWM周期减一次脉宽,刚好4.266秒。<br /><br />L1:&nbsp;cjne&nbsp;a,7,$+3&nbsp;&nbsp;;比较脉宽,a作循环计数,r7为脉宽值<br />&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;P0.0,c&nbsp;&nbsp;&nbsp;;输出比较结果<br />&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;b,#8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;设定延时值<br />&nbsp;&nbsp;&nbsp;&nbsp;djnz&nbsp;b,$&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;延时<br />&nbsp;&nbsp;&nbsp;&nbsp;djnz&nbsp;acc,L4&nbsp;&nbsp;&nbsp;;完成一次PWM周期<br />&nbsp;&nbsp;&nbsp;&nbsp;jbc&nbsp;&nbsp;f0,L3&nbsp;&nbsp;&nbsp;&nbsp;;两个PWM周期改变一次脉宽<br />&nbsp;&nbsp;&nbsp;&nbsp;setb&nbsp;f0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;设立标记<br />&nbsp;&nbsp;&nbsp;&nbsp;dec&nbsp;&nbsp;r7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;脉宽递减<br />L2:&nbsp;jmp&nbsp;&nbsp;L1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;匹配时序<br />L3:&nbsp;jmp&nbsp;&nbsp;L2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;匹配时序<br />L4:&nbsp;jmp&nbsp;&nbsp;L3<br />
 楼主| 反孔精英 发表于 2008-11-13 08:31 | 显示全部楼层

一些不明白的地方

r7应该设初始值ff吧&nbsp;,前面应该有个mov&nbsp;r7,#0ffh。cjne&nbsp;a,7,$+3&nbsp;&nbsp;;$+3是什么?应该是cjne&nbsp;a,r7,$吧。
5880527 发表于 2008-11-13 09:20 | 显示全部楼层

***

没看太明白这个120HZ如何保证的,好象是在主循环里做的,除非就做这一件事情
lyjian 发表于 2008-11-13 09:26 | 显示全部楼层

2楼方法不错

只有256级,最小的占空比只能为1/256,是实现不了0%的。<br />占空比变化为1/256%~100%
ljm810010 发表于 2008-11-13 09:53 | 显示全部楼层

回复3楼反孔精英

一般来说,r7确应赋初值,而且acc,f0也应赋初值,这三个量决定了PWM的初始状态。但因你这里PWM状态是不断循环的,就不用管它初态如何,这三个值为任意,都是循环内的某一状态,不影响工作,只不过是PWM的初态不同。<br /><br />cjne&nbsp;a,7,$+3&nbsp;中的&nbsp;$+3&nbsp;是指向下一条指令,这里只作比较,无论结果如何,都是执行下一指令,而比较结果反映地进位标志c中。
ljm810010 发表于 2008-11-13 10:08 | 显示全部楼层

回复4楼5880527

120Hz是这样算:&nbsp;L1段每隔30周期(由寄存器b的值决定)执行一次,acc作256次循环计数,一次循环就是一个PWM周期,256*30=7680机器周期,11.0592MHz/12/7680&nbsp;=&nbsp;120Hz。<br /><br />本例是MCU处理单一事件的情况,实际应用要有PWM模块的MCU才能实用,没有PWM模块,用定时+中断,很难保证中断响应时间,从而PWM输出不精确,除非对PWM要求不高。
 楼主| 反孔精英 发表于 2008-11-13 10:22 | 显示全部楼层

还是不太明白2楼的程序

为什么是cjne&nbsp;a,7,$+3是不是等同于cjne&nbsp;a,R7,$+3?前面是不是应该加2句指令。<br />mov&nbsp;r7,#ffh<br />dec&nbsp;r7<br />回下4楼的,其实实现的思路是先显示2次pwm,然后改变一次pwm占空比,再显示2次pwm,改变pwm,如此循环256次,占空比由100%到0%&nbsp;。pwm的频率是120hz,周期是1/120s,显示2次需要1/60s,共计256个2次显示,耗时1/60*256s约等于4.2666s。这个程序需要一直循环的。就是2楼的程序还不怎么理解。
ljm810010 发表于 2008-11-13 10:39 | 显示全部楼层

回LS

cjne&nbsp;a,7,$+3&nbsp;就是等同&nbsp;cjne&nbsp;a,r7,$+3,不过写成r7是不能通过编译的,会报错。<br /><br />r7不用赋初值,我在6楼解释过<br /><br />至于&nbsp;dec&nbsp;r7,我放在程序后面,效果一样,不必在前面再加dec&nbsp;r7
5880527 发表于 2008-11-13 17:53 | 显示全部楼层

不管任务有多简单

个人还是觉得用定时器做好点,定时器做PWM的精度和单片机自带的PWM一样,而且定时器调节更灵活
ljm810010 发表于 2008-11-13 18:06 | 显示全部楼层

不一样D

PWM设一后就自行工作,没PWM用定时中断,中断响应时间就不同,精度跟硬件PWM没法比。
dengm 发表于 2008-11-13 18:26 | 显示全部楼层

11.0592MHz 120hz 1/256

11,059,200/12/120/256&nbsp;=&nbsp;30&nbsp;(指令周期)<br />用定时器能&quot;精确&quot;完成,&nbsp;CPU&nbsp;使用&nbsp;&lt&nbsp;0.5%&nbsp;.<br />
ljm810010 发表于 2008-11-13 19:12 | 显示全部楼层

楼主dengm可能有点误解

用定时器能“精确”完成计时,但不能“精确”输出PWM,“精确”计时完成后,还要通过中断处理才能输出PWM,一旦要中断,就不能“精确”了,因为响应中断的时间是不可预知的。
5880527 发表于 2008-11-13 19:31 | 显示全部楼层

其实是能完全能做到精确输出的

虽然每次定时器中断响应速度不一致,但简单修正就可以使得在同一时刻输出了。定时器做PWM只占用单片机很少时间资源,对于没有硬件PWM时完全可以用它做,唯一的缺点是不适合频率过高,象楼主这里的1/256用定时器做起来就很吃力了
 楼主| 反孔精英 发表于 2008-11-13 20:18 | 显示全部楼层

谢谢ljm810010的指点。

程序非常好用,我的控制板用的是24mhz晶振。就是输出有干扰,波形不是很好看,不过这个也没什么关系了,这个pwm波形是用来控制led亮度的。
 楼主| 反孔精英 发表于 2008-11-13 21:15 | 显示全部楼层

现在又有问题了

一个zql9712的ic,其实就是一个74hc595的缩小版,需要输入一个3bit的数据,控制时序如图,自己写了个程序,不能正常输入数据,大家帮看看有什么问题<br />ORG&nbsp;0030H<br />&nbsp;&nbsp;&nbsp;&nbsp;MOV&nbsp;P1,#0F7H&nbsp;&nbsp;&nbsp;&nbsp;;初始化p0<br />&nbsp;&nbsp;&nbsp;&nbsp;MOV&nbsp;29H,#01H&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;要输入的数据,00000001,<br />&nbsp;&nbsp;&nbsp;&nbsp;ACALL&nbsp;SEND<br />&nbsp;&nbsp;&nbsp;&nbsp;SETB&nbsp;P1.3<br />&nbsp;&nbsp;&nbsp;&nbsp;NOP<br />&nbsp;&nbsp;&nbsp;&nbsp;NOP<br />&nbsp;&nbsp;&nbsp;&nbsp;NOP<br />&nbsp;&nbsp;&nbsp;&nbsp;NOP<br />&nbsp;&nbsp;&nbsp;&nbsp;CLR&nbsp;P1.3<br />SEND:&nbsp;&nbsp;&nbsp;&nbsp;MOV&nbsp;R0,#03H&nbsp;&nbsp;&nbsp;&nbsp;;发送显示数据<br />S_LOOP:&nbsp;&nbsp;&nbsp;&nbsp;MOV&nbsp;C,29H.2<br />&nbsp;&nbsp;&nbsp;&nbsp;CLR&nbsp;P1.2<br />&nbsp;&nbsp;&nbsp;&nbsp;NOP<br />&nbsp;&nbsp;&nbsp;&nbsp;NOP<br />&nbsp;&nbsp;&nbsp;&nbsp;NOP<br />&nbsp;&nbsp;&nbsp;&nbsp;NOP<br />&nbsp;&nbsp;&nbsp;&nbsp;MOV&nbsp;P1.1,C<br />&nbsp;&nbsp;&nbsp;&nbsp;NOP<br />&nbsp;&nbsp;&nbsp;&nbsp;NOP<br />&nbsp;&nbsp;&nbsp;&nbsp;SETB&nbsp;P1.2<br />&nbsp;&nbsp;&nbsp;&nbsp;MOV&nbsp;A,29H<br />&nbsp;&nbsp;&nbsp;&nbsp;RL&nbsp;A<br />&nbsp;&nbsp;&nbsp;&nbsp;MOV&nbsp;29H,A<br />&nbsp;&nbsp;&nbsp;&nbsp;NOP<br />&nbsp;&nbsp;&nbsp;&nbsp;NOP<br />&nbsp;&nbsp;&nbsp;&nbsp;NOP<br />&nbsp;&nbsp;&nbsp;&nbsp;NOP<br />&nbsp;&nbsp;&nbsp;&nbsp;NOP<br />&nbsp;&nbsp;&nbsp;&nbsp;CLR&nbsp;P1.2<br />&nbsp;&nbsp;&nbsp;&nbsp;DJNZ&nbsp;R0,S_LOOP<br />&nbsp;&nbsp;&nbsp;&nbsp;CLR&nbsp;P1.1<br />&nbsp;&nbsp;&nbsp;&nbsp;RET<br />&nbsp;&nbsp;&nbsp;&nbsp;END
 楼主| 反孔精英 发表于 2008-11-13 21:21 | 显示全部楼层

时序图如下和输出io定义如下

;P1.0&nbsp;OE<br />;P1.1&nbsp;DA<br />;P1.2&nbsp;CK<br />;P1.3&nbsp;LA<br />
耕在此行 发表于 2008-11-13 21:35 | 显示全部楼层

同意10楼观点

首先:楼主的思路有问题,既然是控制LED,那就只要在0-5秒内均匀地从100%降到0就行了.不必管它每次降多少.<br />所以:120HZ&nbsp;*&nbsp;5&nbsp;S&nbsp;=&nbsp;600次&nbsp;,每次降1/&nbsp;600就行了.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;定时器每1/(120*600)秒=13.88uS中断一次并计数,并从0计数.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;计数到600,重新开始输出脉宽(IO高),计数到脉宽比较值,结束输出脉冲(IO低),比较值每脉宽输出一次减一.<br />注意点:单片机机器周期越小越小,如STC的单CLK的片子,或PHILIPS的900&nbsp;,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;430的等等.晶振频率在允许情况下越高越好.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;另外,定时器中断定在最高优先级.其它中断定在次优先级.<br />本人曾经做过七彩背光.呵呵&nbsp;用430做的&nbsp;PWM控制效果很不错.<br />
lyjian 发表于 2008-11-13 23:10 | 显示全部楼层

控制LED而已,没必要做得那么精确

用定时中断做,误差一个指令周期(1/30=3.3%&nbsp;with&nbsp;XTAL=11.0592)。
 楼主| 反孔精英 发表于 2008-11-14 08:16 | 显示全部楼层

这个倒不是什么精不精确的问题

led调光都是用多少位调光的,一般都是2的n次方,这里用的是8位调光,所以要分为256级。随便设是不行的。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

12

主题

74

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部