8位单片机随机数
量不高。随机数是一个既简单又复杂的问题,这里的例子使用了众所周知的线性叠加法,没
有完美的方法产生随机数,不过线性叠加法是一个合适的方法,彻底解决8位机随机数的问
题。
伪随机数函数总是返回可预知的数字,像抛骰子,如果抛足够多次,那么我们得到了一
个足够长的数字序列,
3,1,5,1,4,6,5,4,6,5,4,5,6,1,3,2,1,6,4,6,5,4,3,2,1,3,2,1,4,2,3,1,3......
如果从序列中一个接一个的取出数字,那么数字就看似随机。
问题的关键是从这序列的哪个点(数字)开始取数?这个开始的点(数字)叫做种子。
注意,如果从相同的点(种子)开始,将会得到相同的数字,这是因为我们是从固定的序
列中取数字(所以叫伪随机)。但这却是一个有用的特性,我们可以每次从不同的点取数,即
改变种子!
在6502上,8位或16位随机数是最常用的,函数返回一个32位的数字,范围0~2^32。名
词"线性叠加"听起来容易范晕, 其实只涉及二个内容:乘法和加法。三个步骤:
1. 为了取得新的种子(也就是从序列开始的那个点的数字),旧的种子和一个常数A相乘,
2. 所得结果然后和第二个常数c相加。
3. 新的种子是结果的低32位(记住,这个函数返回32位数字)。保留低32位很重要,用来获
得下一个种子。
计算公式:
种子 = A * 种子 + C
此公式在几何图中表示一条直线,而且新种子由旧种子反复相加得来,所以叫线性叠加。
随机数函数的关键在于选择优秀的"常数A"(也叫乘数A),其实也就是选择了一个固定
的数字序列。"常数c",不像乘数A那样重要,但是它一定是个奇数。事实上, c可选1,而
且这是例程所使用的,因为它会简化计算。
注意,奇数(旧的种子)乘奇数(乘数A)是奇数,再加奇数(常数c)将会是一个偶数;偶数
(旧的种子)乘奇数(乘数A),加奇数(常数c)将会是一个奇数。如此种子将会在奇数和偶数之
间转变。因为种子的变化足够随机,所以新种子的值可以作为8位或16位随机数。
子程序F_RandomSeed,计算 "种子 = 乘数 * 种子+1" (记得,c=1)。有三个版本:
(1) 快速版本, 速度快,但占用Rom多。
(2) 兼顾版本,速度和占用Rom适中,空间和速度是在另外二个版本之间。
兼顾版B, 使用了另一个神奇的数字66066(10进制).
(3) 最小版本,速度慢,但占用Rom小。
三个版本中使用的乘数1664525(10进制)=19660D(16进制),是从计算机程序的艺术,
第2册>>一书中选出,这是一个神奇的数字,经过论证和测试,这个数字对产生随机数至
关重要。想进一步研究的朋友可以阅读原著(参考资料2),书中以特别专业的数学方法讨论
了随机数问题。这里只是应用了其中的两个常数1664525(10进制)和69069(10进制),这里不
作讨论,因为篇幅问题是借口,其实自己没弄懂。
;==============================================================================
; 快速版本
;==============================================================================
丰收先要选好种子,育种很重要,同样,获得随机种子是重要的一步。
种子变量设定在零页RAM可以提高速度。
程序F_RandomSeed计算 1664525*种子,需要5个字节(R_Seed0~R_Seed3,R_Temp)。
F_GeneratTables预先计算1664525*X(x=0~255),生成四个256字节的列表T3,T2,T1,T0.
T3,X = 表T3的第X字节 = 1664525 * X的第31~24位(X = 0 to 255)
T2,X = 表T2的第X字节 = 1664525 * X的第23~16位(X = 0 to 255)
T1,X = 表T1的第X字节 = 1664525 * X的第15~ 8位(X = 0 to 255)
T0,X = 表T0的第X字节 = 1664525 * X的第 7~ 0位(X = 0 to 255)
对于单片机来说 使用1K RAM很夸张,也可以不用F_GeneratTables,直接把随机数表存
在ROM中。
;==============================================================================
; 伪随机数函数的线性叠加
; 计算 Seed = 1664525 * Seed + 1
;------------------------------------------------------------------------------
; 输入:
; R_Seed0 --- 种子0
; R_Seed1 --- 种子1
; R_Seed2 --- 种子2
; R_Seed3 --- 种子3
; 回返:
; 种子0 ---> R_Seed0
; 种子1 ---> R_Seed1
; 种子2 ---> R_Seed2
; 种子3 ---> R_Seed3
; 重写
; R_Temp
;------------------------------------------------------------------------------
; 为提高速度R_Seed0,R_Seed1,R_Seed2,R_Seed3,R_Temp选零页Ram
; 每张列表从Rom地址 xx00h 处开始 或在Rom中
;------------------------------------------------------------------------------
; 空间: 程序58个字节
;
8位单片机随机 相关文章:
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)