#05 使用Arduino 數位I/O自造一個計算器

Arduino 新手村的基本教學,利用Arduino 數位I/O的輸入與輸出特性,可以輕鬆最一些簡單的應用,例如開關按鈕的偵測觸發訊號與輸出控制以及使用LCD液晶顯示器作為資訊輸出,瞭解Arduino C語言架構後即可自造一個裝置。

Arduino 新手村基本教學資料如下:

任務提示:解國中數學題目-無窮級數求和

今天的教學內容以國中數學無窮級數求和的問題自造一個計算器。首先複習國中數學無窮級數的定義:

無窮級數中1 + 2 + 3 + 4 + …的數列,這個數列的起始與結束自然數是可以被設定,這個數列自然數的和則是我們要計算的數值。

舉例:1+2+3+4+5+6+7+8+9+10=55

參考資料:維基百科

硬體分析

要設計一款自動加總計算器需要一個人機介面以及數列的起始數值、結束數值的設定,硬體功能需要以下幾個特點:

  1. 使用LCD 1602作為資訊的顯示,輸入資訊與計算結果顯示。
    • LCD 1602操作背景知識請參閱【04 Arduino輸出訊息利器-LCD 1602液晶顯示器】
  2. 設計【設定按鈕】,主要用於最大值、最小值輸入值設定。
  3. 設計【執行按鈕】,按下按鈕後開始進行結果計算。
    • 按鈕的操作等同開關電路,背景知識請參閱【03 模擬練習Arduino C的程式架構】

硬體分析後即可透過Tinkercad設計模擬的環境,電路圖如下所示。

軟體分析

設計硬體電路之後,還需要設計軟體進行硬體I/O的輸入輸出控制,軟體功能需要以下特點:

  1. 起始、結束與計算按鈕偵測:程式監測按鈕按下與按鈕釋放的處理。
  2. 利用迴圈計算數列和的計算:利用迴圈從最小值逐一執行至最大值的加總。
  3. LCD 1602 資訊顯示的副程式:每一次按鈕觸發後都需要處理 LCD 1602的文字內容,透過副程式的方式讓按鈕觸發時進行呼叫。

系統設計

清楚定義出硬體與軟體的功能後,開始著手規劃系統介面。

  • 數位I/O介面輸入偵測:當按鈕按下時,數位I/O的 pinMode()為INPUT時,會收到高電位(HIGH)的資訊;當按鈕未按下時(釋放的狀態),數位I/O會收到低電位(LOW)的資訊。按鈕功能與數位I/O對應關係如下:
    • 起始按鈕-> Arduino.D8
    • 結束按鈕-> Arduino.D7
    • 計算按鈕-> Arduino.D6
  • LCD 1602介面與Arduino連接定義
LCD 1602 介面Arduino 介面
RSD12
RWGND
ENABLED11
DB4D5
DB5D4
DB6D3
DB7D2

程式設計

基本宣告,宣告起始值、結束值的變數,使用程式庫控制LCD 1602參數設定。

int nI = 0;	//BtnI計數器變數(儲存起始值)
int nJ = 0;	//BtnJ計數器變數(儲存結束值)

#include <LiquidCrystal.h>

// 建立 LiquidCrystal 的變數 lcd
// LCD 接腳: rs, enable, d4, d5, d6, d7
// 對應到 Arduino 接腳: 12, 11, 5, 4, 3, 2
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

setup()初始化設定,定義LCD1602類型、數位I/O輸入設定與按鈕的對應

控制要點:利用pinMode(),將Arduino 數位I/O D8, D7, D6 設定為輸入偵測。

void setup() {
  // 設定 LCD 的行列數目 (2 x 16)
  lcd.begin(16, 2);

  // 列印 "Hello World" 訊息到 LCD 上
  lcd.print("hello, world!");
  
  //D8(BtnI), D7(BtnJ), D6(BtnRun) 設定為INPUT, 接收按鈕開關的事件
  pinMode(8, INPUT);	//每按一次起始按鈕(BtnI),nI +1
  pinMode(7, INPUT);	//每按一次結束按鈕(BtnJ),nJ +1
  pinMode(6, INPUT);	//(BtnRun)計算按鈕
}

loop()處理按鈕按下偵測

控制要點:

  1. digitalRead()偵測 Arduino 數位I/O的狀態,當偵測按鈕按下後將變數的內容+1。
    • 參考範例行號 3, 15, 27
  2. 再次料用digitalRead()偵測按鈕是否備釋放,避免造成連續觸發事件。
    • 參考範例行號 7, 19, 28
  3. 依據按鈕的功能,分別呼叫副程式 DrawNumber() 或 DrawCalculator()。
    • 範例參考行號 11, 23, 32
void loop(){
  //當BtnI 按下後
  if (digitalRead(8)==HIGH){
    nI++;
    
    //Arduino 執行速度很快,當Btn按鈕未鬆開,程式停留在此,避免重複做nI++
    while (digitalRead(8)==HIGH){
      delay(2);
    }
    
    DrawNumber();	//呼叫副程式(DrawNumber(), 顯示nI, nJ 的內容訊息
  }
  
  //當BtnJ 按下後
  if (digitalRead(7)==HIGH){
    nJ++;
    
	//Arduino 執行速度很快,當Btn按鈕未鬆開,程式停留在此,避免重複做nJ++
    while (digitalRead(7)==HIGH){
      delay(2);
    }

    DrawNumber();	//呼叫副程式(DrawNumber(), 顯示nI, nJ 的內容訊息
  }
  
  //當BtnRun按下後
  if (digitalRead(6) == HIGH){
    while (digitalRead(6)==HIGH){
      delay(2);
    }
    
    DrawCalculator();	//呼叫副程式(DrawCalculator(), 顯示nI+...+nJ 的內容
  }
  
}

DrawNumber() 當【起始按鈕】或【結束按鈕】按下後,觸發副程式進行LCD1602資訊顯示

//副程式:1602顯示器內容更新 nI+nJ = ?
void DrawNumber(){
  String sOutString;
  
  //組合LCD顯示的字串內容
  sOutString = String(nI);
  sOutString += "+.abc..+";
  sOutString += String(nJ);
  sOutString +="=?";
  
  //清除LCD內容,顯示LCD內容
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print(sOutString);
}

當【計算】按鈕按下時,呼叫副程式DrawCalculator()進行迴圈的方式,計算開始至結束期間內和的計算。

//副程式:處理BtnRun動作 (計算I+...+J 的和)
void DrawCalculator(){
  int nY=0, nZ=0, nResult=0;
  
  lcd.setCursor(0, 1);
  
  //判斷nI < nJ 不需要調整nI, nJ先後順序
  if (nI < nJ){
    nY = nI;
    nZ = nJ;
  }
  
  //判斷nI > nJ, 進行nI, nJ先後順序調整
  if (nI > nJ){
    nY = nJ;
    nZ = nI;
  }
  
  //判斷nI = nJ, 不做處理
  if (nI == nJ){
    lcd.print("nothing!!");
    return;
  }
  
  //計算nI+...+nJ 的和
  for(int a = nY; a <= nZ; a++){
    nResult += a;
  }
  
  //顯示結果
  lcd.print(nResult);

}

實際成果影片

結論

透過前面幾篇的新手村教學文章,瞭解Arduino 數位I/O的控制應用,再搭配適合的人機介面,很快速就可以完成一個互動裝置的自造。

在Arduino Open Source領域上充斥許多各類型的輸入與輸出裝置,常見的輸入裝置有雙軸搖桿、紅外線偵測 IR、超音波、亮度…等,都很適合自造一些創意的主題,未來在分單元逐一示範。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *