脉冲宽度调制基本上是一个随时间变化而变化的方波。基本的PWM信号如下图所示。
有很多术语与PWM相关:
如图所示,Ton表示导通时间,Toff表示信号的关断时间。周期是导通和关断时间的总和,并按照以下公式计算: T t o t a l = T o n + T o f f T_{total}=T_{on}+T_{off} Ttotal=Ton+Toff
占空比用于计算为一段时间的导通时间。使用上面计算的周期,占空比计算为:
D = T o n T o n + T o f f = T o n T t o t a l D=\frac{T_{on}}{T_{on}+T_{off}}=\frac{T_{on}}{T_{total}} D=Ton+ToffTon=TtotalTon
analogWrite ( pin , value ) ;
//value − the duty cycle: between 0 (always off) and 255 (always on).
value - 占空比:0(始终导通)到255(始终关断)之间。
int ledPin = 9; // LED connected to digital pin 9
int analogPin = 3; // potentiometer connected to analog pin 3
int val = 0; // variable to store the read value
void setup() {
pinMode(ledPin, OUTPUT); // sets the pin as output
}
void loop() {
val = analogRead(analogPin); // read the input pin
analogWrite(ledPin, (val / 4)); // analogRead values go from 0 to 1023,
// analogWrite values from 0 to 255
}
例如:
analogWrite(5, 168);
上面的指令将使第5引脚输出3.3V电压,因为 168 255 × 5 ≈ 3.3 \frac {168}{255}\times {5} \approx 3.3 255168×5≈3.3
Arduino控制板预设采用1kHz 和 500Hz两组不同的PWM输出频率
Arduino的PWM输出频率是由ATmega微处理器内部的三个系统定时器:
下面的程序语句将Timer1(9、10端口输出)的PWM频率调整成31250Hz。
void setup() {
TCCR1B = TCCR1B & 0b11111000 | 0x01;
}
关于参数的详细说明以及频率对照表
物品 | 数量 |
---|---|
LED | 1个 |
电位器 | 1个 |
线性电位器是一个模拟量的电子元器件,模拟量和数字量有什么区别呢?简单的说,数字量只有0和1两种状态,对应的就是开和关,高电平和低电平。而模拟量则不一样,他的数据状态呈现线性状态例如1到1000。
我们将电位器接入了arduino控制板的A0模拟量检测口,arduino的模拟接口能够测量0-5V的电压,对应的返回值为0-1024,对电压变化的测量精度相对较高。
注意:本次试验我们使用的是精密线性电位器,电位器最好选用绕线的精密线性电位器,因为市面上的廉价的非线性电位器做这种实验时,数值漂移大,容易造成led闪烁,电阻成非线性变化,亮度变化不明显,容易产生和按钮调光实验那种层级感,影响试验效果。
3. 实验程序
byte potPin = A0;
byte ledPin = 11;
int potSpeed = 0;
byte val = 0;
void setup() {
pinMode(ledPin OUTPUT);
}
void loop() {
potSpeed = analogRead(potPin);
val = map(potSpeed, 0, 1023, 0, 255);
analogWrite(ledPin, val);
}
实验说明: 随机, 通过随机调整接在数字11端口的LED亮度,以及随机持续时间来模拟烛光效果。
random
byte rnd = random(200); //从0~199之间挑选一个数字,存入rnd
byte rnd = random(20, 50); //从20~49之间挑选一个数字,存入rnd
然而,Arduino每次挑选的数字并不是那么随意,为了提高不重复的比率,在每次执行random()函数之前,先执行randomSeed()函数,
byte ledPin = 11;
void setup() {
pinMode(ledPin, OUTPUT);
randomSeed(analogRead(A5); //空接端口的读取值很不稳定,适合于做randomSeed()参数。
}
void loop() {
analogWrite(ledPin, random(135) + 120);
delay(random(200));
}
实验说明: 接收用户输入的0~255数值来改变接在11引脚的LED亮度。
用户通过按键的输入值是字符串格式,而模拟输出指令所需要的参数是数字格式。有两种方法把字符或字符串转换成数字。
pwm = pwm * 10 + (_in - '0')
pwm = pwm * 10 + (_in - '0')
pwm = pwm * 10 + (_in - '0')
byte ledPin = 11;
void setup() {
Serial.begin(9600);
}
void loop() {
int pwm = 0;
byte _in;
if (Serial.available()) {
_in = Serial.read();
while (_in != '\n') {
if (_in >= '0' && _in <='9') {
pwm = pwm * 10 + (_in - '0');
}
_in = Serial.read();
}
if (pwm >255) pwm = 255;
analogWrite(ledPin, pwm);
}
}
setup()函数只需声明9号引脚为输出引脚,其他什么都不做。
调用analogWrite()函数(在loop函数内)需要两个参数:第一个为要操作的引脚,第二个时要写出的PWM 脉冲宽度 值。
为了让LED的熄灭和点亮有渐变效果,你需要逐渐将PWM值从0(全部时间不通电)逐渐增加到255(全部时间通电)。然后,再从255调到0,以完成一轮亮度渐变。在下方的工程中,PWM值用一个名为brightness的变量存储。loop函数每执行一次,就将brightness变量的值与fadeAmount变量的值相加,并将和再赋给brightness变量。
当brightness变量的值是0或255时,如果发现fadeAmount值为-5,它就应被设为5;若为5则设为-5。如此一来,下次进入循环时亮度就会跟着由弱转亮或由亮转弱。analogWrite()函数能极其快速的改变PWM值,因此在loop函数最后的delay控制了渐变速度。试试看改变delay的时间,看看它如何影响渐变效果。
代码:
int n=0;
void setup ()
{
pinMode(4,INPUT);
pinMode(6,OUTPUT); //该端口需要选择有#号标识的数字口
pinMode(10,INPUT);
}
void loop()
{
int up =digitalRead(4); //读取4号口的状态
int down = digitalRead(10); //读取10号口的状态
if (up==HIGH) //判断4号口目前是否是高电平
{
n=n+5; //每次累加值为5
if (n>=255) {
n=255;
} //限定最大值为255
analogWrite(6,n); //使用PWM控制6号口输出,变量n的取值范围是0-255
delay (300);
}
if (down==HIGH) //减少亮度
{
n=n-5;
if (n<=0) {
n=0;
}
analogWrite(6,n);
delay (300);
}
}
先声明一个空字符串变量,每次收到的新字符,存入字符串变量(data),以及变量i,每次接收到新的字符,就将它存入字符串变量,最后通过atoi()转换。
byte ledPin = 11;
void setup(){
Serial.begin(9600);
Serial.println("LED ready:");
}
void loop() {
int pwm;
char data[4];
byte i = 0;
char chr;
if (Serial.available()) {
while ((chr = Serial.read()) != '\n') {
if ( chr >= '0' && chr <= '9' && i < 3) {
data[i] = chr;
i++;
}
}
data[i] = '\0';
pwm = atoi(data);
if (pwm > 255) pwm = 255;
Serial.print("PWM: ");
Serial.println(pwm);
analogWrite(ledPin, pwm);
}
}
《LED亮度渐隐》你可以在Arduino IDE文件->工程库->示例程序->Analog菜单( File->Sketchbook->Examples->Analog)
LED亮度渐隐的例子向你展示如何通过PWM来输出近似的模拟信号。
脉宽调制技术(PWM)是通过数字信号的快速切换来获取近似的”模拟信号”的一种方式。数字信号有一个特点:它只有两个状态,高电平和低电平,因而它的输出在示波器上看起来不会有波动,都是方形的,因而我们把数字信号输出产生的数字信号称为方波。
方波是一种非正弦曲线的波形,通常会与电子和讯号处理时出现。理想方波只有“高”和“低”这两个值。电流或电压的波形为矩形的信号即为矩形波信号,高电平在一个波形周期内占有的时间比值称为占空比,占空比为50%的矩形波称之为方波。方波有低电平为零与为负之分,必要时,可加以说明“低电平为零”、“低电平为负”。【百度百科】
数字信号的快速开关可以产生近似的模拟信号。当一直处于打开状态时就是5V,当一直关闭时就是0V。通过改变固定一小段时间内高电平和低电平占的时间,我们就可以输出0V到5V的等效电压,也就是等效的模拟信号了。在这一小段时间内高电平所占的时间就叫做脉冲宽度,简称脉宽。为了获取不同的等效电压,你可以改变脉冲宽度(就是上面所说的改变固定一小段时间内高电平和低电平占的时间),对于脉冲宽度的调整就是所谓的脉宽调制技术(PWM)。 对引脚进行PWM操作,将PWM值从0逐渐调整到255,就相当于LED那条电路上的总电压从0V渐渐调整到了5V,LED的亮度也由最暗变最亮。
在这张图表中,绿色的线代表PWM的时间间隔(上文所提到的固定的一小段时间)。这个最大长度的倒数就是PWM的频率(频率等于时间的倒数)。因此,假如时间间隔是2ms,那么PWM频率就是500Hz左右。例如PWM频率为500Hz左右,则时间间隔是2ms。analogWrite() 输出的是0-5v的等效电压。若传入一个0-255的某个整数就代表引脚上将输出0V到5V的某个等效电压,例如
请将《LED亮度渐隐》一文中的例子下载到板子上。当例程开始运行后,请来回摇晃Arduino板。这样做的目的是为了让你不用示波器也能真切的看到PWM的真实面貌。因为人眼的视觉暂留让你在晃动过程中将点亮的板载LED看成连续的线条。当你对LED进行PWM操作时,这些线条的长度会根据脉宽变长变短。这样你就更加能体会到PWM的实质啦!
LED的工作电压约2V,但Arduino微电脑的输出电压是5V,我们应该在Arduino的输出和LED之间连接一个限流电阻,但有时我们把LED直接接在第13脚,这是因为Arduino处理器的输出电流不高(每个脚位可输出20mA,所有引脚最多40mA),第13引脚内接一个1kΩ电阻,因此不会烧毁LED。在实际的操作中,请串联一个220Ω~1kΩ的电阻,连接方式有:源流(source current)和潜流(sink current)两种。源流是当引脚的值为1时,电流由微处理器流出,经组件后至地端。潜流是当引脚的输出状态为0时,电流由Vcc流出,经组件后进入微处理器。无论哪一种接法,都要确认不要从微处理器流出或流入40mA以上的电流,否则该引脚可能会损毁。
在许多电工电子线路中,为了调节电流、电压的大小,改变控制电路的电性能,一般可使用可变电阻器(也称电位器、变阻器)来实现,通过调节改变电路中的电阻值来达到控制电流或电压的目的。 一般电位器有三只引脚,如图所示的是碳膜电位器内部结构图。其中中间引脚连接滑动片,其余两脚为固定臂,当滑动片在碳膜上滑动时,即可获得变化的电阻值,其阻值可在一定范围内连续可调。