Skip to content

Arduino - 随机数

在涉及游戏、模拟或不可预测行为的项目中,生成随机数是一个常见需求。Arduino 核心提供了生成伪随机数的简单函数。

计算机,包括微控制器,是确定性机器。它们本身无法生成真正的随机数。相反,它们使用数学公式生成一系列看似随机的数字,但如果您知道起始点,这些数字实际上是可以预测的。这被称为伪随机序列,而起始点则称为种子(seed)。

如果每次都使用相同的种子,您将得到完全相同的“随机”数字序列。为了让我们的程序感觉真正随机,我们必须提供一个不可预测的种子。

randomSeed() 函数使用一个种子值初始化伪随机数生成器。它应该只调用一次,通常在您的 setup() 函数中。为了获得一个好的种子,我们需要一个不可预测的来源。在 Arduino 上,一种常见的技术是读取未连接的模拟引脚上的电噪声。

// 使用浮空模拟引脚的环境噪声为生成器播种。
// 这使得每次电路板上电时序列都不同。
randomSeed(analogRead(A0));

一旦播种,random() 函数就会生成序列中的下一个数字。它有两种用法。

// 生成一个介于 0 和 (max - 1) 之间的随机数
long randomNumber = random(max);
// 生成一个介于 min 和 (max - 1) 之间的随机数
long randomNumber = random(min, max);

重要提示:范围中的最大值是不包含的(exclusive)。例如,random(1, 7) 将返回集合 {1, 2, 3, 4, 5, 6} 中的一个数字,这非常适合模拟标准骰子投掷。

这个 sketch 模拟每两秒投掷一次六面骰子,并将结果打印到串口监视器。

/*
数字骰子模拟器
这个 sketch 演示了如何正确地播种并生成
特定范围内的随机数。
*/
void setup() {
// 启动串口通信以显示结果
Serial.begin(9600);
// 等待串口连接。对于原生 USB 端口的开发板(例如 Leonardo)需要此行
while (!Serial) {
; // 等待
}
// 播种随机数生成器。使用浮空模拟引脚是一种简单的方法,
// 可以在每次上电时获得不同的种子。
randomSeed(analogRead(A0));
Serial.println("--- 随机骰子投掷 ---\n");
}
void loop() {
// 生成一个 1 到 6(包含)之间的随机数。
// random() 的上限是独占的,所以我们使用 7。
long dieRoll = random(1, 7);
Serial.print("您掷出了:");
Serial.println(dieRoll);
// 等待 2 秒钟,然后进行下一次投掷
delay(2000);
}

理解数字的存储方式会很有帮助。数据的基本单位是位(bit),它可以是 0 或 1。8 个位组成一组称为字节(byte)。一个字节可以表示 2^8 = 256 种不同的值(通常是 0 到 255)。

  • random() 函数返回一个 long 类型的值,它是一个 4 字节(32 位)的数字,允许非常大的可能值范围。
  • 位在字节中的位置决定了它的值。最右边的位是最低有效位(LSB,Least Significant Bit),最左边的位是最高有效位(MSB,Most Significant Bit)。