跳轉至內容

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/

華夏公益教科書