七段顯示器進階控制

《 bitRead() 使用說明 》

bitRead(x, n)
x :要讀取的數字,如果輸入是10進位或16進位,會自動轉成2進位
n :要讀取的字元,0 代表最右邊的字元

void setup() {
  // 例:七段顯示器欲顯示2,控制碼為 0101 1011(2進制碼) –> 0x5B(16進制碼)
  //    (dp) g f e d c b a
  // x =  0  1 0 1 1 0 1 1 (0x5B)
  int x = 0x5B;
  Serial.begin(9600);
  Serial.println(bitRead (x,0));    // bitRead (x,0) = 1 —> a
  Serial.println(bitRead (x,1));    // bitRead (x,1) = 1 —> b
  Serial.println(bitRead (x,2));    // bitRead (x,2) = 0 —> c
  Serial.println(bitRead (x,3));    // bitRead (x,3) = 1 —> d
  Serial.println(bitRead (x,4));    // bitRead (x,4) = 1 —> e
  Serial.println(bitRead (x,5));    // bitRead (x,5) = 0 —> f
  Serial.println(bitRead (x,6));    // bitRead (x,6) = 1 —> g
  Serial.println(bitRead (x,7));    // bitRead (x,7) = 0 —> dp
}

void loop() {
}

原基本控制的程式碼:

int seg[8] = {15, 16, 17, 18, 19, 21, 22, 23};
// 對應的接腳 { a,  b,  c,  d,  e,  f,  g, dp}

void setup() {
  for(int i=0; i<=7; i++)
  {
    pinMode(seg[i], OUTPUT);
  }
}

void loop() {
  // (dp)gfedcba
  // 顯示0: 0011 1111(2進制碼) --> 0x3F(16進制碼)
  digitalWrite(seg[0],1); // a
  digitalWrite(seg[1],1); // b
  digitalWrite(seg[2],1); // c
  digitalWrite(seg[3],1); // d
  digitalWrite(seg[4],1); // e
  digitalWrite(seg[5],1); // f
  digitalWrite(seg[6],0); // g
  digitalWrite(seg[7],0); // dp
  delay(1000);
  // 顯示1: 0000 0110(2進制碼) --> 0x06(16進制碼)
  digitalWrite(seg[0],0); // a
  digitalWrite(seg[1],1); // b
  digitalWrite(seg[2],1); // c
  digitalWrite(seg[3],0); // d
  digitalWrite(seg[4],0); // e
  digitalWrite(seg[5],0); // f
  digitalWrite(seg[6],0); // g
  digitalWrite(seg[7],0); // dp
  delay(1000);
}

可使用bitRead函式改寫:

int seg[8] = {15, 16, 17, 18, 19, 21, 22, 23};
// 對應的接腳 { a,  b,  c,  d,  e,  f,  g, dp}
int data[]= {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x27,0x7F,0x67,0x00};
// 顯示的數字{ 0  ,  1 ,  2 ,  3 ,  4 ,  5 ,  6 ,  7 ,  8 ,  9 ,全滅}

void setup() {
  // 初始化七段顯示器
  for(int i=0; i<=7; i++)
  {
    pinMode(seg[i], OUTPUT);
  }
}

void loop() {
  // (dp)gfedcba
  // 顯示0: 0011 1111(2進制碼) --> 0x3F(16進制碼)
  digitalWrite(seg[0],bitRead(data[0],0));  // a
  digitalWrite(seg[1],bitRead(data[0],1));  // b
  digitalWrite(seg[2],bitRead(data[0],2));  // c
  digitalWrite(seg[3],bitRead(data[0],3));  // d
  digitalWrite(seg[4],bitRead(data[0],4));  // e
  digitalWrite(seg[5],bitRead(data[0],5));  // f
  digitalWrite(seg[6],bitRead(data[0],6));  // g
  delay(1000);

  // 顯示1: 0000 0110(2進制碼) --> 0x06(16進制碼)
  digitalWrite(seg[0],bitRead(data[1],0));  // a
  digitalWrite(seg[1],bitRead(data[1],1));  // b
  digitalWrite(seg[2],bitRead(data[1],2));  // c
  digitalWrite(seg[3],bitRead(data[1],3));  // d
  digitalWrite(seg[4],bitRead(data[1],4));  // e
  digitalWrite(seg[5],bitRead(data[1],5));  // f
  digitalWrite(seg[6],bitRead(data[1],6));  // g
  delay(1000);
}

進一步可將要顯示的數字改寫成副程式:

void showdata(int x)
{
  for(int i=0; i<7; i++)
  digitalWrite(seg[i],bitRead(data[x],i));
}
int seg[8] = {15, 16, 17, 18, 19, 21, 22, 23};
// 對應的接腳 { a,  b,  c,  d,  e,  f,  g, dp}
int data[]= {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x27,0x7F,0x67,0x00};
// 顯示的數字{ 0  ,  1 ,  2 ,  3 ,  4 ,  5 ,  6 ,  7 ,  8 ,  9 ,全滅}

