題:
Arduino如何輸出特定的(即56 kHz)載波頻率?
jlbnjmn
2014-02-24 06:55:35 UTC
view on stackexchange narkive permalink

我正在研究一個自由空間光學項目,以在兩點之間無線發送數據。為此,我使用了連接到Arduino Uno的IR LED,該IR LED發射器以56 kHz的載波頻率進行脈衝,第二個Arduino接收器以56 kHz的紅外檢測器模塊進行脈衝。

我嘗試過在引腳高和引腳低命令之間使用delayMicroseconds()來創建載波頻率。這種工作方式有效,但頻率並不總是相同,脈衝信號的任何其他延遲(即調用函數和遞減所需的時間)都可以改變它。

讀取數據表在ATmega328上,似乎有一種使用芯片的計時器來設置更精確的脈衝的方法。可以嗎?如果可以,如何使用計時器創建一個56 kHz的脈衝?

您的56KHz頻率需要多少精度?即您的項目可接受什麼頻率範圍?我問,因為僅使用Arduino定時器,精度就有局限性。
55.5khz至56.5khz是理想的,以便在檢測器中保持較高的響應度。
五 答案:
jfpoilpret
2014-02-25 02:45:44 UTC
view on stackexchange narkive permalink

確實可以用Arduino 定時器生成56 kHz信號。

定時器實際上可以看作是MCU中的一個特殊寄存器,其中包含一個值(從0開始)以MCU時鐘頻率(在Arduino Uno上為16 MHz)的頻率遞增,可能性除以稱為 prescaler 的因子。當該值達到您指定的稱為 Compare Match 的限制時,就會發生兩件事:

  • 計時器寄存器的值重置為0。
  • 調用一個 ISR (中斷服務例程)回調函數(您可以將其定義為指向您自己的代碼)。

該想法是使用該ISR會在每次被調用時更改邏輯引腳的輸出( HIGH ,然後是 LOW ,然後是 HIGH ...)。

現在,為了生成56 kHz方波,您需要每秒將ISR稱為 56000 * 2 次( * 2 因為您需要每個週期兩次更改輸出值。)

您可以從以下列表中選擇所需的定時器預分頻值:

  • 1(時鐘頻率)不被分頻,因此為16 MHz)
  • 8(時鐘頻率被8分頻,因此為2 MHz)
  • 64
  • 256
  • 1024

Arduino Uno上有兩種尺寸的計時器/計數器(它們(實際上稱為 timer / counter ):8位和16位。

在Arduino Uno(ATmega328P)上,您總共有三個定時器,但是Arduino內核可能會使用其中的一些庫或草圖中使用的其他庫(您必須自己檢查):

  • timer0(8位)
  • timer1(16位)
  • timer2(8位):這個具有更多的預縮放選項(1、8、32、64、128、256和1024)

現在您需要從16MHz產生56kHz的波,因此,如果不進行預分頻,您將需要計數為:

16000000 /(56000 * 2)-1 = 141.857 -1 ,因為計時器從0計數到該值,並且僅在之後重置已達到)

從此計算中,我們可以得出兩個觀察結果:

  1. 141.857 不是整數,因此您不會不能產生正好為56 kHz的波形。
  2. 沒有預分頻,您需要一個16位計時器,因為285不能表示為8位無符號整數。
  3. ol>

    從現在開始,您有兩個選擇:

    1. 使用16位計時器( timer1 ),使用prescaler = 1,然後選擇 142 作為比較匹配;這將為您提供以下頻率: 16000000 /(2 *(142 + 1))= 55944 Hz
    2. 使用8位定時器( timer0 ),使用prescaler = 8,然後選擇 17 作為比較匹配;在以下頻率下會降低精度: 16000000 /(8 * 2 *(17 + 1))= 55555 Hz 仍在所需範圍內。
    3. ol>

      現在,關於如何為此編寫草圖,我建議您檢查這本可指導的,它非常完整,而且非常有趣。

      當然, ATmega328P完整的數據表如果您想最詳細地了解自己在做什麼,也很重要。

      一些重要說明:

  • ISR是在禁用中斷的情況下執行的,因此必須盡可能短。特別是,Arduino庫中有一些函數不能從ISR調用。
  • Arduino Uno時鐘不是很準確(它使用陶瓷諧振器而不是石英,這本來很多更準確),因此這意味著輸出頻率將進一步偏移。
