您好,欢迎来到五一七教育网。
搜索
您的当前位置:首页pwm原理

pwm原理

来源:五一七教育网
你要用51产生PWM去控制LED,首先你要确定PWM的周期T和占空比D,确定了这些以后,你可以用定时器产生一个时间基准t,比如定时器溢出n次的时间是PWM的高电平的时间,则D*T=n*t,类似的可以求出PWM低电平时间需要多少个时间基准n'

那么你就可以编写程序,根据你定的时间基准 t 去给定时器赋值初始化,然后开启定时器,定义一个标志位flag,根据flag的状态决定输出高平还是低电平,假设定义flag=1的时候输出高电平,用一个变量去记录定时器中断的次数,每次中断就让记录中断次数的变量+1,在中断程序里面判断这个变量的值是否到了 n ,如果到了说明高电平的时间够了,那么就改变flag为0,输出低电平,同时记录中断变量的值清零,每次中断的时候依旧+1,根据flag=0的情况跳去判断记录变量的值是否到了 n' 如果到了,说明PWM的低电平时间够了,那么就改flag=1,输出改高电平,同时记录次数变量清零,重新开始,如此循环便可得到你想要的PWM波形。

用51单片机比较麻烦,可以用定时器T0来控制频率,定时器T1来控制占空比。大致思路是这样的:T0定时器中断是让一个IO口输出高电平,在这个定时器T0的中断当中启动定时器T1,二这个T1是让IO口输出低电平,这样改变定时T0的初值就可以改变频率,改变定时器T1的初值就可以改变占空比。

PWM 控制 LED 灯渐亮渐灭程序 * ; 利用定时器控制产生占空比可变的 PWM 波 * ; 按K1,PWM值增加,则占空比减小,LED 灯渐暗。 * ; 按K2,PWM值减小,则占空比增加,LED 灯渐亮。 * ;当PWM值增加到最大值或减小到最小值时,蜂鸣器将报警 * ;资源:p0口,8路指示灯。p1.4,p1.5亮度控制按键(端口按键)p3.7小喇叭报警 * ;********************************************************************************

;* 【版权】 Copyright(C)深圳市学林电子有限公司 51c51 *

;* 【声明】 此程序仅用于学习与参考,引用请注明版权和作者信息! * ;* 【技术支持】请访问51c51/bbs/index.asp 官方论坛 *

;********************************************************************************/

;---------------------------- PWM EQU 7FH

WM赋初始值

OUT EQU P0 ;8个LED灯的接口 INCKEY EQU P1.4 ;K1,PWM值增加键。 DECKEY EQU P1.5 ;K2,PWM值减小键。 BEEP EQU P3.7

;---------------------------- ORG 0000H SJMP START ORG 000BH SJMP INTT0

ORG 001BH

SJMP INTT1 ORG 0043H

;---------------------------- ;主程序

;定时器0工作在模式1,定时器1工作在模式2。

;---------------------------- START:

MOV SP,#30H

MOV TMOD,#21H

MOV TH1,PWM ;脉宽调节 MOV TL1,#00H

MOV TH0,#0FCH ;1ms延时常数 MOV TL0,#066H ;频率调节 SETB EA SETB ET0

SETB ET1 SETB TR0

LOOP: MOV A,PWM ; JB INCKEY,LOOP1 ;增加键是否按下? CALL DELAY ;延时往抖动 JB INCKEY,LOOP1

CJNE A,#0FFH,PWMINC ;是否到最大值? CALL BEEP_BL ;是,蜂鸣器报警。 SJMP LOOP

PWMINC:

INC PWM ;调节脉宽(脉宽减小) SJMP LOOP

LOOP1: JB DECKEY,LOOP2 ;减小键是否按下? CALL DELAY ;延时往抖动 JB DECKEY,LOOP2

CJNE A,#02H,PWMDEC ;是否到最小值? CALL BEEP_BL ;是,蜂鸣器报警。 SJMP LOOP PWMDEC:

DEC PWM ;调节脉宽(脉宽增加)

LOOP2: SJMP LOOP

;------------------------------ ;T0中断服务子程序 (频率) ;控制定时器1中断

;------------------------------ INTT0:

