2013年4月4日 星期四

Arduino: 串列輸入 (RS232 INPUT)


   串列通信是在實現PC與u'P微控制器間相互通信最簡單的辦法。之前的PC上一般都配有標準的RS-232或者RS-422接口來實現串列通信,但現在這種情況已經發生了一些改變,大家更傾向於使用USB這樣一種更快速但同時也更加複雜的方式來實現串行通信。

儘管在有些計算機上現在已經找不到RS-232或者RS-422端口了,但我們仍可以通過USB /串列或者PCMCIA/串列這樣的轉換器,在這些設備上得到傳統的串列端口上。



通過串列連接的Arduino在交互式設計中能夠為PC提供一種全新的相互通信方式,例如用PC控制一些看來非常複雜的事情,像聲音和視頻等。很多場合中會要求Arduino能夠通過串列接收來自於PC的命令,並完成相應的功能,這可以通過Arduino語言中提供的Serial.read()函數來實現。

在實驗中我們不需要任何額外的電路,而只需要用串列線將ArduinoPC連起來就可以了,相應的Arduino程式碼如下:


int ledPin = 12;
int val;

void setup() {
  pinMode(ledPin, OUTPUT);
  Serial.begin(9600);
}

void loop() {
  val = Serial.read();
  if (-1 != val) {
    if ('H' == val or 'h'==val ) {  //讀取 H 或 h
      digitalWrite(ledPin, HIGH);
      Serial.println("LED ON !");
      delay(1500);
      digitalWrite(ledPin, LOW);
      Serial.println("LED OFF !");
     }
  }
}




把程式下載到Arduino模組中之後,在Arduino IDE開發環境中打開串列監視器並將Baud rate設置為9600,然後向Arduino發送字碼 H 或 h,如下圖所示:



該程式程運行後會不斷使用Serial.read()函數從串列口獲得資料數據。 Arduino語言提供的這個函數是不阻塞的,也就是說不論串口上是否真的有數據到達,該函數都會立即返回。

Serial.read()函數每次只讀取一個Word的資料數據,當串列上有數據到達的時候,該函數的返回值為到達的數據中第一個字符的ASCII碼;當串列上沒有數據到達的時候,該函數的返回值則為-1


Arduino語言的參考手冊中沒有對Serial.read()函數做過多的說明,我的一個疑問是如果PC一次發送太多的數據,Arduino是否提供相應的串列口緩衝功能來保證數據不會丟失?

Arduino語言中提供的另外一個函數Serial.available()或許能夠幫助我們用實驗來進行驗證:


int ledPin = 12;
int val;

void setup() {
  pinMode(ledPin, OUTPUT);
  Serial.begin(9600);
}

void loop() {
  val = Serial.read();
  if (-1 != val) {
    if ('H' == val or 'h' ==val ) {
      digitalWrite(ledPin, HIGH);
      delay(500);
      digitalWrite(ledPin, LOW);

      Serial.print("Available: ");
      Serial.println(Serial.available(), DEC);
    }
  }
}



函數Serial.available()的功能是返回串列緩衝區中當前剩餘的Char個數,按照Arduino提供的函數的說明串列緩衝區中最多能緩衝128個chars。

我們可以一次給Arduino模組發送多個Chars,來驗證這一功能:

在這一實驗中,每當Arduino成功收到一個字碼(chars) H 或h,連接在數位I/O口 接12上的LED就會閃爍一次:






Arduino: 串列輸出(RS232 TTL Level)


    在許多應用場合中我們會要求在Arduino和其它設備之間實現相互通信,而最常見也是最簡單的辦法就是使用串列通信。

在串列通信中,兩個設備之間一個接一個地來回發送數位脈衝,它們之間必須遵循相應的協議以保證通信的正確性。

PC上最常見的串列通信協議是RS-232串行協議,而在各種微控制器(單片機)上採用的則是TTL串行協議。由於這兩者的電平有很大的不同,因此在實現PC機和微控制器的通信時,必須進行相應的轉換。完成RS-232電平和TTL電平之間的轉換一般採用專用芯片,如MAX232等,但在Arduino上是用相應的位準轉換電路來完成的。



根據Arduino的原理圖我們不難看出,ATmegaRXTX引腳一方面直接接到了數位I/O 端口的0號和1號接腳, 另一方面又通過電平轉換電路接到了串口的母頭上。因此,當我們需要用ArduinoPC通信時,可以用串列線將兩者連接起來;當我們需要用 Arduino與微控制器(如另一塊Arduino)通信時,則可以用數位I/O端口的0號和1號接腳。

串行通信的困難點在於參數的設置,如baud rate、Data bit、Stop bit等,在 Arduino 語言可以使用Serial.begin()函數來簡化這一任務。為了實現數據的發送,Arduino則提供了Serial.print()Serial.println()兩個函數,它們的區別在於後者會在請求發送的數據後面加上換行符號(line feed),以提高輸出結果的可讀性。

在這一實驗中沒有用到額外的電路, 我們只需要用串口線將ArduinoPC機連起來就可以了,相應的程式為:

void setup() {
  Serial.begin(9600);
}

