AVR單片機教程——隨機點亮LED


本文隸屬於AVR單片機教程系列。

 

之前我們做的閃爍LED和流水燈,燈效都是循環的。這次我們來嘗試一些不一樣的——每一次隨機選擇一個LED並點亮。

要實現隨機的效果,我們要用C語言標准庫中的相關設施:

1 #define RAND_MAX /*implementation defined*/
2 int rand();
3 void srand(unsigned seed);

以上設施都定義在 <stdlib.h> 中。其中,rand() 可以返回[0, RAND_MAX ]范圍內的偽隨機整數,srand() 用於給 rand() 提供種子,當種子相同時,多次調用 rand() 得到的序列是相同的,這就是為什么稱 rand() 產生的數為“偽隨機數”。如果使用 rand() 之前沒有調用過 srand() ,則相當於調用過 srand(1) 。

利用這些工具,很容易就能寫出一個隨機LED的程序:

 1 #include <ee1/led.h>
 2 #include <ee1/delay.h>
 3 
 4 #include <stdlib.h>
 5 
 6 int main()
 7 {
 8     led_init();
 9     // srand(1);
10     while (1)
11     {
12         led_set(rand() % 4, LED_ON);
13         delay(200);
14         led_off();
15     }
16 }

rand() 返回[0, RAND_MAX ]范圍內的整數,但 led_set 的第一個參數只有在 [0, 3] 范圍內才有效,因此我們把 rand() 的返回值對4取模。

srand(1) 被打上注釋,是因為這行調用沒有必要。

把這段代碼編譯並燒寫進單片機,你會發現LED閃爍的時間是不等長的,這是因為可能存在連續兩次亮相同燈的情況。為了解決這個問題,我們引入一個變量,保存當前亮的LED,並讓下一個亮的LED與當前的不同。代碼如下:

 1 #include <ee1/led.h>
 2 #include <ee1/delay.h>
 3 
 4 #include <stdint.h>
 5 #include <stdlib.h>
 6 
 7 int main()
 8 {
 9     led_init();
10     // srand(0);
11     uint8_t cur = rand() % 4;
12     while (1)
13     {
14         led_set(cur, LED_ON);
15         delay(200);
16         uint8_t next = rand() % 3;
17         if (next >= cur)
18             next++;
19         led_set(cur, LED_OFF);
20         cur = next;
21     }
22 }

使連續兩次不亮相同燈的核心代碼是16~18行。程序生成一個[0, 2]范圍內的隨機值,3種取值概率相等,然后當此值大於或等於當前亮燈值時,讓它自增。假設當前亮燈為1,則生成的隨機數在值為0、1、2的情況下分別變成(映射為)0、2、3,因此下一次亮燈就是在當前沒有亮的3個燈中等概率地選擇一個。

按開發板上的RESET鍵可以讓單片機復位。觀察LED序列,你會發現對於每一次復位,LED序列都是一樣的。這個問題我們暫時無法解決。

 

今天的作業:一個更復雜的隨機效果,每次亮1~2個燈,連續兩次不能有相同的燈亮,也不能都亮2個,總體來看亮2個的概率為1/3。

這里有一個hex文件,是作業的一個實現,以及一個.c源文件,把單片機程序的main函數復制到文件最后,用計算機的C編譯器編譯運行可以檢查算法是否正確。一個正確的結果應該跟這個差不多:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM