Arduino UNO (atau STM32 "blue pill" / "black pill")
1
Aplikasi dan Layanan Online
Arduino IDE — untuk menulis dan mengunggah skets.
Tentang Proyek Ini
R-2R DAC
Salah satu implementasi paling sederhana dari konverter digital ke analog dapat dicapai dengan merancang tangga DAC R-2R. Jenis DAC ini hanya membutuhkan resistor untuk bekerja, sehingga sangat ramah pemula.
Prinsip dasar dari jenis DAC ini adalah Anda hanya perlu dua nilai resistor. R dan 2R. Kemudian Anda dapat menyusunnya seperti yang ditunjukkan dalam skematik di bawah ini.
R dapat berapa saja asalkan setiap kemunculan R dalam skematik memiliki nilai yang sama.
Misalnya, jika kita memilih R = 1k, maka 2R akan menjadi dua kali lipatnya. Dalam kasus ini 2R = 2k. Jadi Anda dapat menggunakan resistor 1k dan 2k saja.
Jika Anda menggunakan R=3.3K maka 2R = 6.6k dan seterusnya. Jika Anda hanya ingin menggunakan nilai resistor yang sama untuk semuanya, maka untuk mendapatkan 2R, Anda hanya perlu menempatkan dua resistor secara seri dan itu akan meningkatkan jumlah komponen.
Jumlah bit ditentukan oleh berapa banyak cabang 2R yang Anda miliki yang menjulur. Dalam proyek ini kita akan menggunakan R-2R 8-bit dan R-2R 6-bit untuk Arduino Uno atau Nano. Jika Anda menggunakan mikrokontroler lain yang Anda ketahui mendukung manipulasi port penuh setidaknya 8-bit seperti STM32 "blue pill" dan "black pill", maka Anda dapat menggunakan dua DAC 8-bit saja.
Catatan samping tentang IC DAC:
Proyek ini difokuskan pada penggunaan DAC R-2R, tetapi Anda bebas menggunakan IC DAC untuk mencapai sesuatu yang serupa. Jika Anda akan menggunakan IC DAC, saya merekomendasikan menggunakan yang mendukung protokol komunikasi cepat seperti SPI karena I2C akan terlalu lambat untuk menggambar gambar yang detail. Saya tidak akan membahas cara menggunakan IC DAC dalam tulisan ini tetapi mungkin di masa depan. Metode R-2R tetap merupakan pilihan saya karena dapat menghasilkan gambar dengan lebih banyak detail.
Manipulasi Port
Kita akan menggunakan manipulasi port paralel dari mikrokontroler kita. Alasan melakukannya adalah karena memungkinkan kecepatan output yang lebih cepat dan juga menjaga kode tetap sederhana. Anda dapat membaca lebih banyak detail tentang register port untuk Arduino di tautan ini.
Arduino Uno dan Nano memiliki mikrokontroler ATmega328p. Mikrokontroler ini memiliki pemetaan pin yang sama dengan Atmega168:
Pin port dan bit ditandai dengan label PXN di mana X adalah huruf port dan N adalah nomor bit.
Contoh: PB1 adalah untuk PORT B bit 1. Demikian pula PC5 adalah untuk PORT C bit 5.
Jika kita memeriksa pin, kita melihat bahwa mikrokontroler memiliki port B, C, dan D. Dengan kembali ke referensi Arduino kita dapat melihat port mana yang dapat ditulis atau dibaca atau keduanya. Dalam aplikasi kita, kita hanya peduli tentang tulis.
Dokumentasi menyatakan bahwa PORTD adalah read/write dan dipetakan ke pin digital 0 hingga 7. Ini memberikan kita 8 bit penuh dari port untuk ditulis.
Selanjutnya kita memiliki PORTB yang seperti yang dinyatakan dipetakan ke pin digital 8-13. Pernyataan tambahan dibuat mengatakan bahwa 6 dan 7 yang akan melengkapi 8 bit penuh tidak dapat diakses. Port ini hanya dapat digunakan untuk menulis 6 bit.
Hal yang sama berlaku untuk PORTC. Ini dipetakan ke pin analog 0-5 tetapi dua pin juga dicadangkan sehingga kita hanya memiliki 6 bit untuk ditulis.
Karena pembatasan ini, kita harus menggunakan kombinasi dari DAC 8-bit untuk PORTD dan DAC 6-bit untuk PORTC atau PORTB.
Kita akan menggunakan PORTD dan PORTB dan sekarang kita dapat mulai merangkaikan DAC ke pin.
Jika Anda membutuhkan bantuan visual tentang cara merakit, ini adalah cara saya merakit kedua R-2R di breadboard. Perhatikan bahwa saya menggunakan dua R-2R karena saya mengujinya pada STM32 "black pill" saya. Saya menempatkan dua kabel jumper yang menjulur sehingga saya dapat menghubungkan sond osiloskop saya dan juga kabel ground di sisi. Saya menggunakan semua resistor 10k jadi untuk 2R saya saya menempatkan dua resistor 10k secara seri.
Ini adalah pengaturan breadboard yang lebih bersih menggunakan Tinkercad. Saya menandai output dengan X dan Y karena itulah yang akan dihubungkan oleh sond osiloskop kita. Jika Anda membutuhkan lebih banyak panduan tentang pengaturan, saya akan memberikan skematik yang menunjukkan tangga R-2R yang terdiri dari semua nilai resistor yang sama dan yang lain dengan dua nilai.
Pastikan untuk memeriksa ground Anda! Setiap kali saya merakit pengaturan ini saya cenderung melupanya. Juga periksa kembali apakah Anda tidak meninggalkan celah tanpa koneksi.
Kode Arduino
Sekarang waktunya untuk skets Arduino.
Pertama kita perlu menyiapkan port kita sebagai output. Dari referensi Arduino tentang manipulasi port. Kita dapat melihat cara menetapkan port:
Dasarnya nilai 1 ke bit akan mengaturnya sebagai output dan nilai 0 akan mengaturnya sebagai input. Untuk PORTD kita dapat menulis langsung karena semua bit dapat diakses. Untuk PORTB, ingat bahwa bit 6 dan 7 tidak dapat digunakan karena mereka dipetakan ke kristal. Ini adalah praktik yang baik untuk menggunakan bitwise OR dengan nilai 0 untuk menghindari memodifikasi bit yang tidak akan diatur.
Dalam loop pengaturan kami ini akan menjadi kode:
Kode akan dilampirkan untuk diunduh, jadi jangan khawatir untuk mengetiknya secara manual.
Loop for di bawah konfigurasi hanya memetakan ulang nilai untuk port 6-bit. Nilai-nilai ini akan dari daftar yang akan memiliki nilai dalam rentang 8-bit. Untuk memetakan ulang ke 6-bit, nilai maksimum kami akan menjadi 2^6-1 yaitu 63. Kita memetakan dari rentang 0 hingga 2^8-1 yaitu 255. Alasan kita memetakan ulang dalam kode Arduino adalah karena alat plot tangan kami akan menghasilkan titik x dan y dalam istilah 8-bit. Kita dapat mengubahnya di kode mana pun, tetapi lebih baik untuk mengubahnya pada mikrokontroler yang digunakan.
Dasarnya kita butuh beberapa delay tergantung pada osiloskop. Saya menemukan bahwa untuk saya 1 sudah cukup. Faktanya, menghapus delay sepenuhnya juga cukup. Untuk titik, itu akan secara otomatis dibuat oleh alat plot tangan kami jadi Anda hanya bisa menyalin dan menempel angka tetapi dasarnya ini adalah berapa banyak titik yang akan digambar sehingga variabel iterasi dapat melewati mereka. Bagaimanapun, ini adalah kode lengkap:
Array x_points dan y_points akan berbeda untuk Anda setiap kali Anda menggambar sesuatu dan akan secara otomatis dibuat dengan alat kami.
Catatan samping tentang PWM cepat:
Jika Anda adalah pengguna mikrokontroler tingkat lanjut, Anda mungkin menyadari bahwa jika khawatir tentang kecepatan, maka mungkin hal yang sama dapat dicapai oleh PWM cepat dan memodifikasi register clock. Kemudian memberikan output PWM ke filter rendah-pass untuk mendapatkan tegangan analog yang akan mengurangi jumlah pin. Saya telah mencoba kedua metode, dan ini masih menghasilkan dukungan yang lebih baik untuk gambar dengan lebih banyak detail. Setidaknya di Arduino Uno
Alat Menggambar
Saya membuat alat ini dalam Python 3 menggunakan tkinter. Jika Anda tidak memiliki tkinter terinstal, instal dengan pip.
pip install tk
Kode hanya akan dilampirkan, tetapi dasarnya mencatat koordinat di jendela di mana kursor Anda diklik. Jangan mencoba mengubah ukuran jendela karena itu akan mengubah resolusi. Jika Anda ingin lebih tepat, gunakan kaca pembesar di Windows. Jendela didasarkan pada 255x255 karena itulah nilai maksimum dari rentang bit kami. Tentu saja salah satu dimensi akan dipetakan ke 6-bit jika Anda menggunakan Arduino UNO.
Untuk memanggil alat cukup gunakan format ini
python drawlog.py > arduino_list.txt
Ini akan membuat file .txt bernama arduino_list.txt dengan daftar Arduino untuk x_points, y_points dan NUM_POINTS yang dihasilkan untuk Anda, siap disalin dan ditempelkan ke dalam kode Anda.
Sebagai contoh, ini adalah tampilan file .txt saat Anda membukanya. Anda hanya perlu mengganti baris-baris tersebut dalam kode.
Ini adalah tampilannya setelah dibuka. Dari sana Anda dapat menggambar apa pun.
Saya menggambar gambar berikut untuk mengujinya. Kode dihasilkan saat penutupan jendela.
Dan setelah mengunggah kode pada Arduino ini adalah tampilannya dalam mode X-Y.
PENTING:
Jika Anda mengalami kesalahan kompilasi tentang memori, ini adalah karena memori rendah yang tersedia di Arduino UNO. Itu berarti Anda harus menggambar gambar yang kurang detail. Saya pikir jumlah titik maksimum sekitar 400, tetapi mungkin lebih. Jika Anda menggunakan STM32 "Blue pill" atau "black pill" angka ini di atas 4.000.
Mode X-Y Osiloskop
Osiloskop harus diatur ke mode x-y. Output DAC R-2R 8-bit (PORTD) akan dihubungkan ke Channel 1 dan DAC R-2R 6-bit (PORTB) akan dihubungkan ke Channel 2. Dari sana Anda dapat menyesuaikannya dengan knob sampai Anda melihat gambar.
Itu saja! Jika Anda memiliki pertanyaan silakan tanya. Selain itu, jika Anda ingin mencobanya pada blue pill atau black pill ini adalah tautan ke halaman GitHub saya dengan beberapa kode contoh
Sekarang inilah beberapa gambar yang saya plot.
Bebas untuk berbagi milik Anda!!!
Edit:
Detail Penting untuk manajemen memori
Seperti Tim yang disebutkan dalam komentar
Dalam kode Arduino Anda iterator Anda melalui titik, t, adalah tipe "byte", jadi hanya mendukung hingga 255 titik. Mengapa tidak menjadikannya "int"?
Kode plotter Anda mengeluarkan "const unsigned long" untuk x_points dan y_points - itu tidak akan bekerja karena nanti Anda memodifikasi y-points. Juga, mengapa tidak hanya menggunakan "byte" untuk menghemat memori?
Waspadai keterbatasan perangkat keras yang Anda gunakan. Untuk Arduino Uno lebih baik menggunakan byte, namun jika Anda menggunakan STM32 atau bahkan ESP32, Anda akan memiliki lebih banyak titik yang tersedia untuk digambar. Terima kasih semua untuk umpan balik Anda.
Timster:
Saya telah menemukan cara untuk meningkatkan secara massal jumlah titik yang didukung pada UNO - pindahkan mereka ke ruang penyimpanan program. Anda dapat melakukannya dengan modifier PROGMEM. Dengan cara ini Anda dapat menyimpan sekitar 15.000 titik!
Jangan melakukan modifikasi ke y_points dalam fungsi setup (yaitu hapus loop for di sana). Sebaliknya lakukan pergeseran bit dalam fungsi loop.
Anda juga memerlukan perintah khusus untuk membaca data dari memori program (pgm_read_byte_near). Jadi loop for dalam void loop() terlihat seperti:
for (int t=0; t < NUM_POINTS; t++) // run through points { PORTD = pgm_read_byte_near(x_points + t); PORTB = pgm_read_byte_near(y_points + t) >> 2; delayMicroseconds(FIGURE_DELAY); }
Kemudian mungkin untuk menyimpan satu gambar resolusi tinggi atau beberapa gambar yang lebih kecil dan beralih di antara mereka 😃
Kode
Kode Arduino
Alat Plotting
Kode ArduinoArduino
Skets Arduino untuk digunakan pada papan Arduino Uno atau Nano
const byte FIGURE_DELAY = 1; // trace delay in uS. adjust if needed
const int NUM_POINTS = 87;// number of XY points in figure
// x and y coordinates to plot
byte x_points[NUM_POINTS] = {106,106,105,104,103,102,101,100,99,98,97,96,95,94,93,92,91,90,90,89,88,87,87,87,86,86,86,86,87,89,90,91,93,95,97,99,101,102,102,104,104,105,105,106,106,106,106,106,106,108,109,110,112,113,115,117,119,121,122,123,123,124,124,124,124,124,123,122,121,120,119,118,117,116,115,114,113,112,111,110,110,109,109,109,108,107,107};
byte y_points[NUM_POINTS] = {78,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,98,99,100,101,103,105,106,108,110,112,113,113,114,115,115,115,115,115,115,114,112,112,110,109,107,106,106,108,110,112,114,114,115,116,116,117,117,117,117,117,116,115,113,112,110,108,106,104,103,102,100,99,98,97,96,95,94,93,92,91,90,89,87,86,84,82,81,80,78};
void setup(){
// initialize port D and B for writing
DDRD = B11111111;
DDRB = B00111111;
byte t;
for (t=0; t < NUM_POINTS; t++) {
y_points[t] = map(y_points[t],0,255,0,63); // re-map Y points to 6 bits since port B is limited to 6 bits on Arduino
}
}
void loop(){
for (byte t=0; t < NUM_POINTS; t++)// run through points
{
PORTD = x_points[t];
PORTB = y_points[t];
delayMicroseconds(FIGURE_DELAY);
}
}
Alat PlottingPython
Alat menggambar untuk mengekspor titik untuk digambar
import tkinter as tk
X = []
Y = []
lastx, lasty = 0, 0
# xy and addLine are for graphical purposes only
# on_move_press is the one that logs the one to the list and fixes Y
def xy(event):
# logs coordinates when mouse is clicked
global lastx, lasty
lastx, lasty = event.x, event.y
def addLine(event):
# draws line from old point to new point
global lastx, lasty
canvas.create_line((lastx, lasty, event.x, event.y))
# this makes the new starting point of the drawing
lastx, lasty = event.x, event.y
# logs clicked coordinate on list
def on_move_press( event):
curX, curY = (event.x, event.y)
curY=255-curY # since tkinter uses different coordinates
X.append(str(curX))
Y.append(str(curY))
# set up needed for window
root = tk.Tk()
root.geometry("255x255")
root.columnconfigure(0, weight=1)
root.rowconfigure(0, weight=1)
canvas = tk.Canvas(root)
canvas.grid(column=0, row=0, sticky=(tk.N, tk.W, tk.E, tk.S))
# bind left click and drag to functions and start loop
canvas.bind("<Button-1>", xy)
canvas.bind("<B1-Motion>", addLine)
root.bind("<B1-Motion>",on_move_press)
root.mainloop()
# delete every 2nd entry to reduce points and increase trace refresh
for i in range(1,int(len(X)/2)):
X.pop(i)
Y.pop(i)
print("const int NUM_POINTS = %s;" % str(len(X)))
print("const unsigned long x_points[NUM_POINTS] = {%s};" % ','.join(X))
print("const unsigned long y_points[NUM_POINTS] = {%s};" % ','.join(Y))
#call python drawlog.py > arduino_list.txt