每個(gè)喜歡在某個(gè)時(shí)間點(diǎn)修補(bǔ)電子設(shè)備的工程師都希望擁有自己的實(shí)驗(yàn)室設(shè)置。萬(wàn)用表、鉗形表、示波器、LCR 表、函數(shù)發(fā)生器、雙模電源和自動(dòng)變壓器是體面實(shí)驗(yàn)室設(shè)置的最低限度設(shè)備。雖然所有這些都可以購(gòu)買(mǎi),但我們也可以輕松地自己構(gòu)建一些,例如函數(shù)發(fā)生器和雙模電源。
在本文中,我們將學(xué)習(xí)如何快速輕松地使用 Arduino 構(gòu)建自己的函數(shù)生成器。這個(gè)函數(shù)發(fā)生器又名波形發(fā)生器可以產(chǎn)生頻率范圍從 1Hz 到 2MHz 的方波 (5V/0V),波的頻率可以通過(guò)旋鈕控制,占空比硬編碼為 50%,但很容易改變?cè)诠?jié)目中也是如此。除此之外,該發(fā)生器還可以產(chǎn)生帶頻率控制的自波。請(qǐng)注意,該發(fā)生器不是工業(yè)級(jí)的,不能用于嚴(yán)格的測(cè)試。但除此之外,它對(duì)于所有愛(ài)好項(xiàng)目都會(huì)派上用場(chǎng),您無(wú)需在數(shù)周內(nèi)等待貨物到達(dá)。還有什么比使用我們自己構(gòu)建的設(shè)備更有趣的事情。
所需材料
Arduino納米
16*2 字母數(shù)字液晶顯示屏
旋轉(zhuǎn)編碼器
電阻(5.6K,10K)
電容 (0.1uF)
Perf 板,Bergstik
焊接套件
電路原理圖
這個(gè)Arduino 函數(shù)發(fā)生器的完整電路圖如下所示。如您所見(jiàn),我們有一個(gè) Arduino Nano 作為我們項(xiàng)目的大腦和一個(gè)16x2 LCD來(lái)顯示當(dāng)前生成的頻率值。我們還有一個(gè)旋轉(zhuǎn)編碼器,可以幫助我們?cè)O(shè)置頻率。
完整的設(shè)置由 Arduino 本身的 USB 端口供電。由于某些我們將在本文后面討論的原因,我之前使用的連接沒(méi)有成功。因此,我不得不通過(guò)更改引腳順序來(lái)稍微弄亂接線。無(wú)論如何,您不會(huì)有任何此類(lèi)問(wèn)題,因?yàn)樗呀?jīng)全部解決了,只需仔細(xì)按照電路了解哪個(gè)引腳連接到什么。您還可以參考下表來(lái)驗(yàn)證您的連接。
電路非常簡(jiǎn)單;我們?cè)?D9 引腳上產(chǎn)生一個(gè)方波,可以這樣使用,該方波的頻率由旋轉(zhuǎn)編碼器控制。然后為了得到一個(gè)正弦波,我們?cè)谝_ D5 上產(chǎn)生 SPWM 信號(hào),它的頻率必須與 PWM 頻率相關(guān),所以我們將此 PWM 信號(hào)提供給引腳 D2 作為中斷,然后使用 ISR 來(lái)控制頻率自波。
您可以在面包板上構(gòu)建電路,甚至可以為其購(gòu)買(mǎi) PCB。但我決定將它焊接在 Perf 板上,以快速完成工作并使其長(zhǎng)期使用可靠。所有連接完成后,我的電路板看起來(lái)像這樣。
如果您想了解更多關(guān)于如何使用 Arduino 產(chǎn)生 PWM 和正弦波的信息,請(qǐng)閱讀以下段落,否則您可以直接向下滾動(dòng)到 Programming Arduino 部分。
產(chǎn)生變頻方波
使用 Arduino 的人可能會(huì)熟悉, Arduino只需使用模擬寫(xiě)入功能即可產(chǎn)生 PWM 信號(hào)。但此功能僅限于控制 PWM 信號(hào)的占空比,而不是控制信號(hào)的頻率。但是對(duì)于波形發(fā)生器,我們需要一個(gè)頻率可以控制的 PWM 信號(hào)。這可以通過(guò)直接控制 Arduino 的定時(shí)器并基于它切換 GPIO 引腳來(lái)完成。但是有一些預(yù)先構(gòu)建的庫(kù)可以做同樣的事情并且可以這樣使用。我們使用的庫(kù)是Arduino PWM 頻率庫(kù)。我們將在編碼部分討論更多關(guān)于這個(gè)庫(kù)的信息。
這個(gè)庫(kù)也有一些缺點(diǎn),因?yàn)閹?kù)改變了 Arduino 中的默認(rèn)定時(shí)器 1 和定時(shí)器 2 設(shè)置。因此,您將不再能夠在 Arduino 上使用伺服庫(kù)或任何其他與計(jì)時(shí)器相關(guān)的庫(kù)。此外,引腳 9、10、11 和 13 上的模擬寫(xiě)入功能使用定時(shí)器 1 和定時(shí)器 2,因此您將無(wú)法在這些引腳上產(chǎn)生 SPWM。
這個(gè)庫(kù)的優(yōu)點(diǎn)是它不會(huì)干擾 Arduino 的 Timer 0,它比 Timer 1 和 Timer 2 更重要。因此,您可以毫無(wú)問(wèn)題地自由使用延遲函數(shù)和 millis() 函數(shù)。引腳 5 和 6 也由定時(shí)器 0 控制,因此我們?cè)谶@些引腳上使用模擬寫(xiě)入或伺服控制操作不會(huì)有問(wèn)題。最初我花了一些時(shí)間才弄清楚這一點(diǎn),這就是為什么接線有點(diǎn)混亂的原因。
這里我們也建了一個(gè)簡(jiǎn)單的方波發(fā)生器,但是要改變波形的頻率,你必須更換電阻或電容,而且很難得到所需的頻率。
使用 Arduino 產(chǎn)生正弦波
眾所周知,微控制器是數(shù)字設(shè)備,它們不能僅通過(guò)編碼來(lái)產(chǎn)生正弦波。但是有兩種從微控制器獲得正弦波的流行方法,一種是利用 DAC,另一種是創(chuàng)建 SPWM。不幸的是,Arduino 板(Due 除外)沒(méi)有內(nèi)置 DAC 來(lái)產(chǎn)生正弦波,但您始終可以使用簡(jiǎn)單的 R2R 方法構(gòu)建自己的 DAC,然后使用它來(lái)產(chǎn)生體面的正弦波。但為了減少硬件工作,我決定使用后一種方法來(lái)創(chuàng)建 SPWM 信號(hào),然后將其轉(zhuǎn)換為正弦波。
什么是 SPWM 信號(hào)?
術(shù)語(yǔ) SPWM 代表正弦脈沖寬度調(diào)制。該信號(hào)與 PWM 非常相似,但對(duì)于 SPWM 信號(hào),占空比被控制為獲得類(lèi)似于正弦波的平均電壓。例如,100% 占空比時(shí),平均輸出電壓為 5V,25% 時(shí)我們將有 1.25V,因此通過(guò)控制占空比,我們可以獲得預(yù)定義的可變平均電壓,這不過(guò)是一個(gè)正弦波。這種技術(shù)通常用于逆變器。
在上圖中,藍(lán)色信號(hào)是 SPWM 信號(hào)。請(qǐng)注意,波形的占空比從 0% 變化到 100%,然后又回到 0%。該圖是為 -1.0 到 +1.0V 繪制的,但在我們的例子中,由于我們使用的是 Arduino,因此比例將從 0V 到 5V。我們將在下面的編程部分學(xué)習(xí)如何使用 Arduino 生成 SPWM。
將 SPWM 轉(zhuǎn)換為正弦波
將 SPWM 單波轉(zhuǎn)換為正弦波需要一個(gè)由至少 4 個(gè)電源開(kāi)關(guān)組成的 H 橋電路。我們不會(huì)更深入地研究它,因?yàn)槲覀冊(cè)谶@里沒(méi)有使用它。這些 H 橋電路通常用于逆變器。它利用兩個(gè) SPWM 信號(hào),其中一個(gè)與另一個(gè)相移,兩個(gè)信號(hào)都應(yīng)用于 H 橋中的電源開(kāi)關(guān),以使對(duì)角相對(duì)的開(kāi)關(guān)同時(shí)打開(kāi)和關(guān)閉。通過(guò)這種方式,我們可以得到一個(gè)看起來(lái)類(lèi)似于正弦波的波形,但實(shí)際上不會(huì)更接近上圖所示的任何波形(綠色波形)。為了獲得純自波輸出,我們必須使用像低通濾波器這樣的濾波器,它由電感器和電容器組成。
然而,在我們的電路中,我們不會(huì)使用正弦波為任何東西供電。我只是想從生成的 SPWM 信號(hào)中創(chuàng)建,所以我使用了一個(gè)簡(jiǎn)單的 RC 濾波器。您也可以嘗試使用 LC-Filter 以獲得更好的結(jié)果,但為了簡(jiǎn)單起見(jiàn),我選擇了 RC。我的電阻值是 620 歐姆,電容是 10uF。上圖顯示了來(lái)自引腳 5 的 SPWM 信號(hào)(黃色)和通過(guò) RC 濾波器后獲得的正弦波(藍(lán)色)。
如果您不想改變頻率,您也可以使用這個(gè)使用晶體管的簡(jiǎn)單正弦波發(fā)生器電路來(lái)產(chǎn)生正弦波。
添加 Arduino PWM 頻率庫(kù)
可以通過(guò)單擊下面的鏈接下載 Arduino 頻率庫(kù)。
Arduino PWM 頻率庫(kù)
在撰寫(xiě)本文時(shí),Arduino PWM 頻率庫(kù) V_05 是最新的,它將以 ZIP 文件的形式下載。提取 ZIP 文件廣告,您將獲得一個(gè)名為 PWM 的文件夾。然后導(dǎo)航到 Arduino IDE 的 Libraries 文件夾,對(duì)于 Windows 用戶,它將位于您的文檔中,路徑為C:UsersUserDocumentsArduinolibraries。將 PWM 文件夾粘貼到庫(kù)文件夾中。有時(shí)您可能已經(jīng)有一個(gè) PWM 文件夾,在這種情況下,請(qǐng)確保將舊文件夾替換為新文件夾。
為波形發(fā)生器編程 Arduino
與往常一樣,可以在本頁(yè)底部找到該項(xiàng)目的完整程序。您可以這樣使用代碼,但請(qǐng)確保您已為 Arduino IDE 添加了可變頻率庫(kù),如上所述,否則您將收到編譯時(shí)錯(cuò)誤。在本節(jié)中,讓我們查看代碼以了解正在發(fā)生的事情。
基本上我們想在引腳 9 上產(chǎn)生一個(gè)可變頻率的 PWM 信號(hào)。該頻率應(yīng)使用旋轉(zhuǎn)編碼器設(shè)置,該值也應(yīng)顯示在 16*2 LCD 上。一旦在引腳 9 上創(chuàng)建了 PWM 信號(hào),它將在引腳 2 上產(chǎn)生中斷,因?yàn)槲覀円呀?jīng)將兩個(gè)引腳都短路了。使用此中斷,我們可以控制在引腳 5 上生成的 SPWM 信號(hào)的頻率。
與往常一樣,我們通過(guò)包含所需的庫(kù)來(lái)開(kāi)始我們的程序。液晶庫(kù)是 Arduino 內(nèi)置的,我們剛剛安裝了 PWM 庫(kù)。
#include
#include
接下來(lái)我們聲明全局變量,并提及 LCD、Rotary Encoder 和信號(hào)引腳的引腳名稱(chēng)。如果您按照上面的電路圖進(jìn)行操作,則可以不受干擾。
const int rs = 14, en = 15, d4 = 4, d5 = 3, d6 = 6, d7 = 7; //注明LCD連接的管腳號(hào)
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
常量 int Encoder_OuputA = 11;
常量 int Encoder_OuputB = 12;
常量 int Encoder_Switch = 10;
常量 int signal_pin = 9;
常量 int Sine_pin = 5;
常量 int POT_pin = A2;
int Previous_Output;
整數(shù)乘數(shù) = 1;
雙角 = 0;
雙倍增量 = 0.2;
int32_t 頻率;//要設(shè)置的頻率
int32_t lower_level_freq = 1; //最低可能的頻率值為1Hz
int32_t upper_level_freq = 100000; //最大可能頻率為100KHz
在setup函數(shù)中,我們初始化 LCD 和串行通信以進(jìn)行調(diào)試,然后將 Encoder 的引腳聲明為輸入引腳。我們還在引導(dǎo)過(guò)程中顯示一條介紹消息,以確保一切正常。
lcd.begin(16, 2); //初始化16*2 LCD
lcd.print("信號(hào)發(fā)生器"); //介紹消息行 1
lcd.setCursor(0, 1);
lcd.print("-CircuitDigest"); //介紹消息第 2 行
延遲(2000);
lcd.clear();
lcd.print("頻率:00000Hz");
lcd.setCursor(0, 1);
lcd.print("Inc. by: 1");
序列號(hào).開(kāi)始(9600);//調(diào)試串口
//pin 模式聲明
pinMode (Encoder_OuputA, INPUT);
pinMode (Encoder_OuputB, INPUT);
pinMode(編碼器開(kāi)關(guān),輸入);
另一條重要的線路是InitTimerSafe,它初始化定時(shí)器 1 和 2 以產(chǎn)生可變頻率 PWM。一旦調(diào)用此函數(shù),Arduino 的默認(rèn)計(jì)時(shí)器設(shè)置將被更改。
InitTimersSafe(); //初始化定時(shí)器而不干擾定時(shí)器0
我們還在引腳 2 上運(yùn)行了外部中斷。因此,每當(dāng)引腳 2 的狀態(tài)發(fā)生變化時(shí),都會(huì)觸發(fā)一個(gè)中斷,該中斷將運(yùn)行中斷服務(wù)程序 (ISR) 功能。這里 ISR 函數(shù)的名稱(chēng)是generate_sine。
attachInterrupt(0,generate_sine,CHANGE);
接下來(lái),在void 循環(huán)中,我們必須檢查旋轉(zhuǎn)編碼器是否已轉(zhuǎn)動(dòng)。只有當(dāng)它已經(jīng)轉(zhuǎn)動(dòng)時(shí),我們才需要調(diào)整 PWM 信號(hào)的頻率。我們已經(jīng)學(xué)習(xí)了如何將Rotary Encoder 與 Arduino連接。如果你是新來(lái)的,我建議你回到那個(gè)教程然后回到這里。
如果旋轉(zhuǎn)編碼器順時(shí)針旋轉(zhuǎn),我們通過(guò)將頻率值與乘數(shù)相加來(lái)增加頻率值。這樣我們可以將頻率值增加/減少 1、10、100 甚至 1000。乘數(shù)的值可以通過(guò)按下旋轉(zhuǎn)編碼器來(lái)設(shè)置。如果編碼器旋轉(zhuǎn),我們會(huì)改變頻率值并在引腳 9 上產(chǎn)生一個(gè) PWM 信號(hào),如下所示。這里的值 32768 將 PWM 設(shè)置為 50% 周期。選擇值 32768,因?yàn)?65536 的 50% 是 32768,因此您可以確定所需占空比的值。但這里的占空比固定為 50%。最后,函數(shù)SetPinFrequencySafe用于設(shè)置我們的信號(hào)引腳(即引腳 9)的頻率。
pwmWriteHR(signal_pin, 32768); //默認(rèn)設(shè)置占空比為50% -> for 16-bit 65536/2 = 32768
SetPinFrequencySafe(signal_pin, frequency);
在 ISR 函數(shù)中,我們編寫(xiě)代碼來(lái)生成 SPWM 信號(hào)。有很多方法可以生成 SPWM 信號(hào),甚至還有可用于 Arduino 的預(yù)構(gòu)建庫(kù)。我使用了最簡(jiǎn)單的方法來(lái)利用Arduino 中的 sin() 函數(shù)。如果您有興趣,也可以嘗試使用查找表方法。sin() 返回一個(gè)介于 -1 到 +1 之間的變量值(十進(jìn)制),當(dāng)根據(jù)時(shí)間繪制時(shí),這會(huì)給我們一個(gè)正弦波。
現(xiàn)在我們要做的就是將這個(gè) -1 到 +1 的值轉(zhuǎn)換為 0 到 255 并將其提供給我們的模擬寫(xiě)入函數(shù)。為此,我將其乘以 255 只是為了忽略小數(shù)點(diǎn),然后使用 map 函數(shù)將值從 -255 到 +255 轉(zhuǎn)換為 0 到 +255。最后,使用模擬寫(xiě)入功能將該值寫(xiě)入引腳 5。每次調(diào)用 ISR 時(shí),角度值都會(huì)增加 0.2,這有助于我們控制正弦波的頻率
雙正弦值 = sin(角度);
正弦值 *= 255;
int plot = map(sineValue, -255, +255, 0, 255);
Serial.println(plot);
類(lèi)比寫(xiě)入(正弦引腳,繪圖);
角度 += 增量;
在硬件上測(cè)試 Arduino 函數(shù)發(fā)生器
根據(jù)電路圖構(gòu)建您的硬件并上傳本頁(yè)底部給出的代碼?,F(xiàn)在,您已準(zhǔn)備好測(cè)試您的項(xiàng)目。如果你有 DSO(示波器)會(huì)容易得多,但你也可以用 LED 測(cè)試它,因?yàn)轭l率范圍非常高。
將探頭連接到電路的方波和正弦波引腳。如果您沒(méi)有示波器,請(qǐng)?jiān)谶@兩個(gè)引腳上使用兩個(gè) LED。接通電路電源,您應(yīng)該會(huì)在 LCD 上看到介紹性消息。然后改變旋轉(zhuǎn)編碼器并設(shè)置所需的頻率,您應(yīng)該能夠在示波器上觀察方波和正弦波,如下所示。如果您使用 LED,您應(yīng)該注意到 LED 根據(jù)您設(shè)置的頻率以不同的間隔閃爍。
#include
#include
const int rs = 14, en = 15, d4 = 4, d5 = 3, d6 = 6, d7 = 7; //注明LCD連接的管腳號(hào)
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
int Encoder_OuputA = 11;
int Encoder_OuputB = 12;
int Encoder_Switch = 10;
int Previous_Output;
整數(shù)乘數(shù) = 1;
雙角 = 0;
雙倍增量 = 0.2;
常量 int signal_pin = 9;
常量 int Sine_pin = 5;
常量 int POT_pin = A2;
int32_t 頻率;//要設(shè)置的頻率
int32_t lower_level_freq = 1; //最低可能的頻率值為1Hz
int32_t upper_level_freq = 100000; //最大可能頻率為100KHz
無(wú)效 setup()
{
lcd.begin(16, 2); //初始化16*2 LCD
lcd.print("信號(hào)發(fā)生器"); //介紹消息行 1
lcd.setCursor(0, 1);
lcd.print("-CircuitDigest"); //介紹消息第 2 行
延遲(2000);
lcd.clear();
lcd.print("頻率:00000Hz");
lcd.setCursor(0, 1);
lcd.print("Inc. by: 1");
序列號(hào).開(kāi)始(9600);//調(diào)試序列號(hào)
InitTimersSafe(); //初始化定時(shí)器而不干擾定時(shí)器 0
//pin 模式聲明
pinMode (Encoder_OuputA, INPUT);
pinMode (Encoder_OuputB, INPUT);
pinMode(編碼器開(kāi)關(guān),輸入);
Previous_Output = digitalRead(Encoder_OuputA); //讀取輸出A的初始值
attachInterrupt(0,generate_sine,CHANGE);
}
void loop()
{
if (digitalRead(Encoder_OuputA) != Previous_Output)
{
if (digitalRead(Encoder_OuputB) != Previous_Output)
{
頻率 = 頻率 + 乘數(shù);
// Serial.println(頻率);
pwmWriteHR(signal_pin, 32768); //默認(rèn)設(shè)置占空比為50% -> for 16-bit 65536/2 = 32768
SetPinFrequencySafe(signal_pin, frequency);
lcd.setCursor(0, 0);
lcd.print("頻率:Hz");
lcd.setCursor(5, 0);
lcd.print(頻率);
}
else
{
頻率 = 頻率 - 乘數(shù);
// Serial.println(頻率);
pwmWriteHR(signal_pin, 32768); //默認(rèn)設(shè)置占空比為50% -> for 16-bit 65536/2 = 32768
SetPinFrequencySafe(signal_pin, frequency);
lcd.setCursor(0, 0);
lcd.print("頻率:Hz");
lcd.setCursor(5, 0);
lcd.print(頻率);
}
}
if (digitalRead(Encoder_Switch) == 0)
{
乘數(shù) = 乘數(shù) * 10;
如果(乘數(shù)> 1000)
乘數(shù)=1;
// Serial.println(乘數(shù));
lcd.setCursor(0, 1);
lcd.print("Cng.by:");
lcd.setCursor(8, 1);
lcd.print(乘數(shù));
延遲(500);
而(數(shù)字讀?。ň幋a器開(kāi)關(guān))== 0);
}
Previous_Output = digitalRead(Encoder_OuputA);
}
void generate_sine()
{
double sineValue = sin(angle);
正弦值 *= 255;
int plot = map(sineValue, -255, +255, 0, 255);
Serial.println(plot);
類(lèi)比寫(xiě)入(正弦引腳,繪圖);
角度 += 增量;
如果(角度> 180)
角度=0;
}
?
評(píng)論
查看更多