void loop() {
  Serial.println("Hello World!");
  delay(1000);
}

在將程式下載到Arduino模塊中之後,在Arduino IDE開發環境的工具欄中單擊“Serial Monitor”控制,打開串列監視器:


接著將Baud rate設置為9600,即保持與實驗中的設置相一致:

如果一切正常,此時我們就可以在Arduino IDE開發環境的Console視窗中看到串列上輸出的數據了:


為了檢查串列上是否有數據發送,一個比較簡單的辦法是在數字I/O端口的1號接腳(TX)和5V電源之間接一個LED,如下圖所示:


這樣Arduino在通過串列向PC發送數據時,相應的發光二極管就會閃爍。

Arduino : PWM 輸出


就像類比輸入一樣,在真正的物理世界中我們經常需要輸出除了01之外的其他數值。例如,除了想用微控制器找開或者關閉電燈之外,我們還會想控制燈光的亮度,這時就需要用到類比輸出。

由於Arduino的微控制器只能產生高電壓(5V)或者低電壓(0V),而不能產生變化的電壓,因此必須採用脈寬度調變技術(PWMPulse Width Modulation)來模仿類比電壓。

脈衝寬度調變 (Pulse Width Modulation,PWM) 是將類比訊號轉換為脈波的一種技術,一般轉換後脈波的週期固定,但脈波的占空比會依類比訊號的大小而改變。PWM的使用隨著數位控制邏輯電路的增加而普及,該技術提供簡單的方法,可讓數位控制邏輯電路建立相當於類比的功能。許多微控制器都內建 PWM功能。PWM同時也可用於通訊系統,因為數位訊號比較穩定,也比較不容易受到雜訊干擾。

555  Duty cycle (PWM) 控制馬達


PWM是一種開關式穩壓電源應用,它是借助微處理器的數位輸出來對類比電路進行控制的一種非常用效的技術,廣泛應用在從測量、通信到功率控制與變換的許多領域中。

簡而言之,PWM是一種對模擬信號位準進行數位編碼的方法,它通過對半導體開關元件的導通和關斷進行控制,使輸出端得到一系列幅值相等但寬度不相等的脈衝,而這些脈衝能夠被用來代替正弦波或其它所需要的波形。

Arduino數未I/O接腳 91011上,我們可以通過analogWrite()函數來產生模擬輸出。該函數有兩個參數,其中第一個參數是要產生模擬信號的引腳(910或者11);第二個參數是用於產生模擬信號的脈衝寬度,取值範圍是0255。脈衝寬度的值取0可以產生0V的模擬電壓,取255則可以產生5V的模擬電壓。不難看出,脈衝寬度的取值變化1,產生的模擬電壓將變化0.0196V5V/255 = 0.0196V)。

本實驗中我們將用類比輸出來調暗發光二極管(LED),由於正常情況下LED對電壓的變化非常敏感,因此當脈衝寬度變化時人眼會感覺到LED實際上是在不斷地熄滅和點亮,而不是逐漸變暗。解決這一問題可以採用濾波電路,它能使有用頻率信號通過而同時抑制(或大大衰減)無用頻率信號。  (R/C 低通)

                 cut frequency = 0.16/ (220*10^-5)= 80Hz

實驗中我們採用的是低通濾波器,它的原理非常簡單,只需要一個電阻和一個電容,能夠很好地過濾掉電路中超過某一頻率的信號。此處給出的電路並不能校平所有脈衝,它之所以被稱為低通濾波是因為它只允許頻率低於某個限度的脈衝通過,對於高於這個限度的脈衝則被平衡為偽類比電壓,濾波的頻率範圍由電阻器和電容器的比值決定。








int potPin = 5;
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號接腳上模仿類比輸出,每產生一次輸出後都設置了相應的延時Delay ,而延時的長度由類比輸入端口5號接腳上的電位器來決定。通過調整電位器的位置,我們可以觀察到LED逐漸變亮後再逐漸變暗的效果。

Arduino : 類比輸入來控制LED 閃爍的頻率


Arduino的優勢在於對數位信號的識別和處理,但我們的真實世界並不是數位(digital)的,簡單到只要用01就能夠表示所有的現象。

例如溫度的變化,它只能在一個範圍之內連續變化,而不可能發生像從01這樣的瞬時跳變,類似這樣的物理量被人們稱為是類比(analog)的。

Arduino是無法理解這些類比量,它們必須在經過類比轉換後變成數位量後(A/D converted),才能被Arduino進一步處理。

像溫度這樣的數據必須先被轉換成微處理器能夠處理的數位形式(比如電壓),才能被Arduino處理,這一任務通常由各類感測器(sensor)來完成的。

例如,電路中的溫度感測器能夠將溫度值轉換成0V5V間的某個電壓,比如 0.3V 、 3.27V 4.99V等。由於感器輸出的是類比信號,它不會像數位信號那樣只有簡單的Hi 和 Lo,而有可能是在這兩者之間的任何一個數值。至於到底有多少可能的值則取決於類比轉換(ADC)的精度,精度越高能夠得到的值就會越多。