void setup() {
  // 初始化七段顯示器
  for(int i=0; i<=7; i++)
  {
    pinMode(seg[i], OUTPUT);
  }
}

void loop() {
  showdata(0);  // 顯示0
  delay(1000);

  showdata(1);  // 顯示1
  delay(1000);
}

void showdata(int x)
{
  for(int i=0; i<7; i++)
  digitalWrite(seg[i],bitRead(data[x],i));
}

作業練習:

  1. 開機後,七段顯示器顯示 8 和 dp (好壞測試),1秒後顯示0。
  2. 每按一下按鈕開關,可開始或停止計數(每秒加1,在0~9之間循環)。
  3. 長按按鈕開關,計數器歸 0。
  4. 七段顯示器的狀態必須同步顯示在監看視窗上。
  5. 在Wokwi網站上進行模擬,並完成實體接線。

參考範例:

//---------------------------------------------------------------------------
const int pb = 34;                   // 按鈕開關接腳
bool lastButtonState = HIGH;         // 按鈕開關前一次的狀態
unsigned long lastDebounceTime = 0;  // 按鈕開關前一次狀態改變時的millis()時間
int debounceDelay = 150;             // 防彈跳預設的延遲時間
//---------------------------------------------------------------------------
int seg[8] = {15, 16, 17, 18, 19, 21, 22, 23};
// 對應的接腳 { a,  b,  c,  d,  e,  f,  g, dp}
int data[]= {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x27,0x7F,0x67,0x00};
// 顯示的數字{ 0  ,  1 ,  2 ,  3 ,  4 ,  5 ,  6 ,  7 ,  8 ,  9 ,全滅}
//---------------------------------------------------------------------------
bool startCount = 0;  // (0:停止,1:開始)
int count = 0;        // 計數器,初值為0
//---------------------------------------------------------------------------
unsigned long previousMillis = 0;    // 前一次的millis()時間
const long interval = 1000;          // 預設計時的時間
//---------------------------------------------------------------------------

void setup() {
  //--------------------------------------------------
  Serial.begin(9600);     // 啟用串列埠監看視窗
  //--------------------------------------------------
  pinMode(pb, INPUT);     // 初始化按鈕開關
  //--------------------------------------------------
  for(int i=0; i<=7; i++) // 初始化七段顯示器
  {
    pinMode(seg[i], OUTPUT);
  }
  //--------------------------------------------------  
}

void loop() {
  // ---------------------------------------------------------------------------------------------------------------
  unsigned long currentTime = millis();  // 當前的millis()時間
  bool buttonState = digitalRead(pb);    // 當前的按鈕開關狀態:未按下(HIGH),按下(LOW)

  // 若按鈕開關狀態發生變化,且超過防彈跳預設的延遲時間
  if ((buttonState != lastButtonState) && (currentTime - lastDebounceTime) > debounceDelay)
  {
    // --------------------------------------------------------------------------------------
    if (lastButtonState == HIGH && buttonState == LOW)        // 若按鈕從未按下(HIGH)到按下(LOW)
    {
      // 按鈕按下時,想做的事
      startCount = !startCount;           // 取反相
      if(startCount==0)
      {
        Serial.println("Stop.");          // 印出停止狀態  
      }
      else
      {
        Serial.println("Start count..."); // 印出開始計數狀態  
      }
    }
    else if (lastButtonState == LOW && buttonState == HIGH)   // 若按鈕從按下(LOW)到未按下(HIGH)
    {      
      // 按鈕放開時,想做的事
    }
    lastButtonState = buttonState;    // 更新按鈕狀態
    // --------------------------------------------------------------------------------------
    lastDebounceTime = currentTime;   // 更新前一次狀態改變時的millis()時間
  }
  // ---------------------------------------------------------------------------------------------------------------


  // ---------------------------------------------------------------------------------------------------------------
  unsigned long currentMillis = millis();          // 當前的millis()時間

  if (currentMillis - previousMillis >= interval)  // 若達到預設計時的時間
  {
    //---------------------------------------------------------------------
    // 每經過一個interval的時間,要做的事
    //---------------------------------------------------------------------
    if(startCount == 1)
    {
      count = count + 1; 
      Serial.println(count);      
    }
    //---------------------------------------------------------------------

    previousMillis = currentMillis;  // 更新前一次的millis()時間
  }
  // ---------------------------------------------------------------------------------------------------------------
}

void showdata(int x)
{
  for(int i=0; i<7; i++)
  digitalWrite(seg[i],bitRead(data[x],i));
}