在工控行业,PWM信号可以用来调节电机转速、调节变频器以及BLDC电机驱动等;在LED照明行业,可以通过PWM来控制LED灯的亮暗变化;还可以通过PWM信号来控制无源蜂鸣器发出简单的声音以及实现功率继电器的线圈节能等。
PWM(Pulse Width Modulation,脉冲宽度调制)为脉冲周期固定、占空比可调的信号如图所示。
设计并制作PWM信号产生电路,具体要求如下:
1.PWM信号的频率为2kHz;
2.PWM信号的占空比在0~100%之间可调,分辨率不大于1%;
3.用PWM信号驱动发光二极管,能够观察到PWM信号占空比的变化。
★发挥部分:在完成基本功能的基础上,实现上呼吸灯功能。
PWM是利用微处理器的数字输出来对模拟电路进行控制,控制方式就是对逆变电路开关器件的通断进行控制,使输出端得到一系列幅值相等的脉冲,用这些脉冲来代替正弦波或所需要的波形。
信号从高电平到低电平再回到高电平所需要的时间称之为周期。
一秒内有多少这样的周期就是pwm的频率。
f=1/T;
占空比是一个脉冲周期内高电平保持的时间与该pwm时钟周期的比值(高电平所占的时间比例)
举个
第一个周期内占空比为80%,第二个周期内占空比为40%。
对于占空比为80%,平均电压就是4v,总的来说就是占空比越大平均电压就越大。
皇上儿,燕国使者原理图奉上☝
报菜名:(51的芯片+晶振+电容+按键+74hc573+74hc138+74hc02+拨码开关+发光二极管+示波器)
晶振电路的作用是为电路提供基本的时钟信号,使其工作在稳定的频率范围内,从而保持各个部分之间的同步。驱动数字电路运转是时钟信号,时序电路都需要一个外部时钟信号来驱动,完成记时和计数
防止程序跑飞,接上复位电路按下按键,程序从头开始跑,当单片机一上电,C3击穿相当于导线,直接将vcc接入rst置为1,发生复位,当按键S1按下将电容短路,rst置一复位
1~8:P1对应的IO口(可编程输入输出口)
9:RST复位引脚,引脚上出现2个机器周期的高电平将使单片机复位。
10~17:P3对应的IO口。
18:XTAL2晶振输出端。
19:XTAL1晶振输入端。
20:GND电源地。
21~28:P2对应的IO口。
29:PSEN外部存储器读选通信号引脚。
30:ALE/PROG地址锁存允许信号引脚。
31:EA/VPP程序存储器的内外部选通,接低电平从外部程序存储器读指令,如果接高电平则从内部程序存储器读指令。
32~39:P0对应的IO口。
40:VCC电源。
74hc138让使能端有效,使得74hc138正常工作,A,B,C分别接25,26,27引脚,通过芯片给p2口的高三位赋值选择不同的通道,这里我们不用数码管显示,只看灯的情况,所以将P2口的高三位置100,选择4通道,74hc138输出低有效,选四通道,其余全是1,Y4=0,由于SW1拨码开关接地,74hc02单输入非门,输出则是1.
74hc573锁存器,由Y4c通道送来个高电平,使其使能端有效,74hc573正常工作,有没有人有这样的疑惑?????为什么74hc138译码器输出有不同的通道,每个138输出端口连接这每个573的LE使能端,总结一下就是P2高3位决定138输出选择哪个端口为低有效,然后通过非门将数据置1对应的573锁存器有效,将P0口的数据输出,这里的P0口复用解决了io口不够用的问题。你想想如果数码管位选段,数码管片选段,二极管,用不同的io口的话,单片机那几个引脚完全不够用的。
二极管D1接的P0最低位如果P0^0=0,二极管导通放光,对应的示波器A为低电平,
二极管D2接的P0次低位如果P0^1=0,二极管导通放光,对应的示波器B为低电平.
当对应的按键按下,单片机对应的io口电平就会被拉低。
#include
sbit S7=P3^0;
sbit L1=P0^0;
sbit S4=P3^3;
sbit L2=P0^1;
unsigned char PWMcnt1=0;//进入中断3的次数
unsigned char PWMduty1=0;//D2的占空比
unsigned char PWMuad=0;//变亮模式还是变暗模式
unsigned char S4no=0;//S4按下的次数,S4没有按下,不会进入呼吸部分
unsigned char keypressed=0;//S4按下置1,S4松开置0
unsigned char times=0;
unsigned char stat=0;//按下S7一次改变对应的状态(不同的状态占空比不同)
unsigned char PWMduty;//D1的占空比
void Delay(unsigned int t)//延迟去抖动
{while(t--);}
void Selecthc138(unsigned char channel)
{switch(channel)
{case 4:P2=(P2&0x1f)|0x80;break;//P2高三位置100
}}
void show()//按键控制函数
{if(S7==0)//S7按一次占空比改变10%
{Delay(20);
if(S7==0)
{ if(stat==0)
{stat=1;PWMduty=1;TR0=1;L1=0;}//第一次按下S7的时候开始计时器0开始计时L1=0就是L1灯亮的时候,对应的就是高电平,占空比的时候
else if(stat==1)//每次按下的时候stat就会改变成下一种状态再次按下的时候就是对应的改变后的状态
{stat=2;PWMduty=2;}
else if(stat==2)
{stat=3;PWMduty=3;}
else if(stat==3)
{stat=4;PWMduty=4;}
else if(stat==4)
{stat=5;PWMduty=5;}
else if(stat==5)
{stat=6;PWMduty=6;}
else if(stat==6)
{stat=7;PWMduty=7;}
else if(stat==7)
{stat=8;PWMduty=8;}
else if(stat==8)
{stat=9;PWMduty=9;}
else if(stat==9)
{stat=0;PWMduty=0;TR0=0;L1=1;}}//关灯,定时器0停止计时
}while(S7==0);
if(S4==0)//呼吸灯按键
{Delay(20);//软件去抖动
。
if(S4==0)
{while(S4==0) keypressed=1;
S4no++;
keypressed=0;
if(S4no>2)
{S4no=1;}}}
}
void Inittime()//中断初始化函数
{ TMOD=0x11;//两个定时器都是定时模式
TH0=(65536-50)/256;
TL0=(65536-50)%256;
TH1=(65536-1000)/256;
TL1=(65536-1000)%256;
ET0=1;//定时器0的使能开关
ET1=1;//定时器1的使能开关
EA=1;//使能总开关
TR1=1;//定时器1开始计时
}
unsigned char PWMcnt=0;//进入中断1的次数
void Servive() interrupt 1// 中断服务函数中断1
{TH0=(65536-50)/256;//高八位
TL0=(65536-50)%256;//16位不重装模式就要自己重装,低八位
PWMcnt++;
if(PWMcnt==PWMduty)
{L1=1;}
else if(PWMcnt==10)
{L1=0;PWMcnt=0;}
}
void Servive1() interrupt 3 // 中断服务函数中断3
{ TH1=(65536-1000)/256;
TL1=(65536-1000)%256;
if(S4no==0)
{L2=0;return;}//为什么不会进入呼吸部分,这里如果S4no==0的话,直接return,跳出中断
PWMcnt1++;
if(PWMcnt1<PWMduty1)
{L2=0;}
else if(PWMcnt1<=10)
{L2=1;}
else
{PWMcnt1=0;
if(keypressed==0)
{times++;}}
}
void LEDcol()
{if(times==5)
{times=0;
if(PWMuad==0)
{PWMduty1++;
if(PWMduty1>10)
{PWMduty1=10;PWMuad=1;}}
else if(PWMuad==1)
{PWMduty1--;
if(PWMduty1==255)
{PWMduty1=0;PWMuad=0;
}}}
}
void main()
{Inittime();
while(1)//为了使无限演示结果,将函数写在循环里面
{show();
LEDcol();
}
}
必杀技:说了这么多,说人话就是使用单片机的定时器,在一个周期内控制高电平的时间,就是占空比,灯的亮度越亮就是占空比越大,高电平时间就是对应灯阴极接口为低电平的时间。
2000hz的频率要怎么调呢???
用定时器0,2000hz的频率对应周期就是500us,
呼吸灯是用的定时器1实现的,按下S4,D2发光二极管开始呼吸。
呼吸灯部分代码解释:当S4按下一次,S4no==1;定时器1设置的时间是1ms进入中断一次,
void Servive1() interrupt 3 // 中断服务函数中断3
{ TH1=(65536-1000)/256;
TL1=(65536-1000)%256;
if(S4no==0)
{L2=0;return;}//为什么不会进入呼吸部分,这里如果S4no==0的话,直接return,跳出中断
PWMcnt1++;
if(PWMcnt1<PWMduty1)
{L2=0;}
else if(PWMcnt1<=10)
{L2=1;}
else
{PWMcnt1=0;
if(keypressed==0)
{times++;}}
1ms进入中断pwmcnt1==1,此时pwmduty1还是0
else if(PWMcnt1<=10)
{L2=1;}
当进入10次这个的时候,接下来进入中断pwmcnt1==11,执行一次这个
else
{PWMcnt1=0;
if(keypressed==0)
{times++;}}
pwmcnt1置0,times+1,当进入50次的时候,times==5,进入
void LEDcol()
{if(times==5)
{times=0;
if(PWMuad==0)
{PWMduty1++;
if(PWMduty1>10)
{PWMduty1=10;PWMuad=1;}}
else if(PWMuad==1)
{PWMduty1--;
if(PWMduty1==255)
{PWMduty1=0;PWMuad=0;
}}}
}
每50ms,pwmduty1+1,pwmduty1越大占空比就越大,这里是逐渐变亮的过程,每50ms就好像S7按下一次开关一样,500次的时候,接下来进去时PWMuad=1;
else if(PWMuad==1)
{PWMduty1--;
if(PWMduty1==255)
{PWMduty1=0;PWMuad=0;
}}
每50ms,pwmduty1-1,pwmduty1越小占空比就越小,这里是逐渐变暗的过程,接下来进去时PWMuad=0;以此循环实现呼吸灯的效果,这里逐渐变亮需要500ms,逐渐变暗需要500ms.在每50ms的时间内pwmduty1是一样的,所以灯的亮度是一样的,每50ms变亮一点
20230803_191206
点击cursors看他的周期
620us=0.62ms;
f=1/T=1612hz
这里试过100hz的误差不大,接近一百赫兹,但是如果是2000hz,我勒亲娘,误差好大,不知道是哪里有问题。
本学期我们专业,在学习完课本上的知识以后,我们做了课程设计,课程设计是培养学生综合运用所学知识,发现,提出,分析和解决实际问题,锻炼实践能力的重要环节,是对学生实际工作能力的具体训练和考察过程。通过这次电子课程设计,我不仅巩固了在课本上学到的知识,而且还学到了很多课本之外的知识。在这次课程设计中我收获颇丰,无论是在培养自己的实验动手能力还是培养自己的性情方面。我明白了要去做好一个东西最重要的是心态,也许在你拿到题目时会觉得很困难,但是只要你充满信心,认真去思考,一步一个脚印去实现它,你就肯定会完成课程实践的。在实践的过程中,我也遇到了很多困难,发现我自己在学习课本上知识的时候并没有深刻的去理解,掌握的只是很浅显的东西,所以在时遇到很多以前在书本上没有遇到过的实际的问题,只要一个小小的错误,就无法成功的完成实践的要求。
分享到此结束,如果你觉得不错的话,记得点个赞哦!!个人理解,如果有不对的地方,求大佬多多指教,阿里嘎多!!点赞大佬offer拿到手软哈哈