arduino教程- 03.使用pwm技术

目录

      • 主要内容
      • 7.1 PWM的基本原理
      • 7.2 基本PWM信号
        • 周期
        • 占空比
      • 7.3 调节电压变化
      • 7.4 模式输出(PWM)指令和默认频率
        • 7.4.1 analogWrite()函数
        • 7.4.2 analogWrite()函数语法
          • 示例
      • 7.5 pwm频率
        • 7.5.1 默认频率
        • 7.5.2 改变PWM的输出频率
      • 任务1:调光器
      • 任务2:随机数字与烛光效果
        • 随机指令:
        • 实验程序:
      • 任务3: 通过串口调整灯光亮度
        • 比如:Arduino收到字符串 '168\n'
      • 活动4:按钮PWM控制LED亮度
        • 实现说明
      • 活动5:使用atoi()转换字符串成数字
        • 实验说明
        • 实验程序
      • 3.7 补充阅读材料:
        • 1. PWM
        • 2. LED的正确接法
        • 3. 电位器:

脉冲宽度调制或PWM是用于改变脉冲串中的脉冲宽度的常用技术。PWM有许多应用,如控制伺服和速度控制器,限制电机和LED的有效功率。

主要内容

  1. Arduino输出模拟信号,也就是可变电压输出。
  2. pwm技术原理及实现方法
  3. 利用不同技术实现pwm

7.1 PWM的基本原理

脉冲宽度调制基本上是一个随时间变化而变化的方波。基本的PWM信号如下图所示。
原理图

7.2 基本PWM信号

有很多术语与PWM相关:

  • On-Time(导通时间) - 时间信号的持续时间较长。
  • Off-Time(关断时间) - 时间信号的持续时间较短。
  • Period(周期) - 表示为PWM信号的导通时间和关断时间的总和。
  • Duty Cycle(占空比) - 它表示为在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

7.3 调节电压变化

  1. 改变电路中的电压。
  • 缺点:体积增大,电能变成热能
  1. 省电又环保的PWM变频技术
  • 称为:脉冲宽度调制(Pulse Width Modulation)
  • 通过改变脉冲宽度,将能仿真模拟电压高低变化的效果。
  • 公式:
    模 拟 输 出 电 压 = 脉 冲 宽 度 × 高 电 平 值 ⇒ 输 出 电 压 高 电 平 值 = 开 启 时 间 百 分 比 模拟输出电压 = 脉冲宽度 \times 高电平值 \Rightarrow \frac {输出电压}{高电平值} = 开启时间百分比 =×=

7.4 模式输出(PWM)指令和默认频率

7.4.1 analogWrite()函数

  1. analogWrite()函数将模拟值(PWM波)写入引脚。它可用于以不同的亮度点亮LED或以各种速度驱动电机。在调用analogWrite()函数之后,引脚将产生指定占空比的稳定方波,直到下一次调用analogWrite()或在相同引脚上调用digitalRead()或digitalWrite()。大多数引脚上的PWM信号频率约为490Hz。在Uno和类似的板上,引脚5和6的频率约为980Hz。Leonardo上的引脚3和11也以980Hz运行。
  2. Arduino 的模拟输入(analogRead)的范围值介于0~1023之间,而模拟输出(analogWrite)介于0 ~ 255。
  3. 在大多数Arduino板上(ATmega168或ATmega328),此功能在引脚3,5,6,9,10和11上工作。在Arduino Mega上,它在引脚2-13和44-46上工作。旧的Arduino ATmega8板仅支持引脚9,10和11上的 analogWrite()。
  4. Arduino Due支持引脚2至13以及引脚DAC0和DAC1上的 analogWrite()。与PWM引脚不同,DAC0和DAC1是数模转换器,用作真正的模拟输出。
  5. 在调用analogWrite()之前,不需要调用pinMode()将引脚设置为输出。

7.4.2 analogWrite()函数语法

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×53.3

7.5 pwm频率

7.5.1 默认频率

Arduino控制板预设采用1kHz 和 500Hz两组不同的PWM输出频率

  • 引脚5、6:976.5625Hz
  • 引脚3、11、9、10:490.196Hz
  • 若PWM频率太低,电机会抖动,LED会闪烁
  • 人耳可以感受20kHz以内的频率,为避免听到电机的抖动音,应调高PWM的输出频率

7.5.2 改变PWM的输出频率

