arduino教程-7.脉冲宽度调制【变频】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:使用atoi()转换字符串成数字
        • 实验说明
        • 实验程序

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

主要内容

  1. Arduino输出模拟信号,也就是可变电压输出。
  2. 电机型号和规格,常见的电机驱动和控制电路
  3. 介绍常见的晶体管,以及晶体管电路的基本应用与设计方式

7.1 PWM的基本原理

脉冲宽度调制基本上是一个随时间变化而变化的方波。基本的PWM信号如下图所示。
arduino教程-7.脉冲宽度调制【变频】pwm_第1张图片

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()函数

analogWrite()函数将模拟值(PWM波)写入引脚。它可用于以不同的亮度点亮LED或以各种速度驱动电机。在调用analogWrite()函数之后,引脚将产生指定占空比的稳定方波,直到下一次调用analogWrite()或在相同引脚上调用digitalRead()或digitalWrite()。大多数引脚上的PWM信号频率约为490Hz。在Uno和类似的板上,引脚5和6的频率约为980Hz。Leonardo上的引脚3和11也以980Hz运行。

在大多数Arduino板上(ATmega168或ATmega328),此功能在引脚3,5,6,9,10和11上工作。在Arduino Mega上,它在引脚2-13和44-46上工作。旧的Arduino ATmega8板仅支持引脚9,10和11上的 analogWrite()。

Arduino Due支持引脚2至13以及引脚DAC0和DAC1上的 analogWrite()。与PWM引脚不同,DAC0和DAC1是数模转换器,用作真正的模拟输出。

在调用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个
10kΩ可变电阻 1个
  • Arduino 的模拟输入(analogRead)的范围值介于0~1023之间,而模拟输出(analogWrite)介于0 ~ 255。
  1. 实验程序
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:使用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);
	}
}

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