Oberon/ETH Oberon/speaker
外观
< Oberon | ETH Oberon
该文档最初托管在ETHZ。它仍在 ETH 许可证 下,并且位于 WayBack 存档 中。
扬声器支持
摘要
PC 扬声器是一个穷人的声音发生器,只能发出可怜的哔哔声和尖叫声,但在 Oberon 中编程很简单。但是,由于使用了 SYSTEM 模块,因此代码不可移植。
如何通过程序控制扬声器
假设一个频率为 f 的声音应该在时间 t 内发出。系统 Timer 2(可编程间隔定时器 (PIT) 中的三个定时器之一)用于控制声音生成,分五个连续步骤。PIT 以 1.19318 MHz 的频率运行。
- 计算一个 2 字节计数器值(1 <= count <= 65'535),对应于指定的频率 f - IntFreq。1'193'180 >= f >= 18.2
- 向端口地址 43H 发送一个 PIT 控制字 - InitTimer
- 向端口地址 42H 发送计数器值 - SetFreq
- 在端口地址 61H 处设置控制寄存器中的位 0 和 1 为“开”,以打开扬声器和放大器 - Tone
- 经过时间延迟 t 后,在端口地址 61H 处将相同的位设置为“关” - Tone
时间延迟必须由后台任务控制。请注意,一旦扬声器“打开”,频率可以随意更改,甚至可以设置为不可听的声音以模拟静音。
程序片段
CONST TONES = 12; OCTAVES = 10; ON = TRUE; OFF = FALSE; A4 = 440; (* the latin "la" *) (* Convert the frequency to an "internal" value *) PROCEDURE IntFreq(hz: LONGINT): INTEGER; CONST Rate = 1193180; (* Timer clock is 1.19318 MHz *) BEGIN RETURN SHORT(Rate DIV hz) END IntFreq; (* Set PIT control word to: Timer 2, 16-bit, mode 3, binary = {01110110} i.e. B6H *) PROCEDURE InitTimer; (* Timer port address: 43H *) BEGIN SYSTEM.PORTOUT (43H, 0B6H) END InitTimer; (* Set counter value *) PROCEDURE SetFreq(hz: LONGINT); (* Timer 2 port address: 42H *) BEGIN SYSTEM.PORTOUT (42H, CHR(hz MOD 100H)); SYSTEM.PORTOUT (42H, CHR(hz DIV 100H)); Tone(ON) END SetFreq; (* Switch speaker and amplifier on/off *) PROCEDURE Tone(b: BOOLEAN); (* Loudspeaker port address: 61H *) VAR s: SET; BEGIN SYSTEM.PORTIN (61H, SYSTEM.VAL(CHAR, s)); IF b THEN s := s + {0, 1} ELSE s := s - {0, 1} END; SYSTEM.PORTOUT (61H, SYSTEM.VAL(CHAR, s)) END Tone; (* Calculate table of "internal" frequencies for a number of octaves *) PROCEDURE CalcTF; VAR t, oct: INTEGER; f, f0, df: REAL; BEGIN df := Math.exp(Math.ln(2) / TONES); f0 := A4 * df * df * df / 32; (* = c0 *) FOR oct := 0 TO OCTAVES-1 DO f := f0; FOR t := 0 TO TONES-1 DO TF[t, oct] := IntFreq(ENTIER(f)); f := f * df END; f0 := f0 * 2 END END CalcTF; (* Beep on the speaker: beepFreq during beepLen *) PROCEDURE Beep*; VAR wakeUp: LONGINT; BEGIN IF ~timerActive THEN InitTimer; SetFreq(beepFreq); wakeUp := Input.Time() + beepLen * (Input.TimeUnit DIV 1000); REPEAT UNTIL Input.Time() - wakeUp >= 0; Tone(OFF); timerActive := FALSE END END Beep;
2002 年 7 月 13 日 - 版权所有 © 2002 ETH Zürich。保留所有权利。
电子邮件:oberon at lists.inf.ethz.ch
主页:http://www.ethoberon.ethz.ch/