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/