Arduino中国 | Flamingo EDA

CAT | 教程

Sep/07

3

Arduino教程四: 模拟输出

就像模拟输入一样,在现实的物理世界中我们经常需要输出除了0和1之外的其他数值。例如,除了想用微控制器找开或者关闭电灯之外,我们还会想控制灯光的亮度,这时就需要用到模拟输出。由于Arduino的微控制器只能产生高电压(5V)或者低电压(0V),而不能产生变化的电压,因此必须采用脉宽度调制技术(PWM,Pulse Width Modulation)来模仿模拟电压。

PWM是一种开关式稳压电源应用,它是借助微处理器的数字输出来对模拟电路进行控制的一种非常用效的技术,广泛应用在从测量、通信到功率控制与变换的许多领域中。简而言之,PWM是一种对模拟信号电平进行数字编码的方法,它通过对半导体开关器件的导通和关断进行控制,使输出端得到一系列幅值相等但宽度不相等的脉冲,而这些脉冲能够被用来代替正弦波或其它所需要的波形。

在Arduino数字I/O管脚9、10和11上,我们可以通过analogWrite()函数来产生模拟输出。该函数有两个参数,其中第一个参数是要产生模拟信号的引脚(9、10或者11);第二个参数是用于产生模拟信号的脉冲宽度,取值范围是0到255。脉冲宽度的值取0可以产生0V的模拟电压,取255则可以产生5V的模拟电压。不难看出,脉冲宽度的取值变化1,产生的模拟电压将变化0.0196V(5/255 = 0.0196)。

本实验中我们将用模拟输出来调暗发光二极管(LED),由于正常情况下LED对电压的变化非常敏感,因此当脉冲宽度变化时人眼会感觉到LED实际上是在不断地熄灭和点亮,而不是逐渐变暗。解决这一问题可以采用滤波电路,它能使有用频率信号通过而同时抑制(或大大衰减)无用频率信号。实验中我们采用的是低通滤波器,它的原理非常简单,只需要一个电阻和一个电容,能够很好地过滤掉电路中超过某一频率的信号。

low_pass_filter.png

此处给出的电路并不能校平所有脉冲,它之所以被称为“低通滤波”是因为它只允许频率低于某个限度的脉冲通过,对于高于这个限度的脉冲则被平衡为伪模拟电压,滤波的频率范围由电阻器和电容器的比值决定。

实验中采用的电路原理如下:

tutorial_4_schematic.png

相应的代码为:


int potPin = 0;
int ledPin = 11;

byte bright_table[] = {  30,  30,  30,  40,  50,  60,  70,  80,  90, 100,
                        110, 120, 130, 140, 150, 160, 170, 180, 190, 200,
                        210, 220, 230, 240, 250, 250, 240, 230, 220, 210,
                        200, 190, 180, 170, 160, 150, 140, 130, 120, 110,
                        100,  90,  80,  70,  60,  50,  40,  30,  30,  30 };
int MAX = 50;
int count = 0;
int val = 0;

void setup() {
  pinMode(ledPin, OUTPUT);
}

void loop() {
  analogWrite(ledPin, bright_table[count]);
  count ++;
  if (count > MAX) {
    count = 0;
  }

  val = analogRead(potPin);
  val = val /4;
  delay(val);
}

该工程调用analogWrite()函数在数字I/O端口的11号管脚上模仿模拟输出,每产生一次输出后都设置了相应的延时,而延时的长度由模拟输入端口0号管脚上的电位器来决定。通过调整电位器的位置,我们可以观察到发光二极管逐渐变亮后再逐渐变暗的效果。

tutorial_4_circuit.jpg

No tags

Sep/07

1

Arduino教程三: 模拟输入

Arduino的优势在于对数字信号的识别和处理,但我们所生活的真实世界并不是数字(digital)化的,简单到只要用0和1就能够表示所有的现象。例如温度这一我们已经司空见惯的概念,它只能在一个范围之内连续变化,而不可能发生像从0到1这样的瞬时跳变,类似这样的物理量被人们称为是模拟(analog)的。Arduino是无法理解这些模拟量的,它们必须在经过模数转换后变成数字量后,才能被Arduino进一步处理。

像温度这样的数据必须先被转换成微处理器能够处理的形式(比如电压),才能被Arduino处理,这一任务通常由各类传感器(sensor)来完成的。例如,电路中的温度传感器能够将温度值转换成0V到5V间的某个电压,比如0.3V、3.27V、4.99V等。由于传感器表达的是模拟信号,它不会像数字信号那样只有简单的高电平和低电平,而有可能是在这两者之间的任何一个数值。至于到底有多少可能的值则取决于模数转换的精度,精度越高能够得到的值就会越多。

Arduino所采用的ATmega8微处理器一其有6个模数转换器(ADC,Analog to Digital Converter),每一个模数转换器的精度都是10bit,也就是说能够读取1024(2^10 = 1024)个状态。在Arduino的每一个模拟输入管脚上,电压的变化范畴是从0V到5V,因此Arduino能够感知到的最小电压变化是4.8毫伏(5/1024 = 4.8mV)。

电位计(potentiometer)是一种最简单的模拟输入设备,它实际上就是一个可变电阻箱,通过控制滑块所在的位置我们可以得到不同的电压值,而输入信号正是从滑块所在的位置接入到电路中的。

tutorial_3_pot_theory.png

tutorial_3_potentiometer.jpg

这一实验我们将通过改变电位计的值来控制发光二极管闪烁的频率。电位计上一共有三个管脚,分别连接到Arduino的电源、地和模拟输入的5号管脚上,发光二极管则连接到数字I/O的13号管脚上,原理图如下所示:

tutorial_3_schematic.png

相应的代码为:


int ledPin = 13;
int potPin = 5;
int value = 0;

void setup() {
  pinMode(ledPin, OUTPUT);
}

void loop() {
  value = analogRead(potPin);
  digitalWrite(ledPin, HIGH);
  delay(value);
  digitalWrite(ledPin, LOW);
  delay(value);
}

在Arduino中,对模拟输入端口不需要调用pinMode()函数将其指定为输入或者是输出模式,这点同数字I/O端口是有所不同的。

通过旋转电位计的轴,我们能改变电位计中间那根连线同地之间的电阻量,从而也就能改变从模拟输入的5号管脚上所读入的模拟量的值。当电位计完全旋转到头时,输入到模拟输入管脚上的电压为0V,用analogRead()函数读出的值为0;当电位计完全旋转到另一头时,输入到模拟I/O管脚上的电压为5V,此时用analogRead()函数读出的值为1023;当电位计旋转到中间的某个位置时,输入到模拟输入管脚上的电压是0V到5V之间的某个值,而用analogRead()函数读出的则是位于0到1023之间的某个对应值。读出的模拟量在我们的实验中被用来确定发光二极管点亮和熄灭的时间,以反映模拟量的变化。

tutorial_3_circuit.jpg

电位计运用的是分压原理,通过旋转到不同的位置来得到不同的电压值。从这种意义上讲,它能够被用来对当前旋转到的位置进行度量,因此可以被用在转向轮等旋转装置中。

今天发现PCB板上另外一个错误,就是将模拟输入对应管脚号标反了,试了好久才意识到是这一问题。加上之前电源设计上的两个小缺陷, 一共有三个需要修改的地方。如果有机会再做PCB板的话,试着将这些问题解决一下:-)

No tags

Sep/07

1

Arduino教程二: 数字输入

 

在数字电路中开关(switch)是一种基本的输入形式,它的作用是保持电路的连接或者断开。Arduino从数字I/O管脚上只能读出高电平(5V)或者低电平(0V),因此我们首先面临到的一个问题就是如何将开关的开/断状态转变成Arduino能够读取的高/低电平。解决的办法是通过上/下拉电阻,按照电路的不同通常又可以分为正逻辑(Positive Logic)和负逻辑(Inverted Logic)两种。

在正逻辑电路中,开关一端接电源,另一端则通过一个10K的下拉电阻接地,输入信号从开关和电阻间引出。当开关断开的时候,输入信号被电阻“拉”向地,形成低电平(0V);当开关接通的时候,输入信号直接与电源相连,形成高电平。对于经常用到的按压式开关来讲,就是按下为高,抬起为低。

tutorial_2_pull_down.png

在负逻辑电路中,开关一端接地,另一端则通过一个10K的上拉电阻接电源,输入信号同样也是从开关和电阻间引出。当开关断开时,输入信号被电阻“拉”向电源,形成高电平(5V);当开关接通的时候,输入信号直接与地相连,形成低电平。对于经常用到的按压式开关来讲,就是按下为低,抬起为高。

tutorial_2_pull_up.png

为了验证Arduino数字I/O的输入功能,我们可以将开关接在Arduino的任意一个数字I/O管脚上(13除外),并通过读取它的接通或者断开状态,来控制其它数字I/O管脚的高低。本实验采用的原理图如下所示,其中开关接在数字I/O的7号管脚上,被控的发光二极管接在数字I/O的13号管脚上:

tutorial_2_schematic1.png

相应的代码为:


int ledPin = 13;
int switchPin = 7;
int value = 0;

void setup() {
  pinMode(ledPin, OUTPUT);
  pinMode(switchPin, INPUT);
}

void loop() {
  value = digitalRead(switchPin);
  if (HIGH == value) {
    // turn LED off
    digitalWrite(ledPin, LOW);
  } else {
    // turn LED on
    digitalWrite(ledPin, HIGH);
  }
}

由于采用的是负逻辑电路,开关按下时用digitalRead()函数读取到的值为LOW,此时再用digitalWrite()函数将发光二极管所在的管脚置为高,点亮发光二极管。同理,当开关抬起时,发光二极管将被熄灭,这样我们就实现了用开关来控制发光二极管的功能。

tutorial_2_circuit.jpg

No tags

Aug/07

30

Arduino教程一: 数字输出

Arduino的数字I/O被分成两个部分,其中每个部分都包含有6个可用的I/O管脚,即管脚2到管脚7和管脚8到管脚13。除了管脚13上接了一个1K的电阻之外,其他各个管脚都直接连接到ATmega上。我们可以利用一个6位的数字跑马灯,来对Arduino数字I/O的输出功能进行验证,以下是相应的原理图:

电路中在每个I/O管脚上加的那个1K电阻被称为限流电阻,由于发光二极管在电路中没有等效电阻值,使用限流电阻可以使元件上通过的电流不至于过大,能够起到保护的作用。

该工程对应的代码为:


int BASE = 2;
int NUM = 6;
int index = 0;

void setup()
{
  for (int i = BASE; i < BASE + NUM; i ++) {
    pinMode(i, OUTPUT);
  }
}

void loop()
{
  for (int i = BASE; i < BASE + NUM; i ++) {
    digitalWrite(i, LOW);
  }
  digitalWrite(BASE + index, HIGH);
  index = (index + 1) % NUM;
  delay(100);
}

下载并运行该工程,连接在Arduino数字I/O管脚2到管脚7上的发光二极管会依次点亮0.1秒,然后再熄灭:

这个实验可以用来验证数字I/O输出的正确性。Arduino上一共有十二个数字I/O管脚,我们可以用同样的办法验证其他六个管脚的正确性,而这只需要对上述工程的第一行做相应的修改就可以了:


int BASE = 8;

No tags

<< Latest posts

Theme Design by devolux.nh2.me