Arduino的PWM输出频率是由ATmega微处理器内部的三个系统定时器:

  • (Timer0~Timer2)决定的,Timer0(5、6)、Timer1(9、10)、Timer2(3、11),通过改变定时器的设置,来调整PWM的输出频率。
  • Arduino的delay()、millis()、micros()等函数的基准时间,来自Timer0,若调整此定时器,将导致这些函数的延迟时间错乱。

下面的程序语句将Timer1(9、10端口输出)的PWM频率调整成31250Hz。

void setup() {
	TCCR1B = TCCR1B & 0b11111000 | 0x01;
}

关于参数的详细说明以及频率对照表

任务1:调光器

  1. 实验说明: 利用电位器的输入信号变化来调整LED亮度
  2. 实验材料:
物品 数量
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);
}

任务2:随机数字与烛光效果

实验说明: 随机, 通过随机调整接在数字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));
}

任务3: 通过串口调整灯光亮度

实验说明: 接收用户输入的0~255数值来改变接在11引脚的LED亮度。

用户通过按键的输入值是字符串格式,而模拟输出指令所需要的参数是数字格式。有两种方法把字符或字符串转换成数字。

  • 将ASCII码减掉48。数字0的十进制ASCII码是48
    ‘2’ - ‘0’ ⇒ \Rightarrow 50 - 48 ⇒ \Rightarrow 2
    ‘2’ - 48 ⇒ \Rightarrow 50 -48 ⇒ \Rightarrow 2
  • 使用atoi()函数指令,把字符串转换成数字。

比如:Arduino收到字符串 ‘168\n’

  1. 处理第一个字:pwm = pwm * 10 + (_in - '0')
  2. 处理第二个字:pwm = pwm * 10 + (_in - '0')
  3. 处理第三个字:pwm = pwm * 10 + (_in - '0')
  4. 读取到字符’\n’,转换完毕!
    由于每次传递的数字长度不确定(如: ‘3’ 和‘168’),为了让接收端确认一串数字的结尾,在发送数据的后面加上‘\n’字符。
    实验程序:
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);
	}
}	

活动4:按钮PWM控制LED亮度

实现说明

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);  
    }  
}

活动5:使用atoi()转换字符串成数字

实验说明

先声明一个空字符串变量,每次收到的新字符,存入字符串变量(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);
	}
}

3.7 补充阅读材料:

1. PWM

《LED亮度渐隐》你可以在Arduino IDE文件->工程库->示例程序->Analog菜单( File->Sketchbook->Examples->Analog)
LED亮度渐隐的例子向你展示如何通过PWM来输出近似的模拟信号。
arduino教程- 03.使用pwm技术_第1张图片
脉宽调制技术(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的某个等效电压,例如

  • analogWrite(255) 代表5V,高电平将占据100%的时间间隔。
  • analogWrite(127) 就表示50%的时间间隔被高电平占据。

请将《LED亮度渐隐》一文中的例子下载到板子上。当例程开始运行后,请来回摇晃Arduino板。这样做的目的是为了让你不用示波器也能真切的看到PWM的真实面貌。因为人眼的视觉暂留让你在晃动过程中将点亮的板载LED看成连续的线条。当你对LED进行PWM操作时,这些线条的长度会根据脉宽变长变短。这样你就更加能体会到PWM的实质啦!

2. LED的正确接法

LED的工作电压约2V,但Arduino微电脑的输出电压是5V,我们应该在Arduino的输出和LED之间连接一个限流电阻,但有时我们把LED直接接在第13脚,这是因为Arduino处理器的输出电流不高(每个脚位可输出20mA,所有引脚最多40mA),第13引脚内接一个1kΩ电阻,因此不会烧毁LED。在实际的操作中,请串联一个220Ω~1kΩ的电阻,连接方式有:源流(source current)和潜流(sink current)两种。源流是当引脚的值为1时,电流由微处理器流出,经组件后至地端。潜流是当引脚的输出状态为0时,电流由Vcc流出,经组件后进入微处理器。无论哪一种接法,都要确认不要从微处理器流出或流入40mA以上的电流,否则该引脚可能会损毁。

3. 电位器:

在许多电工电子线路中,为了调节电流、电压的大小,改变控制电路的电性能,一般可使用可变电阻器(也称电位器、变阻器)来实现,通过调节改变电路中的电阻值来达到控制电流或电压的目的。 一般电位器有三只引脚,如图所示的是碳膜电位器内部结构图。其中中间引脚连接滑动片,其余两脚为固定臂,当滑动片在碳膜上滑动时,即可获得变化的电阻值,其阻值可在一定范围内连续可调。

你可能感兴趣的:(arduino,课程)