0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

PWM是什么?有什么用?PWM能玩出什么花样?

冬至子 来源:ZYuanBlogs 作者:激沄RagingWaves 2023-10-31 17:35 次阅读

一、PWM是什么?有什么用?

PWM指的是脉冲宽度调制技术,通过对脉冲宽度的调节可以达到通信(如控制舵机)、模拟“模拟输出”(如调节灯的亮度),前者在以后再结合舵机来讲,本文侧重讲后者。

图片

首先,我们来了解几个概念:

1、PWM频率、PWM周期

图片

这是一个约为50Hz的PWM输出波形

图片

这个PWM的周期约为20ms

PWM频率指1秒的时间里PWM运行的次数;

PWM周期指一次完整的PWM输出所使用的时间。

2、占空比

图片

从上往下,占空比分别为25%、50%、75%

占空比指在一个周期内接通的时间占这一周期的比例。

明白这些后,恭喜你已经基本掌握PWM的原理了!

我们知道单片机的IO口只有0和1两种输出状态,只能控制LED的亮与灭,如果我们想要得到下面这样的输出效果,思考一下,结合PWM我们可以怎么做?

图片

你可能已经想到了,IO口保持高电平(1)时LED最亮,此时电压为5V(以5V电压工作的单片机为例),如果在里面插入低电平,输出10101010...不就相当于输出2.5V了吗?

不严谨地说,这样使用PWM确实能达到“模拟输出”的效果,但如果真的需要模拟输出,单单这样是不够的(所以前面标了引号),在此不进行细说。

二、怎样设计PWM程序?

我们先来构造这么一个框架:

1、确定一个单位时间t,每个t内固定地输出0或1;

2、过了n个t完成一个PWM周期;

3、使用程序控制一个周期内输出1的数量为m,输出0的数量为(n-m)。

有了上面的框架,设计程序就不难了:

我们可以使用定时器,每隔一定的时间进入一次中断,并记录进入中断的次数x,直到完成一次PWM周期,将x归零;

设我们所需要的PWM输出占空比为y,当x<=y时输出高电平,x>y时输出低电平。

这样,我们的程序基本就设计出来了,是不是很简单?(〃'▽'〃)

在正式编写程序前,我们还需要考虑一些小问题:

因为51单片机的运行频率不高,PWM的频率也不能设计得太高,过于频繁地进入中断也会影响程序的正常运行。

在下面的例程中,我所设置的定时器中断的间隔为0.1ms,每20ms完成一次PWM周期。

在这一小节的最后,我们整理一下思路,可以得到下面的流程图:

图片

三、写个程序试试看!

按上面的流程图,我们就可以写一个控制LED亮度的程序了:

#include < reg52.h >


#define PWM_T 200                      //产生中断的时间,因为是24MHz,200即100微秒(0.1毫秒)
#define LED P1


int PWM_count0 = 0;                    //进入中断的次数
int PWM0 = 100;                        //控制PWM的占空比,下同
int PWM1 = 170;
int PWM2 = 188;
int PWM3 = 198;


sbit LED0 = P1^0;                      //LED引脚定义,下同
sbit LED1 = P1^1;
sbit LED2 = P1^2;
sbit LED3 = P1^3;


void PWM_Start()                      //PWM初始化函数,打开了定时器0
{
  EA = 1;
  ET0 = 1;
  TMOD = 0x09;
  TR0 = 1;


  TH0 = (65536-PWM_T)/256;
  TL0 = (65536-PWM_T)%256;
}


void main()
{
  PWM_Start();                        //PWM开始运行


  while(1)
  {
    if(PWM_count0 <= PWM0)            //调节LED0的亮度
    {
      LED0 = 1;
    }
    else
    {
      LED0 = 0;
    }


    if(PWM_count0 <= PWM1)            //调节LED1的亮度
    {
      LED1 = 1;
    }
    else
    {
      LED1 = 0;
    }


    if(PWM_count0 <= PWM2)            //调节LED2的亮度
    {
      LED2 = 1;
    }
    else
    {
      LED2 = 0;
    }


    if(PWM_count0 <= PWM3)            //调节LED3的亮度
    {
      LED3 = 1;
    }
    else
    {
      LED3 = 0;
    }
  }
}


void Timer0() interrupt 1
{
  TH0 = (65536-PWM_T)/256;
  TL0 = (65536-PWM_T)%256;


  PWM_count0++;
  if(PWM_count0 == 200)                //完成了一个PWM周期,计数变量清零
  {
    PWM_count0 = 0;
  }
}

把上面的程序编译后下载到开发板上:

图片

小提示:人眼对亮度的感觉不是线性变化的,因此LED0与LED1虽然占空比相差较大,但肉眼感觉亮度不相上下,感兴趣的可以去研究一下。

用逻辑分析仪收集一下IO口的输出信息

图片

黄框里的为一个PWM周期

上面的程序还有一些需要注意的地方:

1、记得加while循环,因为PWM输出是持续的,没有循环就只会进行一个周期;

2、晶振频率建议设置为24MHz,12MHz也可以,相应地定时器中断时间也要更改。

我们可以将上面的程序进一步优化,如果我们把if语句写成子函数,通过参数控制占空比,返回值控制0和1的输出,程序会简化很多:

#include < reg52.h >


#define PWM_T 200                      //产生中断的时间,因为是24MHz,200即100微秒(0.1毫秒)
#define LED P1


