之前曾
以四個七段顯示器製作時鐘,這篇則是介紹四合一的七段顯示器,目標是讓它從0000開始計數,然後每秒加1,0001、0002、0003、依此類推。
電路圖與原始碼
可到GitHub下載,按「Download ZIP」即可全部下載,本篇程式碼位於子目錄SevenSegment4in1內。
底下是我買的共陰極、四合一型七段顯示器,每個七段顯示器含小數點。
底下是腳位圖,共有12個腳位,其中8個的功能就是控制七段顯示器,另4個腳位則代表想要控制哪一個七段顯示器,當腳位0為LOW、而腳位1、2、3為HIGH時,代表想要控制最右邊的七段顯示器,依此類推。
控制七段顯示器的8個腳位,a、b、c、d、e、f、g、h(dp),如下所示,本篇不使用h(dp)小數點。
因為有4個七段顯示器,我們必須使用掃描的方式不斷地顯示每一個七段顯示器,只要掃描速度夠快,基於視覺暫留原理,人眼便無法察覺,以為所有數字皆為同時顯示。
電路圖,沒什麼特別的,順著接即可,將在程式碼裡定義腳位的功能。
Arduino數位腳位2接到顯示器的0,
Arduino數位腳位3接到顯示器的g,
Arduino數位腳位4接到顯示器的c,
Arduino數位腳位5接到顯示器的h,
Arduino數位腳位6接到顯示器的d,
Arduino數位腳位7接到顯示器的e,
Arduino數位腳位8接到顯示器的b,
Arduino數位腳位9接到顯示器的1,
Arduino數位腳位10接到顯示器的2,
Arduino數位腳位11接到顯示器的f,
Arduino數位腳位12接到顯示器的a,
Arduino數位腳位13接到顯示器的3。
在下圖裡的四合一型七段顯示器擁有16個針腳,因為我找不到12個針腳的。
照理說,應該要串聯電阻220歐姆,不過我沒加也沒事orz。另外有些文章說Arduino輸出的電流不夠無法驅動,需加入NPN電晶體,不過我沒用也ok。
底下是程式碼:
// 定義腳位
#define PIN_0 2
#define PIN_g 3
#define PIN_c 4
#define PIN_h 5
#define PIN_d 6
#define PIN_e 7
#define PIN_b 8
#define PIN_1 9
#define PIN_2 10
#define PIN_f 11
#define PIN_a 12
#define PIN_3 13
// 共有4個七段顯示器,分別由針腳PIN_0、PIN_1、PIN_2、PIN_3控制
// 七段顯示器裡有8個LED(包含小數點)
#define POS_NUM 4
#define SEG_NUM 8
const byte pos_pins[POS_NUM] = {PIN_0, PIN_1, PIN_2, PIN_3};
const byte seg_pins[SEG_NUM] = {PIN_a, PIN_b, PIN_c, PIN_d, PIN_e, PIN_f, PIN_g, PIN_h};
// 底下定義由七段顯示器顯示數字時所需要的資料
#define t true
#define f false
const boolean data[10][SEG_NUM] = {
{t, t, t, t, t, t, f, f}, // 0
{f, t, t, f, f, f, f, f}, // 1
{t, t, f, t, t, f, t, f}, // 2
{t, t, t, t, f, f, t, f}, // 3
{f, t, t, f, f, t, t, f}, // 4
{t, f, t, t, f, t, t, f}, // 5
{t, f, t, t, t, t, t, f}, // 6
{t, t, t, f, f, f, f, f}, // 7
{t, t, t, t, t, t, t, f}, // 8
{t, t, t, t, f, t, t, f}, // 9
};
// 一支方便的函式,以格式字串輸出到序列埠
void pf(const char *fmt, ... ){
char tmp[128]; // max is 128 chars
va_list args;
va_start (args, fmt );
vsnprintf(tmp, 128, fmt, args);
va_end (args);
Serial.print(tmp);
}
// 設定某個七段顯示器所顯示的數字,
// 參數pos為0~3,指出想要更新哪一個七段顯示器,
// 參數n為0~9,顯示數字
void setDigit(int pos, int n){
if(pos < 0 || 3 < pos){
pf("error pos=%d\n", pos);
return;
}
// 控制想要更新哪一個七段顯示器,將其腳位設為LOW
// 其他腳位則設為HIGH,代表不更新。
for(int p = 0; p < POS_NUM; p++){
if(p == pos)
digitalWrite(pos_pins[p], LOW);
else
digitalWrite(pos_pins[p], HIGH);
}
// 寫入數字
if(0 <= n && n <= 9){
for(int i = 0; i < SEG_NUM; i++){
digitalWrite(seg_pins[i], data[n][i] == t ? HIGH : LOW);
}
}
else{
for(int i = 0; i < SEG_NUM; i++){
digitalWrite(seg_pins[i], LOW);
}
digitalWrite(PIN_h, HIGH);
pf("error pos=%d, n=%d\n", pos, n);
}
}
// 設定整個四合一型七段顯示器想要顯示的數字
// 參數number的範圍應是0~9999
void setNumber(int number)
{
int n0, n1, n2, n3;
n3 = number / 1000;
number %= 1000;
n2 = number / 100;
number %= 100;
n1 = number / 10;
n0 = number % 10;
// 求出每個位數的值後,分別更新
// 注意,此處以delay(5)隔開每個位數的更新
setDigit(0, n0); delay(5);
setDigit(1, n1); delay(5);
setDigit(2, n2); delay(5);
setDigit(3, n3); delay(5);
}
unsigned long time_previous;
void setup() {
Serial.begin(115200);
for(int i = 0; i < POS_NUM; i++){
pinMode(pos_pins[i], OUTPUT);
digitalWrite(pos_pins[i], HIGH);
}
for(int i = 0; i < SEG_NUM; i++){
pinMode(seg_pins[i], OUTPUT);
digitalWrite(seg_pins[i], LOW);
}
time_previous = millis();
}
int number = 0;
void loop() {
// 經過一秒後就讓number加1
unsigned long time_now = millis();
if(time_now - time_previous > 1000){
number++;
time_previous += 1000;
pf("number=%d\n", number);
}
// 不斷地寫入數字
setNumber(number);
}
成功的話,一開始會顯示0000,然後是0001、0002、0003、等等。
可修改的地方:
- 可使用4511減少腳位數量,但4511只能搭配共陰極七段顯示器。
- 處理大於9999的情況。
- 修改setNumber函式裡delay(5)的延遲值,改成10或50,試試看有何效果。
參考資料: