# <center>2. 蜂鳴器_數位類比轉換器</center> <p style="text-align:right">Steven Lee</p> ## 蜂鳴器 * 蜂鳴器基本上分為兩種:有源蜂鳴器和無源蜂鳴器. * 這裡的“源”不是指電源。⽽是指震盪源。 * 有源蜂鳴器 * 有源蜂鳴器內部帶震盪源,所以只要⼀通電就會發出聲響, 輸入不同的⽅波頻率時, 也會產⽣不同的聲響. * 無源蜂鳴器 * 有稱為Passive被動式, 類似於喇叭, 因為內部沒有震盪來源, 所以⼀定要輸入⽅波才有聲⾳. * active buzzer * "-" : GND * "S" : GPIO * 中間的VCC: 5V ![](https://i.imgur.com/r0Sd6CG.png) ![](https://i.imgur.com/HJ32DSQ.png) ``` python= import RPi.GPIO as GPIO GPIO.setwarnings(False) GPIO.setmode(GPIO.BOARD) GPIO.setup(19, GPIO.OUT) while True: select = int(input("Please select the type of output <1-3>, 0:exit -> ")) if select == 0: GPIO.output(19, 0) break if select == 1: for i in range(1000): for j in range(250): GPIO.output(19,1) for j in range(250): GPIO.output(19,0) if select == 2: for i in range(1000): for j in range(250): GPIO.output(19,1) for j in range(1000): GPIO.output(19,0) if select == 3: for i in range(1000): for j in range(1000): GPIO.output(19,1) for j in range(250): GPIO.output(19,0) ``` ![](https://i.imgur.com/aoW8aon.png) * passive buzzer * "-" : GND * "S" : GPIO * 中間的VCC: 5V ``` python= import RPi.GPIO as GPIO GPIO.setwarnings(False) GPIO.setmode(GPIO.BOARD) GPIO.setup(21, GPIO.OUT) while True: select = int(input("Please select the type of output <1-3>, 0:exit -> ")) if select == 0: GPIO.output(21, 0) break if select == 1: for i in range(1000): for j in range(250): GPIO.output(21,1) for j in range(250): GPIO.output(21,0) if select == 2: for i in range(1000): for j in range(250): GPIO.output(21,1) for j in range(1000): GPIO.output(21,0) if select == 3: for i in range(1000): for j in range(1000): GPIO.output(21,1) for j in range(250): GPIO.output(21,0) ``` ## 思考⼀下: 比較聲⾳有何差異? ## 思考⼀下: 如何控制⾳量⼤⼩? ## 讓電⼦元件唱歌 * https://zh.wikipedia.org/wiki/%E9%9F%B3%E7%AC%A6 ![](https://i.imgur.com/pKCiXaB.png) * Let's sing a song ``` python= import RPi.GPIO as GPIO import time GPIO.setwarnings(False) GPIO.setmode(GPIO.BOARD) GPIO.setup(21, GPIO.OUT) GPIO.output(21, 1) p1 = GPIO.PWM(21, 10) p1.start(0) # dc is 0 # 1155665 0 4433221 0 5544332 0 5544332 0 1155665 0 4433221 sheets = [262,262,392,392,440,440,392,0, 349,349,330,330,294,294,262,0, 392,392,349,349,330,330,294,0, 392,392,349,349,330,330,294,0, 262,262,392,392,440,440,392,0, 349,349,330,330,294,294,262] for s in sheets: if s == 0: p1.ChangeDutyCycle(0) else: p1.ChangeFrequency(s) p1.ChangeDutyCycle(50) time.sleep(0.2) p1.ChangeDutyCycle(0) time.sleep(0.1) p1.stop() ``` ## 請同學實作其他旋律 ## I2C * I²C(Inter-Integrated Circuit)為I²C Bus簡稱,所以中文應該叫積體電路匯流排,它是⼀種串列通訊匯流排,使⽤多主從架構,由⾶利浦公司在1980年代為了讓主機板、嵌入式系統或⼿機⽤以連接低速週邊裝置⽽發展。I²C的正確讀法為「I平⽅C」("I-squared-C"),⽽("I-two-C")則是另⼀種錯誤但被廣泛使⽤的讀法。 * I²C的參考設計使⽤⼀個7位元⻑度的位址空間但保留了16個位址,所以在⼀組匯流排最多可和112個節點通訊。常⾒的I²C匯流排依傳輸速率的不同⽽有不同的模式:標準模式(100 kbit/s)、低速模式(10 kbit/s),但時脈頻率可被允許下降⾄零,這代表可以暫停通訊。⽽新⼀代的I²C匯流排可以和更多的節點(⽀援10位元⻑度的位址空間)以更快的速率通訊:快速模式(400 kbit/s)、⾼速模式(3.4 Mbit/s)超⾼速模式(5Mbit/s)。 * I2C Bus 架構及介⾯接腳, 它是以匯流排型式介接,同時匯流排上允許有多個 master (主設備) 和多個slave (從設備). ![](https://i.imgur.com/r0JiwbA.png) * I2C 的匯流排接線⼗分簡單,只有兩條訊號線: * 資料線 (SDA,Serial Data Line) * 時脈線 (SCL,Serial Clock Line) * I2C 的 I/O 接腳不管是 master 或 slave的這⼆⽀接腳都是 CMOS Open Drain 或者是 TTL Open Collector * 並不輸出某⼀特定電壓值或電流值, 輸出的電壓必需由外部決定. * I2C Bus 為 Wired-AND(AND 閘的邏輯狀態當全部輸入是 High 時,輸出為 High ; 只要任何⼀個輸入為Low 時,輸出即為 Low)。所以當全部的晶片輸出為High時,接線可測到High;但只要有⼀晶片輸出為Low是接線則會測到Low。 ## I2C Bus 資料傳輸 * Start : SCL 為 High 時,SDA 由 High 轉為 Low。S黃⾊區域 * Stop: SCL 為 High 時,SDA 由 Low 轉為 High。P黃⾊區域 * SCL 為 Low 時,SDA 可以改變資料。藍⾊區域。 * SCL 為 High 時,SDA 必需保持訊號穩定,不可以改變,以⽅便對⽅讀取資料。綠⾊區域。 ![](https://i.imgur.com/wthKWhT.png) ## I²C的傳輸步驟 * 使⽤I²C時,數據被轉換成messages,messages則被分解為data frames。每條messages都有⼀個address frame,其中包含從裝置(slave)的⼆進位地址,以及⼀個或多個包含正在傳輸的數據的data frame。 Messages還包括每個data frame之間的start和stop條件,read/write和ACK / NACK bit. ![](https://i.imgur.com/FIkUWNk.png) * start condition: SCL: 從High切換到Low 之前, SDA: 從High切換到Low * stop condition: SCL: 從Low切換到High 之前, SDA: 從Low切換到High * read/write bit: 主裝置(master)向slave 發送data(low), 從slave請求data)(high) * ACK/NACK bit: 回應訊號 * I²C沒有slave選擇線, 因此只有⼀個⽅法能讓slave知道data正在發送給他, 透過message中的第⼀個address frame來得知. * master將想要與slave設備的地址發送給每個連接的slave設備. 然後每個slave設備從master設備發送的address與⾃⼰比較. 如果相同, 則將Low ACK訊號發回master主機. 若不相同則不執⾏任何操作, SDA維持在high ![](https://i.imgur.com/3KRfJTr.png) ![](https://i.imgur.com/zgYaJo4.png) * 發送數據 ![](https://i.imgur.com/8EPkZOE.png) * 傳輸data frame後, slave device回送ACK (OW), 給Master確認 ![](https://i.imgur.com/WEulndw.png) * 多個I²C設備連接⽅式 ![](https://i.imgur.com/qQlcjYg.png) ## AD/DA 轉換器 * 數位訊號 * 離散時間, 不連續的訊號 * 類比訊號 (⾃然界現象) * 連續時間, 連續訊號 * A/D 轉換器(Aanlog-to-Digitial Converter, ADC), 將類比訊號轉換成數位訊號的裝置. * D/C 轉換器(Digital-to-Analog Converter, DAC), 將數位訊號轉換成類比訊號的裝置. * 轉換的階數 (Or ADC resolution) * 3 bit = 8 階 * 4 bit = 16階 * 8 bit = 256階 * 10 bit = 1024階 * 12 bit = 4096階 ![](https://i.imgur.com/AWCyKYT.png) ## AD/DA 轉換PCF 8591傳感器模組 ![](https://i.imgur.com/SjgERKG.png) ![](https://i.imgur.com/1LLdrkJ.png) * 4個analog的模擬輸入 * 1個analog的模擬輸出 * 1個I²C2的介⾯ * ⼯作電壓範圍: 2.5V - 6V * AD採樣為8-bit * A0: 電位計調節輸入電壓 * A1: 光敏電阻 * A2: 熱敏電阻 * A3: analog的模擬輸入 ## 查看I²C裝置的位置 ``` sudo i2cdetect -y 1 ``` ![](https://i.imgur.com/QQ8TEs1.png) ## 對應裝置analog 輸入接腳的位置 ``` A0 = 0x40 A1 = 0x41 A2 = 0x42 A3 = 0x43 ``` ## 控制 PCF 8591上的LED 燈透過A0 ``` python= import smbus import time address = 0x48 cmd = 0x40 value = 0 bus = smbus.SMBus(1) #使⽤/dev/i2c-1, 接線在pin 3, 5 while True: bus.write_byte_data(address, cmd, value) value += 1 if value == 256: value = 0 print(f"red led analog value is {value}") time.sleep(0.01) ``` ## 透過PCF 8591上的電位計調節輸入電壓控制AO ``` python= import smbus import time import math address = 0x48 A0 = 0x40 A1 = 0x41 A2 = 0x42 A3 = 0x43 bus = smbus.SMBus(1) while True: bus.write_byte(address,A0) bus.read_byte(address) value = bus.read_byte(address) bus.write_byte_data(address, A0, value) print(f"Current value is {value}") time.sleep(1) ``` ## 讀取 PCF 8591上的 光敏電阻, 透過A1 * 愈暗值愈⼤ ```python= import smbus import time import math address = 0x48 A0 = 0x40 A1 = 0x41 A2 = 0x42 A3 = 0x43 bus = smbus.SMBus(1) while True: bus.write_byte(address,A1) bus.read_byte(address) value = bus.read_byte(address) print(f"Current value is {value}") time.sleep(1) ``` ## 熱敏電阻公式 * NTC THERMISTOR (NEGATIVE TEMPERATURE COEFFICIENT THERMISTOR), 溫度上升電阻值下降 * NTC 熱敏電阻溫度計算公式:Rt = R EXP(B(1/T1-1/T2)) * T1和T2指的是K度, K:開爾文溫度 * 絕對零度 = 0K,等於攝⽒溫標零下273.15度(即−273.15℃) * Rt 是熱敏電阻在T1溫度下的阻值。 * R是熱敏電阻在T2常溫下的標稱阻值。 * 100K的熱敏電阻25℃的值為100K(即R=100K) * T2=(273.15+25) * B值是熱敏電阻的引數 * T1=1/(ln(Rt/R)/B+1/T2) ![](https://i.imgur.com/vIL89EI.png) ```python= import smbus import time import math address = 0x48 A0 = 0x40 A1 = 0x41 A2 = 0x42 A3 = 0x43 bus = smbus.SMBus(1) vin = 3.3 R = 10000 B = 3950.0 T2 = 273.15+25.0 while True: bus.write_byte(address,A2) bus.read_byte(address) value = bus.read_byte(address) v = vin*(value/255) rt = R*(v/(vin-v)) t1 = 1/((math.log(rt/R)/B)+(1/T2)) t = int((t1 - 273.15)*100)/100 print(value) print(f"Current temperature is {t}") time.sleep(1) ``` ## 讀取 PCF 8591上的Analog輸入, 透過A3 * A0類比輸出腳位,可以接到PCF 8591上的Analog輸入腳位,得到0~1023的數值。⽽D0數位輸出腳位,則是依Threshold Value(⾨檻值),來決定輸出LOW或HIGH,⽽「⾨檻值」則可以由板⼦上的可變電阻來 調整:順時針,⾨檻值提⾼;逆時針,⾨檻值降低;調整時可以看綠燈有沒有亮。 ```python= import smbus import time address = 0x48 A0 = 0x40 A1 = 0x41 A2 = 0x42 A3 = 0x43 bus = smbus.SMBus(1) while True: bus.write_byte(address,A3) bus.read_byte(address) value = bus.read_byte(address) print(value) print(f"Current value is {value}") time.sleep(0.1) ``` ###### tags: `物聯網`