同樣,當達到指定的限制時,*硬件*可以切換引腳。因此,根本不需要使用ISR。 ISR總是會產生“抖動”,因為指令一旦開始就無法中斷。但是,硬件將始終以所需的速率切換引腳。
Arduino Uno使用陶瓷諧振器有點令人驚訝,但是它的來源是* [Arduino UNO FAQ](https://learn.adafruit.com/arduino-tips-tricks-and-techniques/arduino-uno-常見問題解答)*(*“附近的Uno是否使用諧振器或晶體作為處理器時鐘?” *)。
Peter Bloomfield
2014-02-24 18:02:05 UTC
view on stackexchange narkive permalink

我發現 tone()可用於在任何引腳上生成高頻脈衝。它應該能夠處理56 KHz。 (編輯:正如jfpoilpret所指出的,您在16 MHz Arduino上實際上可以獲得的最接近頻率約為55.944 KHz)

困難顯然是將其與數據信號結合在一起。我認為您不依靠低級代碼就無法在軟件中做到這一點。

您所需要做的就是將數據信號輸出到不同的引腳上,然後使用與門將其與載波相結合。合併後的信號可以直接發送到您的IR發射器。

如果您沒有AND門,那麼使用一對晶體管來製作自己的門很簡單。只需在線搜索“晶體管和柵極”即可。

接收器通常通常具有低電平有效輸出。如果將LED的頂部連接至56khz,底部連接至數據引腳,則當數據引腳變為低電平時,您將獲得IR輸出,這將使接收器變為低電平。無需柵極,只需一個LED和一個電阻。唯一的問題是電流io引腳可以驅動的範圍。
zzz
2014-04-01 09:10:47 UTC
view on stackexchange narkive permalink

jfpoilpret的公認答案寫得很好,非常有效,在99%的情況下,我都會按照他的解釋做。他的解決方案完全在您定義的參數之內,因此它們應該運作良好。但是,什麼比“ 很好”更好? 完美!畢竟,問題在於要產生確切的價值。正如所說的,在大多數情況下(可以說是所有情況),足夠接近是好的,即使當以1秒鐘需要1秒鐘作為時鐘處理某些東西時,您仍然必須遭受繼承零件的缺陷。

我要做什麼會提示並非總是可能的。在某些情況下,這是可能的,但是比這種情況要麻煩和多得多。是否值得視情況而定。我的目標主要是為將來的參考提供替代方法,在某些情況下更好。本書是針對沒有電子經驗的Arduino新手編寫的。

對於更高級的人來說,這可能看起來太冗長和笨拙了。但我相信,這些人可能已經知道並且不需要這個答案。這也適用於每個微控制器,每個製造商和體系結構。但是對於其他微控制器,您將需要查閱正確的數據表以找到正確的寄存器以及預分頻器的名稱和值。

在您的情況下,您需要一個特定的頻率,其好處是,恰好56實際上,可以很容易地實現kHz(不計算零件的實際缺陷)。因此,這也是一個完美的示例案例。

生成信號取決於微控制器的計時器和時鐘源,如jfpoilpret所述。他的回答僅涉及一種觀點問題,並且擺弄了定時器。但是,您也可以擺弄時鐘源,甚至可以同時擺弄時鐘,以獲得協同作用和出色的結果。通過更改環境參數(在這種情況下,是對系統進行黑客攻擊並更換時鐘源),我們可以輕鬆,簡單得多地處理特定問題。

首先提醒一下,由於切換在引腳狀態下,您需要執行比信號頻率高兩倍的ISR。這是每秒112,000次。正如已經指出的,56,000和16,000,000的總和並不十分理想。我們需要更改信號頻率或間歇頻率。現在讓我們處理一個不變的信號頻率並找到更好的時鐘速度。

選擇一個比56 kHz(或112 kHz)大一個數量級的時鐘將是最簡單的選擇,但實際上相同),因為您只添加零,這種數學對大多數人來說是最簡單的。不幸的是,這個世界上的一切都是某種妥協。並非每個值都可以工作。

第一個示例的發電機轉速太低。

如果選擇56,000 Hz時鐘,您將無能為力。將需要在每個週期調用ISR,並且無法執行其他任何操作。這是完全沒有用的。如果您選擇10倍快的速度(560 kHz),則將有9個微控制器週期(計時器達到其最大值需要10個週期-一個週期才能調用ISR函數)來完成工作,而這完全是不夠的。您通常只是經常需要更多的計算能力。

如果您選擇一個太大的值,則因為56 MHz的微控制器根本無法使用它。太快了。因此,僅選擇商店中的最大價值也不會減少價值。

