跳转至内容

Oberon/ETH Oberon/speaker

来自 Wikibooks,开放世界中的开放书籍

该文档最初托管在ETHZ。它仍在 ETH 许可证 下,并且位于 WayBack 存档 中。

返回:本机 Oberon 硬件兼容性列表

 
扬声器支持
 
摘要

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/

华夏公益教科书