文章目录

  • 1 简单认识 PWM
    • 1.1 PWM简介
    • 1.2 PWM的作用
    • 1.3 产生PWM的引脚
  • 2 使用PWM
    • 2.1 传统方式
    • 2.2 使用寄存器
  • 参考

1 简单认识 PWM

1.1 PWM简介

PWM(Pulse Width Modulation)是一种方波控制信号。采用不同的占空比来模拟“模拟输出”。基本的PWM信号如下图所示:

  • On-Time(导通时间) —— 时间信号的持续时间较长。
  • Off-Time(关断时间) —— 时间信号的持续时间较短。
  • Period(周期) —— 表示为PWM信号的导通时间和关断时间的总和。
  • Duty Cycle(占空比) —— 它表示为在PWM信号周期内保持导通的时间信号的百分比。

周期

Ton 表示导通时间,Toff 表示信号的关断时间。周期是导通和关断时间的总和,并按照以下公式计算:

占空比

占空比用于计算为一段时间的导通时间。使用上面计算的周期,占空比计算为:

常见的占空比如下图所示:

1.2 PWM的作用

  1. 提供模拟输出;如果数字输出被过滤,则其模拟电压将介于0%至100%之间。
  2. 生成音频信号。
  3. 控制灯光亮度,为电机提供变速控制。
  4. 生成调制信号,例如驱动用于远程控制的红外LED。

1.3 产生PWM的引脚

下图为 Arduino UNO 的 PWM 引脚号:


2 使用PWM

2.1 传统方式

1、analogWrite(pin,dutyCycle)

由1.3的图可知,在 UNO 中3,5,6,9,10,11 接口可以通过简单语句 analogWrite(pin, dutyCycle) 来实现一个指定占空比的 PWM。其中 pin 的值选择(3,5,6,9,10,11),dutyCycle 的值在0~255之间,0为占空比0%,255为占空比100%,对应电压从0到+5V。在调用 analogWrite() 函数之后,引脚将产生指定占空比的稳定方波,直到下一次调用 analogWrite() 或在相同引脚上调用 digitalRead()digitalWrite() 。但是这种方式 PWM 信号的频率是固定的默认值,大多数引脚上的 PWM 信号频率约为490 Hz。在 Uno 和类似的板上,引脚5和6的频率约为980Hz。Leonardo上的引脚3和11也以980Hz运行。提示:在使用PWM时,可以使用示波器检测一下频率。

示例代码:

// 引脚命名
# define analogPin 3
void setup()
{pinMode(analogPin,OUTPUT);
}
void loop()
{analogWrite(analogPin,100);        // 输出PWM,占空比为 100/255
}

2、手动实现 PWM

通过 delayMicroseconds() 手动实现频率可调的 PWM,也被称作数字IO轮转法,使用方法:

  1. 两次的digitalWrite输出状态必须相反;
  2. 可以用delay()实现毫秒级延迟,用delayMicroseconds()实现微秒级延迟。

示例代码:

void setup()
{pinMode(8, OUTPUT);                // 设置8号引脚为输出模式
}void loop()
{digitalWrite(8, HIGH);delayMicroseconds(100);          // 输出PWM,占空比为100/1000=10%digitalWrite(8, LOW);delayMicroseconds(1000 - 100);    // 修改这里的1000可以调整频率,总周期为1000us,所以频率为1000Hz.
}

上面这段代码会产生一个PWM=0.1的,周期为1ms的方波(1kHz),这种方式的优缺点很明显:

  1. PWM的比例可以更精确;
  2. 周期和频率可控制;
  3. 所有的pin脚都可以输出,不局限于那几个脚;
  4. 缺点:CPU干不了其他事情了;

2.2 使用寄存器

对 Arduino 时钟的介绍,请参考Arduino中断的使用。时钟一般可以有多种不同的运行模式。常见的模式包括“快速PWM”和“相位修正PWM”。

Arduino除了常用的比较匹配寄存器外,还有一些其他的寄存器用来控制时钟。

  1. TCCRnA 和 TCCRnB 就是用来设置时钟的计数位数。
  2. 脉冲生成模式控制位(WGM):用来设置时钟的模式
  3. 时钟选择位(CS):设置时钟的预定标器
  4. 输出模式控制位(COMnA和COMnB):使能/禁用/反相 输出A和输出B
  5. 输出比较器(OCRnA和OCRnB):当计数器等于这两个值时,输出值根据不同的模式进行变化

不同时钟的这些设置位稍有不同,所以使用的时候需要查一下资料。其中Timer1是一个16位的时钟,Timer2可以使用不同的预定标器。

1、快速PWM