原始Arduino Uno R3的備用時鐘為16 MHz,因此可以保證任何較慢的工作。下一個大於56且小於16 MHz的數量級的值是5.6 MHz。這樣可以每隔50個週期調用一次ISR,並創建一個理想的112,000 Hz定時器頻率。您的信號將恰好是56 kHz。在ISR調用之間,您將有49個MCU週期來執行您的程序,但仍約為原始時鐘速度的1/3。一個人可以使用112作為基本頻率,並使用11.2 MHz時鐘,這將占到現有16 MHz諧振器的約2/3。 ISR函數每100個週期就會調用一次,並且仍會生成一個完美的56 kHz信號。

但是這些值存在兩個主要問題。

  • 第一個問題嚴重取決於您的需求:為了獲得使用易於查找的寄存器值(OCR iirc )的準確信號頻率,您會犧牲大約1/3(11.2 MHz)的最大計算能力。您可能會滿意,也可能不會。

  • 第二個問題是硬頂:查找值非常容易,但非常通常它們根本不作為製造的時鐘源存在。這是 Farnell的諧振器網頁,僅缺少5.6MHz和11.2MHz。

為了避免這種情況,我們可以查看可用的諧振器值,並找出可以用於生成精確所需值的其他方法。如果將56除以4,我們得到14,幸運的是有一個14 MHz諧振器。這為我們提供了更高的速度和更多的功能,並且同樣容易找到寄存器值。要每秒調用一次ISR 112,000次,我們需要在OCR寄存器中放入一個十進制124或十六進制0x7C的值,因此通過計算124個週期+ 1來調用ISR,我們得到了理想的理想值。

NB

  1. ISR-中斷服務程序(這是僅在生成的中斷上執行的代碼)
  2. 程序的大小取決於內存大小!它與時鐘速度無關,也與您調用ISR的頻率無關。
  3. 當微控制器以程序命令啟動時,計數器將遞增。如果產生中斷,則調用ISR,並將該值存儲在特殊寄存器中。 ISR代碼完成後,程序計數器的值將從該特殊寄存器中恢復,並且程序從中斷處繼續執行,就好像從未發生過一樣。

    我將舉一個非常笨拙的示例。如果您是一個純粹主義者,我警告您:鼻子和眼睛可能會流血。分步路線說明是您的主程序及其命令。您走路或跑步的速度取決於您的“時鐘速度”,而不取決於路線說明(前進30步,向左1旋轉90度,前進10步,向右45度等),它們始終是相同的。現在想像一下,一個小孩或一個貪婪的腐敗的當地政客不時地解開鞋子。這是產生中斷的事件。然後您在最後一步後停下來,跪下並再次係好鞋子。這是您的ISR程序。

    然後從停止的地方繼續;您不是從頭開始。當您在世間無時無刻不在走路時,即使您必須每隔一步都係鞋帶,也不在乎。但是,如果您這樣做有時間限制,例如在奧運會上奔跑100米(或從飢餓的食肉天敵中奔跑),停下來系鞋帶可能會帶來可怕的後果。微控制器也是如此。即使只執行一行代碼,程序也會繼續執行,儘管速度很慢。如果您根本不關心速度,那將不是問題。如果您需要做一些與時間有關的事情,例如使用其他與計時器有關的動作,那麼干擾可能是非常不希望的並且有問題。

  4. 少就是多!更快的時鐘並不總是更好。較慢的時鐘設備消耗的功率要少得多。這可能是電池供電設備中的關鍵點。

  5. 所需的周期是從以下公式得出的:
    (時鐘速度/(預分頻器值*所需的ISR通話頻率))-1

  6. ol>
TLDR:解焊陶瓷16 MHz振盪器,並用另一個振盪器進行替換,該振盪器允許*精確地* 56 kHz的整數除法(例如14 MHz並除以250)。
kiwiron
2014-03-31 14:51:33 UTC
view on stackexchange narkive permalink

您只需在輸出和輸入之間切換載波引腳模式即可打開和關閉載波。我用它來通過37KHz紅外線(遠程控制)端口控制熱泵。

kiwiron
2014-04-01 13:12:01 UTC
view on stackexchange narkive permalink

無需使用ISR創建載體。只需設置一個定時器即可在所需的載波頻率上產生50%的PWM輸出。然後,ISR負責調製載波(通常以0.5或1ms的間隔),從而獲得更為舒適的速率。以我的經驗,大多數紅外接收器可以容忍5%的載波頻率誤差。我使用的是Freetronics EtherMega 2560(具有大量的計時器),但是我確定其他CPU也能做到。

那麼如何精確地實現載波調製?在輸入(載波關閉)和輸出(載波開啟)之間更改計時器輸出捕獲引腳的模式?


該問答將自動從英語翻譯而來。原始內容可在stackexchange上找到,我們感謝它分發的cc by-sa 3.0許可。
Loading...