CLR TR1

MOV TH0,#0FCH ;1ms延时常数 MOV TL0,#066H ;频率调节 MOV TH1,PWM SETB TR1

MOV OUT,#00H ;启动输出

RETI

;------------------------------ ;T1中断服务子程序 (脉宽) ;控制PWM脉冲宽度

;------------------------------ INTT1:

CLR TR1 ;脉宽调节结束

MOV OUT,#0FFH ;结束输出 RETI

;------------------------------ ;10ms延时子程序

;------------------------------ DELAY:

MOV R6,#50 DELAY1:

MOV R7,#100

DJNZ R7,$

DJNZ R6,DELAY1 RET

;----------------------------------------------- ;蜂鸣器响一声子程序

;----------------------------------------------- BEEP_BL:

MOV R6,#100 BL1: CALL BL2 CPL BEEP DJNZ R6,BL1 MOV R5,#25 CALL DELAY2 RET

BL2: MOV R7,#180 BL3: NOP

DJNZ R7,BL3 RET

DELAY2: ;延时R5×10MS MOV R6,#50 BL4: MOV R7,#100 BL5: DJNZ R7,BL5 DJNZ R6,BL4

DJNZ R5,DELAY2

RET

;--------------------------------------------------- END

ORG 0000H

START: MOV R5,#20 ;设置刷新速度(显示周期)(流动速度),计数用 MOV A,#0 ;初始化移位寄存器,有没有这句都行 MOV 30H,#81H ;设置第一帧为10000001 MOV 31H,#0c3h ;设置第二帧为11000011 MOV 32H,#0E7H ;设置第三帧为11100111 RUN: MOV P2,#0 ;显示第一帧即全亮 LCALL YS ;调用延时大约500微秒程序

MOV P2,30H ;显示第一帧即关闭0、7号LED其余灯都亮 LCALL YS ;调用延时

MOV P3,31H ;显示第二帧即关闭0、1、6、7号LED LCALL YS ;调用延时

MOV P2,32H ;显示第三帧即关闭0、1、2、5、6、7号LED LCALL YS ;调用延时

MOV P2,#0FFH ;显示第五帧即关闭全部LED,这句也是有没有都可以(到这里已经完整的显示了8个LED的状态即0、7号1/4亮,1、6号1/2亮、2、5号3/4亮,3、4号全亮即4级亮度)

DJNZ R5,RUN ;查看R5,确认是否一完成第一周期(屏)显示,如果没完成继续回到RUN出执行即重复20次

MOV A,30H ;将30H内容送入移位寄存器 RL A ;不带进位左移A的内容

MOV 30H,A ;将结果送回30H即00000011,为显示下一屏画面做准备 MOV A,31H ;以下同上 RL A MOV 31H,A MOV A,32H RL A MOV 32H,A

MOV R5,#20 ;初始化刷新速度(显示周期)的值,注意如果改运行速度别忘了改这里 AJMP RUN ;返回RUN进入下一屏(周期)显示 YS: MOV r6,#2 ;500微秒延时程序 D1: MOV R7,#250 DJNZ R7,$ DJNZ R6,D1 RET END

由于看着第一届单片机电子设计大赛的题目,所以最近构思了此程序的思路 。我想单片机初学者几乎都做的一个实验就是流水灯实验,因为大家都做,所以就觉得很简单,很多人对这个实验几乎不屑。其实要彻底的玩转这个实验也是很不简单的事情,不信看看你能不能应付我下面的实验题:

硬件前提:用单片机的I/O口控制8个LED,1 点亮,0 熄灭(不限单片机类型,51, AVR,PIC,430等等都可以,只要做出来效果就行) (1)第1,3,5,7个灯半亮,其余的全亮。

(2)第1个亮1/8,第2个亮2/8,第3个亮3/8,第4个亮4/8,第5个亮5/8,第6个亮6/8,第7个亮7/8,第8个全亮。

(3)来点小难的,所有的灯逐渐从暗到全亮,再由全亮到暗。

(4)最难的:8个灯从第一个开始依次渐亮,直到最后一个。再从最后一个起渐暗,直到第一个。如此循环往复。这才是真正的流水灯。

