在上一期的“教你花式點燈”中,我們已經(jīng)教會了大家如何將一顆燈點到極致。而點燈到這里還沒有完哦,這次給大家來點進階的小課程,來教教大家如何花式點亮一排燈。快快上車,老司機準備起飛了!
最簡單的一個 LED 的實驗之后,自然是增加幾個 LED,咱排成一排來玩吧。最后,再把一排的 LED 排成一個 8 字來玩——七段數(shù)碼管。
流水燈一—— 跑馬燈
第一個出場的肯定是經(jīng)典的流水燈,也叫跑馬燈
流水燈二—— 端口整體操作
再試流水燈,這里換一個端口整體操作,感受到更簡潔沒?
流水燈三—— 74HC959 擴展 IO 口
又是流水燈!這次使用 74HC595 來擴展 IO 口。對于 arduino 來說,IO 口資源是很緊張的,遲早會遇到不夠用的時候,這時候就需要擴展。使用 74HC595 是一種比較常見的方案。
雨滴拖尾效果流水燈
不好意思,還是流水燈。這次模擬得更真實一點,加上水滴的拖尾效果。
首先是簡單的方法,使用 uno 的六個 pwm 口來實現(xiàn)。
1.// ----------------------------------------------------------------------------
2.// raindropLEDS.ino
3.//
4.// Created 2015-06-04
5.// By seesea
6.//
7.// 雨滴流動效果
8.// 雨滴流動效果與流水燈(跑馬燈)的區(qū)別在于雨滴流水效果有拖尾效果,即亮過的燈是慢慢熄滅的
9.//
10.// 使用 UNO 的六個 PWM 引腳實現(xiàn)雨滴流動的效果
11.// UNO 的六個 PWM 引腳為 pin 3 5 6 9 10 11,這幾個腳分別接 6 個 LED 正極,LED 負極接 GND
12.//
13.// ----------------------------------------------------------------------------
14.
15.const unsigned char pins[] = { 3, 5, 6, 9, 10, 11 }; // 六個 pwm 引腳
16.const unsigned char initPwm= 240; // 最亮的燈的 pwm 值,即移動的時候在最頭一個燈的亮度
17.const unsigned char deltaPwm = 10; // 燈慢慢熄滅的 pwm 值,后一個燈比前一個燈暗多少。這相當于是一個等差隊列。等差的亮度感覺不大好,所以引入下一個等比的因素
18.const unsigned char deltaPercent = 30; // 后一個燈比前一個燈暗,其亮度是前一個燈的百分之幾。相對于前面的遞減,這個相當于是等比級數(shù)
19.const unsigned long delayMs= 100; // 移動延遲,單位 ms
20.const unsigned char pinNum = sizeof(pins) / sizeof(pins[0]);// 引腳數(shù)量,即 LED 個數(shù)
21.
22.unsigned char ledPwm[pinNum]; // 存放運行時每一個 LED 的亮度 PWM 值
23.
24.void setup()
25.{
26. for (char i = 0; i < pinNum; ++i)
27. {
28. pinMode(pins[i], OUTPUT);
29. ledPwm[i] = 0;
30. }
31.}
32.
33.void loop()
34.{
35. static unsigned char head = 0;
36.
37. // 每一次進入 loop() 函數(shù)都對所有的燈亮度進行處理
38. for (unsigned char i = 0; i < pinNum; ++i)
39. {
40. ledPwm[i] = ledPwm[i] * deltaPercent / 100;
41. if (ledPwm[i] <= deltaPwm)
42. ledPwm[i] = 0;
43. else
44. ledPwm[i] -= deltaPwm;
45.
46. if (i == head)
47. ledPwm[i] = initPwm;
48.
49. analogWrite(pins[i], ledPwm[i]);
50. }
51.
52. // 移動水滴頭
53. head = (head + 1) % pinNum;
54.
55. // 延時
56. delay(delayMs);
57.}
雨滴拖尾效果流水燈二——數(shù)字 IO 口模擬
前面只有 6 個 PWM 口實在是不過癮啊,來,我們把所有的 IO 口都用上,包括模擬口,它也是可以作為數(shù)字 IO 口使用的。
1.// ----------------------------------------------------------------------------
2.// digitalRaindropLEDS.ino
3.//
4.// Created 2015-06-04
5.// By seesea
6.//
7.// 數(shù)字引腳實現(xiàn)的雨滴流動效果
8.// 雨滴流動效果與流水燈(跑馬燈)的區(qū)別在于雨滴流水效果有拖尾效果,即亮過的燈是慢慢熄滅的
9.//
10.// 使用 UNO 的所有引腳用模擬 PWM 實現(xiàn)雨滴流動的效果,包括模擬輸入口也可以用做數(shù)字輸出
11.// 各引腳接 LED 正極,LED 負極接 GND
12.// ----------------------------------------------------------------------------
13.
14.const unsigned char leds[] = { A5, A4, A3, A2, A1, A0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 }; // 所有的引腳按 LED 接線順序排列
15.const unsigned int maxPwm = 100; // 手工模擬 PWM,可以自己定義最大的 PWM 值是多少,所以定義一個整百整千的數(shù)比較方便計算
16.const unsigned int initPwm = 100; // 最亮的燈的 pwm 值,即移動的時候在最頭一個燈的亮度
17.const unsigned int deltaPwm = 1; // 燈慢慢熄滅的 pwm 值,后一個燈比前一個燈暗多少。這相當于是一個等差隊列。等差的亮度感覺不大好,所以引入下一個等比的因素
18.const unsigned int deltaPercent = 70; // 后一個燈比前一個燈暗,其亮度是前一個燈的百分之幾。相對于前面的遞減,這個相當于是等比級數(shù)
19.const unsigned long delayMs = 70; // 移動延遲,單位 ms
20.const unsigned char ledNum = sizeof(leds) / sizeof(leds[0]);// 引腳數(shù)量,即 LED 個數(shù)
21.
22.unsigned int ledPwm[ledNum]; // 存放運行時每一個 LED 的亮度 PWM 值
23.
24.void setup()
25.{
26. for (char i = 0; i < ledNum; ++i)
27. {
28. pinMode(leds[i], OUTPUT);
29. ledPwm[i] = 0;
30. }
31.}
32.
33.extern volatile unsigned long timer0_millis; // 聲明外部變量 timer0_millis 以便在程序中使用,其實就是 millis() 的返回值——程序運行的毫秒數(shù)
34.void loop()
35.{
36. static unsigned char head = 0;
37. static unsigned long lastTick = timer0_millis;
38. unsigned int i, j;
39.
40. // 先亮燈,等占空比到切換點的時候滅燈
41. for (i = 0; i < ledNum; ++i)
42. {
43. if (ledPwm[i] == 0)
44. continue;
45.
46. digitalWrite(leds[i], HIGH);
47. }
48.
49. // 水滴頭是最亮的
50. ledPwm[head] = initPwm;
51.
52. // 這里就是數(shù)字口模擬的 PWM 程序了
53. for (i = 0; i < maxPwm; ++i)
54. {
55. for (j = 0; j < ledNum; ++j)
56. {
57. if (i == ledPwm[j])
58. digitalWrite(leds[j], LOW);
59. }
60.
61. delayMicroseconds(1);
62. }
63.
64. // 如果延時時間還沒到,先跳出,不進行水滴的移動
65. // 由于是用數(shù)字口模擬的 PWM,程序要不停的跑,不能使用 delay() 來延時,會卡住的
66. if (timer0_millis - lastTick < delayMs)
67. return;
68.
69. lastTick = timer0_millis;
70.
71. // 處理每一個燈的亮度
72. for (i = 0; i < ledNum; ++i)
73. {
74. ledPwm[i] = ledPwm[i] * deltaPercent / 100;
75. if (ledPwm[i] <= deltaPwm)
76. ledPwm[i] = 0;
77. else
78. ledPwm[i] -= deltaPwm;
79.
80. if (i == head)
81. ledPwm[i] = initPwm;
82. }
83.
84. // 移動水滴頭
85. head = (head + 1) % ledNum;
86.}
POV搖搖棒是時候舞起來了,搖起來吧。
1.// ----------------------------------------------------------------------------
2.// povLEDS.ino
3.//
4.// Created 2015-05-31
5.// By seesea
6.//
7.// 搖搖棒
8.//
9.// pin 0 - 7 接 LED 正極,LED 負極接 GND
10.// pin 8 接水銀開關(guān)一腳,水銀開關(guān)另一腳接 GND
11.// 水銀開關(guān)水平于搖動方向固定放置。如果實際效果與預(yù)想效果水平相反,只要把水銀開關(guān)兩腳的接線互換就可以了
12.// 注意:由于 pin 0 1 通過 LED 接地了,下載的時候需要斷開才能下載成功
13.// ----------------------------------------------------------------------------
14.
15.const unsigned char key = 8; // 水銀開關(guān)
16.const unsigned char delayTimeMs = 2; // 掃描時LED的點亮延時
17.
18.// 取模軟件使用縱向8點上高位的方式取模
19.unsigned char col[] =
20.{
21. // 心
22. // 0x30,0x48,0x44,0x22,0x44,0x48,0x30,0x00
23.
24. // I 心 U
25. 0x82,0xFE,0xFE,0x82,0x00,0x30,0x78,0x7C,
26. 0x3E,0x7C,0x78,0x30,0x00,0xFC,0xFE,0x02,
27. 0x02,0xFE,0xFC,0x00,0x00,0x00
28.
29. /* 1 2 3
30. 0x00,0x42,0xFE,0x02,0x00,0x00,0x00,0x00,
31. 0x46,0x8A,0x92,0x92,0x62,0x00,0x00,0x00,
32. 0x84,0x82,0x92,0xB2,0xCC,0x00
33. */
34.};
35.
36.unsigned char cols = (sizeof(col) / sizeof(col[0]));
37.
38.void setup()
39.{
40. DDRD = 0xFF;
41. pinMode(key, INPUT_PULLUP);
42.}
43.
44.void loop()
45.{
46. char i = 0;
47. char keyValue = digitalRead(key);
48. char delta = 1;
49.
50. if (keyValue == 1) // 搖動方向由右向左的時候
51. {
52. // 這里可以嘗試兩種方案
53. // 一種是向左掃的時候熄滅所有燈
54. // 另一種是反向點亮各列,從而由于方向也是反的,顯示就變回正的
55. // 根據(jù)需要,把 if 條件改成 0 或 1 可以選擇不同的方案
56. // 第一種方案的優(yōu)點是不容易有重影,但缺點是亮度低
57. // 第二種方案的優(yōu)缺正好相反
58. if (0)
59. {
60. // 向左搖熄滅所有燈
61. i = 0;
62. PORTD = 0x00;
63.
64. // 如果選擇這種方案就不需要繼續(xù)下面的掃描了,return掉即可
65. return;
66. }
67. else
68. {
69. delta = -delta;
70. }
71. }
72.
73. if (delta == 1)
74. {
75. // 向右搖的時候
76. for (i = 0; i < cols; ++i)
77. {
78. PORTD = col[i];
79. delay(delayTimeMs);
80. }
81. }
82. else
83. {
84. // 向左搖的時候
85. for(i = cols - 1; i >= 0; --i)
86. {
87. PORTD = col[i];
88. delay(delayTimeMs);
89. }
90. }
91.}
接線圖我覺得得上一下,效果圖嘛,從幾百張照片里挑個好看的來:
靜態(tài)數(shù)碼管顯示
總站成一排多無聊,是時候改改造行了。現(xiàn)在排成 8 字吧。先點亮一個 8 字,用靜態(tài)顯示方法。
1.// ----------------------------------------------------------------------------
2.// static7segLEDS.ino
3.//
4.// Created 2015-06-06
5.// By seesea
6.//
7.// 靜態(tài)七段數(shù)碼管
8.// 使用 PORTD 靜態(tài)顯示七段數(shù)碼管,循環(huán)顯示 0 - F
9.//
10.// 這里使用的是共陽七段數(shù)碼管,如果使用共陰的,只要把段碼表取反即可
11.// 數(shù)碼管段的順序按如下標示排列
12.//
13.// A
14.// ---
15.//F| G |B
16.// ---
17.//E| D |C
18.// ---. DP
19.//
20.// 然后根據(jù)需要顯示的數(shù)字生該段點亮輸出 1,可以制作段碼表。這種方式做出來的是共陰的,所以使用的時候取反即為共陽的段碼
21.// +---+--+--+--+--+--+--+--+--+-----+
22.// | | A| B| C| D| E| F| G|DP| 段碼|
23.// +---+--+--+--+--+--+--+--+--+-----+
24.// | 0 | 1| 1| 1| 1| 1| 1| 0| 0| 0xFC|
25.// +---+--+--+--+--+--+--+--+--+-----+
26.// | 1 | 0| 1| 1| 0| 0| 0| 0| 0| 0x60|
27.// +---+--+--+--+--+--+--+--+--+-----+
28.// | 2 | 1| 1| 0| 1| 1| 0| 1| 0| 0xDA|
29.// +---+--+--+--+--+--+--+--+--+-----+
30.// | 3 | 1| 1| 1| 1| 0| 0| 1| 0| 0xF2|
31.// +---+--+--+--+--+--+--+--+--+-----+
32.// | 4 | 0| 1| 1| 0| 0| 1| 1| 0| 0x66|
33.// +---+--+--+--+--+--+--+--+--+-----+
34.// | 5 | 1| 0| 1| 1| 0| 1| 1| 0| 0xB6|
35.// +---+--+--+--+--+--+--+--+--+-----+
36.// | 6 | 1| 0| 1| 1| 1| 1| 1| 0| 0xBE|
37.// +---+--+--+--+--+--+--+--+--+-----+
38.// | 7 | 1| 1| 1| 0| 0| 0| 0| 0| 0xE0|
39.// +---+--+--+--+--+--+--+--+--+-----+
40.// | 8 | 1| 1| 1| 1| 1| 1| 1| 0| 0xFE|
41.// +---+--+--+--+--+--+--+--+--+-----+
42.// | 9 | 1| 1| 1| 1| 0| 1| 1| 0| 0xF6|
43.// +---+--+--+--+--+--+--+--+--+-----+
44.// | A | 1| 1| 1| 0| 1| 1| 1| 0| 0xEE|
45.// +---+--+--+--+--+--+--+--+--+-----+
46.// | B | 0| 0| 1| 1| 1| 1| 1| 0| 0x3E|
47.// +---+--+--+--+--+--+--+--+--+-----+
48.// | C | 0| 0| 0| 1| 1| 0| 1| 0| 0x1A|
49.// +---+--+--+--+--+--+--+--+--+-----+
50.// | D | 0| 1| 1| 1| 1| 0| 1| 0| 0x7A|
51.// +---+--+--+--+--+--+--+--+--+-----+
52.// | E | 1| 0| 0| 1| 1| 1| 1| 0| 0x9E|
53.// +---+--+--+--+--+--+--+--+--+-----+
54.// | F | 1| 0| 0| 0| 1| 1| 1| 0| 0x8E|
55.// +---+--+--+--+--+--+--+--+--+-----+
56.// ----------------------------------------------------------------------------
57.
58.// 共陽段碼表 0 - F
59.const unsigned char segTable[] = {
60. ~0xFC, ~0x60, ~0xDA, ~0xF2, ~0x66, ~0xB6,
61. ~0xBE, ~0xE0, ~0xFE, ~0xF6, ~0xEE, ~0x3E,
62. ~0x1A, ~0x7A, ~0x9E, ~0x8E
63. };
64.
65.void setup()
66.{
67. DDRD = 0xFF; // PORTD 設(shè)置為輸出
68.}
69.
70.void loop()
71.{
72. for (char i = 0; i < sizeof(segTable) / sizeof(segTable[0]); ++i)
73. {
74. PORTD = segTable[i];
75. delay(500);
76. }
77.}
動態(tài)數(shù)碼管顯示
上面是一位數(shù)碼管的顯示,可以使用靜態(tài),如果要顯示多位,那可得動起來了。
1.// ----------------------------------------------------------------------------
2.// dynamic7segLEDS.ino
3.//
4.// Created 2015-06-06
5.// By seesea
6.//
7.// 動態(tài)七段數(shù)碼管
8.// 動態(tài)顯示七段數(shù)碼管,從 0000 開始計數(shù),9999 后回 0
9.//
10.// 使用 PORTD 進行段選,使用 pin 8 9 10 11 進行位選
11.// ----------------------------------------------------------------------------
12.
13.#define COM_ON HIGH// 共陽數(shù)碼管啟用的公共端電平
14.#define COM_OFF LOW // 共陽數(shù)碼管禁用的公共端電平
15.
16.// 共陽段碼表 0 - F
17.const unsigned char segTable[] = {
18. ~0xFC, ~0x60, ~0xDA, ~0xF2, ~0x66, ~0xB6,
19. ~0xBE, ~0xE0, ~0xFE, ~0xF6, ~0xEE, ~0x3E,
20. ~0x1A, ~0x7A, ~0x9E, ~0x8E
21.};
22.
23.const unsigned char pinPos[] = { 8, 9, 10, 11 }; // 位選管腳,按從低位到高位的排列
24.const unsigned intinitNum= 0; // 計數(shù)初始值
25.const unsigned intmaxNum = 9999; // 最大計數(shù)
26.const unsigned char com_num= sizeof(pinPos) / sizeof(pinPos[0]);// 公共端的數(shù)量,用于確定有幾位
27.const unsigned long delayMs= 50; // 動態(tài)掃描延遲時間
28.
29.void setup()
30.{
31. DDRD = 0xFF; // PORTD 設(shè)置為輸出
32. for (char i = 0; i < sizeof(pinPos) / sizeof(pinPos[0]); ++i)
33. {
34. pinMode(pinPos[i], OUTPUT);
35. }
36.}
37.
38.// 于七段數(shù)碼管上顯示數(shù)字 num
39.// 將 num 數(shù)字的個十百千等各位的數(shù)字一位一位分離出來顯示到每一位數(shù)碼管上
40.void display7segLED(unsigned int num)
41.{
42. unsigned int digital;
43. for (unsigned char i = 0; i < com_num; ++i)
44. {
45. digital = num % 10;
46. num /= 10;
47.
48. PORTD = segTable[digital];
49. digitalWrite(pinPos[i], COM_ON);
50.
51. delayMicroseconds(10);
52. digitalWrite(pinPos[i], COM_OFF); // 傳說中的消隱,避免發(fā)生重影
53. }
54.}
55.
56.void loop()
57.{
58. static unsigned long lastTick = millis();
59. static unsigned intnum = initNum;
60.
61. display7segLED(num);
62.
63. // 動態(tài)掃描,不能用 delay 阻塞式的延遲哦,前面試驗過的這種用法現(xiàn)在派上用場了
64. if (millis() - lastTick < delayMs)
65. return;
66.
67. lastTick = millis();
68. ++num;
69. if (num >= maxNum)
70. num = initNum;
71.}
都學會了嘛~還沒看過癮?!
-
led
+關(guān)注
關(guān)注
242文章
23277瀏覽量
660894 -
流水燈
+關(guān)注
關(guān)注
21文章
433瀏覽量
59716
原文標題:Arduino點燈玩成這樣,也是沒誰了
文章出處:【微信號:eet-china,微信公眾號:電子工程專輯】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論