对于快速 PWM 来说,时钟都是从0计数到255。当计数器=0时,输出高电平1,当计数器等于比较寄存器时,输出低电平0。所以输出比较器越大,占空比越高。这就是传说中的快速PWM模式。后面的例子会解释如何用OCRnA和OCRnB设置两路输出的占空比。很明显这种情况下,这两路输出的周期是相同的,只是占空比不同。

参考示例

下面这个例子以 Timer2 为例,把 Pin3 和 Pin11 作为快速PWM的两个输出管脚。其中:

  • WGM 的设置为 011,表示选择了快速PWM模式;
  • COM2A 和 COM2B 设置为 10,表示A和B输出都是非反转的 PWM;
  • CS的设置为100,表示时钟周期是系统时钟的1/64;
  • OCR2A和OCR2B分别是180和50,表示两路输出的占空比;
pinMode(3, OUTPUT);
pinMode(11, OUTPUT);
TCCR2A = _BV(COM2A1) | _BV(COM2B1) | _BV(WGM21) | _BV(WGM20);
TCCR2B = _BV(CS22);
OCR2A = 180;
OCR2B = 50;
// _BV(n)的意思就是1< COM2A1,表示COM2A的第1位为1,由于寄存器一般是倒序,最后一位为0,所以_BV(COM2A1)表示COM2A = 10

在Arduino Due 开发板,上面这几行代码的结果为:

  • 输出 A 频率: 16 MHz / 64 / 256 = 976.5625Hz
  • 输出 A 占空比: (180+1) / 256 = 70.7%
  • 输出 B 频率: 16 MHz / 64 / 256 = 976.5625Hz
  • 输出 B 占空比: (50+1) / 256 = 19.9%

频率的计算里都除以了256,这是因为除以64是得到了时钟的计数周期,而256个计数周期是一个循环,所以PWM的周期指的是这个循环。另外,占空比的计算都加了1,这个是因为从0开始计数。

2、相位修正PWM

另外一种 PWM 模式是相位修正模式,也有人把它叫做“双斜率PWM”。这种模式下,计数器从0数到255,然后从255再倒数到0。当计数器在上升过程中遇到比较器的时候,输出0;在下降过程中遇到比较器的时候,输出1。

相位修正PWM的例子

继续以 Timer2 为例,设置 Pin3 和 Pin11 为输出管脚。其中WGM设置为001,表示相位修正模式,其他位设置和前面的例子相同:

pinMode(3, OUTPUT);
pinMode(11, OUTPUT);
TCCR2A = _BV(COM2A1) | _BV(COM2B1) | _BV(WGM20);
TCCR2B = _BV(CS22);
OCR2A = 180;
OCR2B = 50;

在Arduino Due开发板,上面这几行代码的结果为:

  • 输出 A 频率: 16 MHz / 64 / 255 / 2 = 490.196Hz
  • 输出 A 占空比: 180 / 255 = 70.6%
  • 输出 B 频率: 16 MHz / 64 / 255 / 2 = 490.196Hz
  • 输出 B 占空比: 50 / 255 = 19.6%

**提示:**与快速 PWM 相比,相位校正 PWM 将频率除以2,因为定时器同时上下运行。有些令人惊讶的是,频率被255除,而不是256除,占空比计算不加一作为快速脉宽调制。

一般来说,普通用户是不需要设置这些时钟参数。Arduino 默认有一些设置,所有的时钟周期都是系统周期的1/64。Timer0 默认是快速 PWM,而 Timer1 和 Timer2 默认是相位修正 PWM。具体的设置可以查看Arduino源代码中writing.c的设置。
        需要特别特别注意的是,Arduino的开发系统中,millis()和delay()这两个函数是基于Timer0时钟的,所以如果你修改了Timer0的时钟周期,这两个函数也会受到影响。直接的效果就是delay(1000)不再是标准的1秒,也许会变成1/64秒,这个需要特别注意。
        如果想要修改时钟频率,以及时钟的计数上限,请参考文章后面的链接。


参考

  1. 调整 PWM 频率: https://playground.arduino.cc/Main/TimerPWMCheatsheet/
  2. Arduino PWM 的秘密——英文教程:http://www.righto.com/2009/07/secrets-of-arduino-pwm.html
  3. Arduino PWM 的秘密——中文教程:http://www.diy-robots.com/?p=852