所以我想各位如果是看了下面程序 我想大家应该很好地去解决上面这个问题到底该怎样去写了吧!!

#include \"reg51.h\" #include unsigned int cd,dd; unsigned char cc,ee;

void led_int() interrupt 1 using 0 {

TH0=0xf1; TL0=0xf1; TR0=1; dd++; if(dd==8) {

if((cc==0x50)&&(ee==0)){cd=0;} if((cc==0)&&(ee==0x50)){cd=1;} if(cd){cc++;ee--;} else {cc--;ee++;} dd=0; } }

void delay(unsigned int i) {

unsigned int j; while(i--) {

for(j=0;j<0x20;j++); } }

void main() { cc=0; ee=0x50; TMOD=0x01; TH0=0xf0; TL0=0xf0 ; EA=1; ET0=1; TR0=1; while(1) {

P1=0x00; delay(ee); P1=0xff; delay(cc); } }

PWM(Pulse-width modulation)脉宽调制

PWM是使用数字手段来控制模拟输出的一种手段。使用数字控制产生占空比不同的方波(一个不停在开与关之间切换的信号)来控制模拟输出。额~~这个说的太专业了,还是说的通俗点。

以本次实验来看,端口的输入电压只有两个0V与5V。如我我想要3V的输出电压怎么办。。。有同学说串联电阻,对滴,这个方法是正确滴。但是如果我想1V,3V,3.5V等等之间来回变动怎么办呢?不可能不停地切换电阻吧。这种情况下。。。就需要使用PWM了。他是怎么控制的呢,对于arduino的数字端口电压输出只有LOW与HIGH两个开关,对应的就是0V与5V的电压输出,咱本把LOW定义为0,HIGH定义为1.一秒内让arduino输出500个0或者1的信号。如果这500个全部为1,那就是完整的5V,如果全部为0,那就是0V。如果010101010101这样输出,刚好一半一半,输出端口就感觉是2.5V的电压输出了。这个和咱们放映电影是一个道理,咱们所看的电影并不是完全连续的,它其实是每秒输出25张图片,在这种情况下人的肉眼是分辨不出来的,看上去就是连续的了。PWM也是同样的道理,如果想要不同的电压,就控制0与1的输出比例控制就ok~当然。。。这和真实的连续输出还是有差别的,单位时间内输出的0,1信号越多,控制的就越精确。

在下图中,绿线之间代表一个周期,其值也是PWM频率的倒数。换句话说,如果arduino PWM的频率是500Hz,那么两绿线之间的周期就是2毫秒。 analogWrite() 命令中可以操控的范围为0-255, analogWrite(255)表示100%占空比(常开), analogWrite(127)占空比大约为50%(一半的时间)。

**************************************************

* 51单片机模拟PWM输出控制灯的10个亮度级 ,还可驱动小舵机 ****************************************************/

#include

#define uint unsigned int #define uchar unsigned char

uchar PWM_T = 0; //占空比控制变量 //------------------------------------------------- void main(void) {

bit flag = 1; //渐亮渐熄. uint n;

TMOD = 0x02; //T0,定时模式2 TH0 = 241; //15us@12MHz TL0 = 241; // TR0 = 1; //启动.

ET0 = 1; //允许T0中断. EA = 1; //允许总中断. while(1) {

if(flag == 1) PWM_T++; //递增, 渐亮. else PWM_T--; //递减, 渐熄.

if(PWM_T >= 10) flag = 0; //为10,改为递减. if(PWM_T == 0) flag = 1; //到 0,改为递增.

for(n = 0; n < 300; n++); //延时. } }

//-------------------------------------------------

///////////////////定时器0中断模拟PWM//////////////////// timer0() interrupt 1 using 2 {

static uchar t; //静态变量t, 中断次数. t++; //

if(t == 10) { //中断了10次. P1 = 0x00; //就开灯. t = 0; }

else if(t == PWM_T) P1 = 0xff;

//不到10次,但是到了关灯的次数,就关灯.

}

//-------------------------------------------------

你把上述程序中的P1口输出,改成你的对595输出,试试看。

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- 517ttc.cn 版权所有 赣ICP备2024042791号-8

违法及侵权请联系:TEL:199 18 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务