Arduino所採用的ATmega8微處理器一其有6個模數轉換器(ADCAnalog to Digital Converter),每一個模數轉換器的精度都是10bit,也就是說能夠讀取10242^10 = 1024)個狀態。

Arduino的每一個類比輸入接腳上,電壓的變化範疇是從0V5V,因此Arduino能夠感知到的最小電壓變化是4.8毫伏(5V/1024 = 4.8mV)。

電位計(potentiometer)是一種最簡單的類比輸入設備,它實際上就是一個可變電阻,通過控制滑稈所在的位置我們可以得到不同的電壓值,而輸入信號正是從滑稈所在的位置接入到電路中的。


這一實驗我們將通過改變電位計的值來控制發光二極管閃爍的頻率。電位計上一共有三個接腳,分別連接到Arduino的電源、地和類比輸入的5號接腳上,LED則連接到數位I/O的7到14號接腳上,原理圖如下所示:




int BASE = 2;
int NUM = 8;
int index = 0;
int potPin = 5;  //analog input
int val=0;

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

void loop()
{
  val= analogRead(potPin); 

   for (int i = BASE; i < BASE + NUM; i ++) {
       digitalWrite(i, HIGH);  }
   delay(val);
   for (int i = BASE; i < BASE + NUM; i ++) {
       digitalWrite(i, LOW);  }
   delay(val);
 }



Arduino中,對類比輸入口不需要用 pinMode()函數 將其指定為輸入或者是輸出模式,這點同數位I/O口是有所不同的。

通過旋轉電位計的軸,我們能改變電位計中間那根連線同地之間的電阻量,從而也就能改變從類比輸入的5號管腳上所讀入的模擬量的值。當電位計完全旋轉到頭時,輸入到類比輸入接腳上的電壓為0V,用analogRead()函數讀出的值為0;當電位計完全旋轉到另一頭時,輸入到類比輸入接上的電壓為5V,此時用analogRead()函數讀出的值為1023

當電位計旋轉到中間的某個位置時,輸入到模擬輸入管腳上的電壓是0V5V之間的某個值,而用analogRead()函數讀出的則是位於01023之間的某個對應值。

讀出的類比輸入量在我們的實驗中被用來確定LED點亮和熄滅的時間,以反映類比量的變化。



2013年4月3日 星期三

Arduino : Digital Input



在數位電路中開關(switch)是一種基本的輸入形式,它的作用是保持電路的連接或者斷開。
Arduino從數I/O pin接腳上只能讀出高電平(5V)或者低電平(0V),因此我們首先面臨到的一個問題就是如何將開關的開/斷狀態轉變成Arduino能夠讀取的高/低電平。解決的辦法是通過上/下拉電阻,按照電路的不同通常又可以分為正邏輯(Positive Logic)和負邏輯(Inverted Logic)兩種。

在正邏輯電路中,開關一端接電源,另一端則通過一個10K的下拉電阻接地,輸入信號從開關和電阻間引出。當開關斷開的時候,輸入信號被電阻向地,形成低電平(0V);當開關接通的時候,輸入信號直接與電源相連,形成高電平。對於經常用到的按壓式開關來講,就是按下為高,抬起為低。




在負邏輯電路中,開關一端接地,另一端則通過一個10K的上拉電阻接電源,輸入信號同樣也是從開關和電阻間引出。當開關斷開時,輸入信號被電阻向電源,形成高電平(5V);當開關接通的時候,輸入信號直接與地相連,形成低電平。對於經常用到的按壓式開關來講,就是按下為低,抬起為高。



為了驗證Arduino數位I/O的輸入功能,我們可以將開關接在Arduino的任意一個數字I/O接上(13除外),並通過讀取它的接通或者斷開狀態,來控制其它數I/O接腳的高低。

本實驗採用的原理圖如下所示,其中開關接在數I/O的12號腳上,被控的發光二極管接腳在數I/O的7到14號腳上:







// I/O Pin12 = High   8 LED Flashing (all on , all off)
// I/O Pin12 = LOW    8 LED Alternately flashing 1 by 1


int BASE = 2;
int NUM = 8;
int index = 0;
int inpin=12;
int val;

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

}

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












Arduino : digital output 8 LED


Arduino的數位I/O被分成兩個部分,其中每個部分都包含有6個可用的I/O管腳,即pin2到pin7 和 pin8到pin13除了pin13上接了一個1K的電阻之外,其他各個管腳都直接連接到ATmega上。

我們可以利用一個6(8)位的digital跑馬燈,來對Arduino數字I/O的輸出功能進行驗證,以下是相應的原理圖:

電路中在每個I/O PIN上加的那個1K限流電阻阻,由於LED在電路中沒有等效電阻值,使用限流電阻可以使元件上通過的電流不至於過大,能夠起保護作用。
程式如下:




int BASE = 2;
int NUM = 8;
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);
}



Node-Red 抓取 opendata 的資料集產生AQI 空氣品質指

Node-Red 抓取 opendata 的資料集產生AQI 空氣品質指標 實現透過 Node-RED 抓取環境部 OpenData(空氣品質 AQI)資料,最核心的流程為: 注入觸發(Inject) → HTTP 請求(http request) → 解析 JSON 資料(Fu...