int PWM_count0 = 0;                    //进入中断的次数
int PWM0 = 100; //去掉7~10行                       //控制PWM的占空比,下同
int PWM1 = 170;
int PWM2 = 188;
int PWM3 = 198;


sbit LED0 = P1^0;                      //LED引脚定义,下同
sbit LED1 = P1^1;
sbit LED2 = P1^2;
sbit LED3 = P1^3;


void PWM_Start()                      //PWM初始化函数,打开了定时器0
{
  EA = 1;
  ET0 = 1;
  TMOD = 0x09;
  TR0 = 1;


  TH0 = (65536-PWM_T)/256;
  TL0 = (65536-PWM_T)%256;
}


int PWM(int PWM_value)                //控制PWM输出的子函数
{
  if(PWM_count0 <= PWM_value)
  {
    return 1;
  }
  else
  {
    return 0;
  }
}


void main()
{
  PWM_Start();                        //PWM开始运行


  while(1)
  {
    LED0 = PWM(100);                  //调节LED0的亮度
    LED1 = PWM(170);                  //调节LED1的亮度
    LED2 = PWM(188);                  //调节LED2的亮度
    LED3 = PWM(198);                  //调节LED3的亮度
  }
}


void Timer0() interrupt 1
{
  TH0 = (65536-PWM_T)/256;
  TL0 = (65536-PWM_T)%256;


  PWM_count0++;
  if(PWM_count0 == 200)                //完成了一个PWM周期,计数变量清零
  {
    PWM_count0 = 0;
  }
}

可以看到,写成子函数后调用PWM输出方便了不少。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 51单片机
    +关注

    关注

    269

    文章

    5649

    浏览量

    120849
  • 定时器
    +关注

    关注

    23

    文章

    3148

    浏览量

    112117
  • 脉冲宽度调制

    关注

    7

    文章

    74

    浏览量

    13572
  • 逻辑分析仪
    +关注

    关注

    3

    文章

    200

    浏览量

    22918
  • PWM输出
    +关注

    关注

    1

    文章

    62

    浏览量

    5060
收藏 人收藏

    评论

    相关推荐

    #工作原理大揭秘 #单片机 pwm波,分辨率100的pwm

    PWM
    陈夫斯基
    发布于 :2022年11月16日 20:20:37

    PWM应用

    PWM
    橙群微电子
    发布于 :2023年03月09日 09:11:48

    PWM调光真的护眼吗?

    PWM
    YS YYDS
    发布于 :2023年06月10日 22:53:57

    PWM 呼吸灯

    PWM
    YS YYDS
    发布于 :2023年07月04日 21:32:53

    PWM信号测量模式-同时测量周期和占空比#STC32G12K128 #PWM

    PWM
    学习电子知识
    发布于 :2023年07月17日 01:14:49

    【FPGA设计实例】JTAG让你的FPGA玩出新花样

    本帖最后由 eehome 于 2013-1-5 09:46 编辑 JTAG让你的FPGA玩出新花样第1部分:JTAG是什么?第2部分:JTAG如何的工作第3部分:查询JTAG链第4部分:运行
    发表于 03-20 15:03

    stc单片机输出pwm,旁边再连上enc28j60模块什么用

    芯片的stc12c5410ad,这芯片输出pwm,然后再连上enc28j60网络模块,这网络模块什么用
    发表于 05-11 21:25

    这个电路干什么用的?PWM_P接的是PMOS;PWMP接的是单片机?

    这个电路干什么用的?PWM_P接的是PMOS;PWMP接的是单片机。这是移动电源上的一个电路。
    发表于 07-09 22:01

    互补PWM什么用啊,感觉浪费了好几个引脚啊,我想单独用某个脚输出PWM波怎么调啊

    互补PWM什么用啊,感觉浪费了好几个引脚啊,我想单独用某个脚输出PWM波怎么调啊
    发表于 07-23 02:03

    请问PWM转为线性电压什么用

    单片机输出PWM信号,经过RC变换再经过跟随器输出线性电压,这样
    发表于 04-16 06:48

    什么是PWM信号?怎么通过STM32来输出一个PWM信号呢?

    什么是PWM信号?这个信号什么用呢?它是怎么实现控制小灯或者电机呢?怎么通过STM32来输出一个PWM信号呢?
    发表于 07-06 07:00

    如何把手中的这颗LED灯玩出新花样

    学会了如何点亮LED灯,那么接下来的就是如何把手中的这颗LED灯玩出新花样,在上一篇文章的基础上这次我加入了按键去抖和LED呼吸灯的程序。根据电路原理图可知,按键一端分别连接PA0和PA1,另一端连接GND。也就是说当PA0或PA1按下的时候,按键与GND导通,使得IO端口短接到...
    发表于 01-24 07:35

    用vivoNEX双屏版玩游戏怎么样

    双屏版独特的设计在拍照方面玩出花样,而作为一名游戏玩家,我发现它还能玩出更多花样
    的头像 发表于 01-07 10:07 1.3w次阅读

    Tivoo像素音箱评测 音箱上也能玩出新花样

    蓝牙音箱品牌很多,但是能玩出花的不多。
    的头像 发表于 03-12 10:33 2379次阅读

    MWCS 2023丨5G时代 还能玩出什么花?

    原文标题:MWCS 2023丨5G时代 还能玩出什么花? 文章出处:【微信公众号:中兴通讯】欢迎添加关注!文章转载请注明出处。
    的头像 发表于 06-26 15:55 180次阅读