Arduino基础篇(四)-- 如何玩转Arduino的PWM相关推荐

  1. Arduino基础篇(一)-- 打开Arduino的大门

    文章目录 1 什么是Arduino 2 为什么选择Arduino作为开发平台 3 Arduino硬件 3.1 Arduino开发板的类型 3.2 不同开发板的对比 4 Arduino软件 4.1 ID ...

  2. Arduino基础篇(七)-- 如何使用DS18B20数字温度传感器(基于OneWire和DallasTemperature库)

    温度传感器是指能感受温度并转换成可用输出信号的传感器.按测量方式分为接触式和非接触式,按照传感器材料及电子元件分为热电阻和热电偶两类,按照工作原理分为模拟式和数字式.本篇主要介绍数字温度传感器 DS1 ...

  3. Arduino基础篇(二)-- 常用的基本函数

    文章目录 1 程序结构 2 数字输入输出 3 模拟输入输出 4 高级输入输出 5 时间控制 6 数学函数 7 串口通信 8 IIC总线的使用--Wire类库 9 SPI总线的使用--SPI类库 10 ...

  4. Arduino基础篇(九)-- 无刷直流电机转速和方向控制

    本文选择Arduino MEGA 2560开发板做调试,通过调整PWM的占空比,控制BLDC3525,内置有感有霍尔驱动,实现对无刷直流电机的转速控制,通过调整数字口输出高低电平,从而实现电机方向控制 ...

  5. Arduino基础篇(十)-- 电源模块设计集合

    文章目录 1 5V电源模块 2 3.3V电源模块 3 5v&3A电源模块 4 1.9V电源模块 5 5V电源模块 参考 1 5V电源模块 参考电路: 电路说明: 本电路采用常见的稳压芯片LM7 ...

  6. 前端开发之JavaScript基础篇四

    主要内容: 1.定时器 2.正则表达式入门 3.元字符 4.正则表达式实战运用 一.定时器 javaScript里主要使用两种定时器,分别是:setInterval()和setTimeout(). 1 ...

  7. 转载:谢谢原作者:块设备驱动实战基础篇四 (逐渐成型,加入ioctl通信机制)

    1.6介绍一种内核与用户空间通信的方法-misc设备ioctl机制 块设备驱动开发中往往需要配合用户态的管理程序工具,管理我们的块设备,此时我们需要涉及用户空间程序与块设备通信的方法,ioctl机制就 ...

  8. c if语句多个条件判断顺序_Java中的流程控制语句 (基础篇四)

    流程控制就是对事物次序的布置和安排,在程序中就是对代码执行次序的安排和控制 程序中的流程控制主要有三种:顺序流程.选择流程.循环流程. 顺序流程:比如打印输出的代码按照指定的顺序结构依次排序,打印的结 ...

  9. java中的四个跳转语句_Java中的流程控制语句 (基础篇四)

    流程控制就是对事物次序的布置和安排,在程序中就是对代码执行次序的安排和控制 程序中的流程控制主要有三种:顺序流程.选择流程.循环流程. 顺序流程:比如打印输出的代码按照指定的顺序结构依次排序,打印的结 ...

最新文章

  1. npm升级package.json依赖包到最新版本号
  2. Bzoj1269 [AHOI2006]文本编辑器editor
  3. boost::statechart模块实现状态转换测试
  4. IOS之学习笔记十四(协议的定义和实现)
  5. git pull不同步_git回退版本,再返回最新分支git pull失败的解决经验
  6. linux运行core控制台程序,VisualStudioCode创建的asp.net core控制台程序部署到linux
  7. 【css】响应式布局 @media媒介 适配平板手机
  8. 30秒内限制函数只被调用一次
  9. Java方法中数组_Java中数组常用方法的总结
  10. 运算放大器基本公式_还在被三阶/四阶/运算放大器滤波器PLL这些概念困扰?这篇文章帮你搞懂它...
  11. win7 安装 memcached
  12. Dave一款gitee热搜项目,不需node基础也能直接部署node
  13. css选择器优先顺序
  14. java显示字母数字组合_Java字母加数字组合比较大小
  15. 人类视觉计算理论经典著作,豆瓣评分9.7,中文版惊鸿面世
  16. HIbernate Session 线程安全的问题
  17. 合并多个js,css文件的方法 - 在服务端合并和压缩JavaScript和CSS文件
  18. STM32之继电器驱动(上下拉电阻)
  19. 《 Visual c++2013入门经典》(Ivor Horton,7th)2.15练习编程验证
  20. 虚拟机中无ens33文件的解决办法

热门文章

  1. 【HTML 教程】HTML 语言简介
  2. Linux下查看图片中某点的像素X、Y坐标
  3. 顶级的JavaScript框架、库、工具及其使用
  4. ndk开发app!靠这份Android知识点PDF成功跳槽,再不刷题就晚了!
  5. java开发中elasticsearch 的简单使用
  6. android经典机型,魅族史上的经典机型大盘点 魅族 17 值得期待吗?
  7. EAIDK-610入门修炼ing系列二MIPI摄像头安装
  8. 第五代 智能计算机和生物计算机
  9. 基于Springboot的仿天猫电商系统
  10. python编程求长方形的面积_小练习 计算长方形的面积和周长