Servo membuatkan Arduino brownout kerana ia menarik arus berunit amp daripada rel yang dikadarkan dalam miliamp β dan PCA9685 menyelesaikannya dengan menjadikan bekalan servo satu rel berasingan yang board itu tidak pernah tanggung. Dua wayar I2C membawa arahan, satu terminal skru membawa arus, dan setiap satu daripada 16 channel mendapat pulse tersendiri dalam langkah 12-bit yang anda kalibrasi bagi setiap servo.
Kenapa menambah servo ketiga membuatkan Arduino anda reset?
Pin 5 V pada Arduino Uno bukan sebuah bekalan kuasa β ia hujung ekor kepada satu bekalan. Atas USB, segala yang board itu hulurkan sudah pun melalui polyfuse boleh-set-semula 500 mA (sebuah Bourns MF-MSMF050-2) yang duduk bersiri dengan talian USB 5 V β dan port USB 2.0 itu sendiri pun hanya wajib memberi 500 mA.
Sekarang timbang permintaan sebuah servo terhadap angka itu. Sebuah SG90 9 g menarik sekitar 10 mA ketika diam, dan lebih kurang 100β250 mA semasa bergerak serta 360 mA yang diukur pada stall. Satu tiada masalah. Dua masih boleh tahan β panduan pan-tilt joystick kami menjalankan tepat dua dan sudah pun terpaksa mencapai bateri. Empat yang bergerak serentak meminta 400 mA hingga 1 A, dan detik paling teruk sebuah servo ialah milisaat pertama setiap gerakan, ketika motornya baru hendak berpusing dan berkelakuan hampir seperti litar pintas merentas rel itu.
Apa yang anda nampak ialah satu rantaian, bukan satu kerosakan tunggal: rel itu melendut, brown-out detector ATmega328P menahan cip dalam keadaan reset, sketch bermula semula di tengah gerakan, dan kalau lendutan itu sampai ke sebelah USB, host menggugurkan port serial dan port COM anda hilang daripada IDE. Sekeluarga dengan panduan brownout SIM800L kami: tiada apa yang rosak, cuma bekalan itu diminta arus yang ia memang tidak pernah dibina untuk beri.
Senarai bahagian β empat servo atas rel kuasa mereka sendiri
Berbaloi ditambah
Adapter dinding 5 V 3 A ialah naik taraf bench sebaik empat servo bertukar menjadi lapan, atau bila anda beralih kepada servo metal-gear yang menarik lebih banyak arus. Ia perlukan pigtail barrel female 5.5x2.1 di sebelahnya: plug adapter itu ditolak masuk ke soket, dan lead merah dan hitam bogel pada pigtail itu mendarat dalam terminal skru pemacu, sama seperti lead bateri. Kabel A-ke-B simpanan itu pula yang memprogram Uno.
Bagaimana PCA9685 menghalang arus servo daripada masuk ke Arduino?
Board PCA9685 mempunyai dua input kuasa yang tidak pernah bertemu, dan pemisahan itulah keseluruhan produk ini. VCC, pada header enam-pin bersudut tepat, hanya menyuap cip PCA9685 dan pull-up I2C-nya β miliamp, yang Uno mampu luangkan sepanjang hari. V+, pada terminal skru hijau di bahagian atas board, mengalir dalam trace tembaga gemuk terus ke pin tengah (merah) kesemua enam belas header channel. Arus servo mengalir bateri β terminal skru β pin merah β servo dan balik semula, tidak pernah melalui cip itu. Kapasitor hitam gempal di sebelah terminal itu duduk merentas rel yang sama dan menampung milisaat pertama setiap gerakan, menumpulkan mata paling tajam lonjakan itu sebelum lead bateri merasainya.
Kerja cip itu cuma satu: mengalih pin ketiga β pin isyarat kuning β antara 0 V dengan VCC. Input isyarat sebuah servo menarik mikroamp sahaja, jadi tugas cip PWM itu sendiri kekal kecil sementara enam belas motor menghela arus berunit amp melepasinya pada tembaga di sebelah.
Ground tetap kena sepunya, dan di sini ia memang sudah sepunya. GND Uno mendarat pada header enam-pin, lead hitam bateri mendarat dalam terminal skru, dan kedua-duanya tiba pada satah ground yang sama di dalam board itu β board itu ialah ground sepunya, jadi anda tidak perlu tambah sebarang jumper. Ia penting kerana satu pulse PWM ialah beza voltan yang diukur terhadap ground: biar sifar servo dan sifar Arduino duduk pada potensi yang berlainan, maka servo mengukur ketinggian pulse yang berbeza daripada apa yang pemacu itu hantar β dan itu tiba sebagai jitter yang anda akan salahkan pada kod anda.

Header I2C pemacu ini ialah pin male bersudut tepat yang sudah dipateri, manakala A4/A5 pada Uno ialah soket female, jadi setiap wayar di sini ialah jumper male-to-female β tiada breadboard, tiada apa yang perlu dipateri (panduan wayar jumper kami menghabiskan kiraan itu).
| Dari | Ke | Kenapa |
|---|---|---|
| GND pemacu | GND Uno | Sifar sepunya untuk pulse isyarat |
| SCL pemacu | A5 Uno | Clock I2C β guna soket yang berpin, bukan blok pad bogel itu |
| SDA pemacu | A4 Uno | Data I2C |
| VCC pemacu | 5 V Uno | Bekalan logik untuk cip sahaja, beberapa miliamp |
| OE pemacu | biarkan tidak bersambung | Output enable aktif-LOW, sudah ditarik rendah pada board β output hidup seperti yang dihantar; pandu ia HIGH untuk memotong kesemua enam belas serentak |
| Lead merah bateri | V+ terminal skru | Semua arus servo masuk di sini |
| Lead hitam bateri | GND terminal skru | Balik di sini; bercantum dengan GND Uno pada board |
| Plug servo | Channel 0β3 | Coklat ke pin hitam, merah ke merah, oren ke kuning |
Tiada apa pada header tiga-pin itu berkunci, jadi plug servo duduk sama elok walaupun terbalik β dan sebab wayar merah mendarat pada pin tengah dua-dua cara, kesilapan itu nampak elok sahaja. Coklat dan oren itulah yang bertukar tempat: laluan balik ground servo berakhir pada output PCA9685 yang dikadarkan dalam miliamp, memaksa arus motor melalui satu-satunya cip yang board ini wujud untuk melindunginya, sementara wayar isyarat pula duduk atas ground dan tidak pernah menerima sebarang pulse. Pastikan wayar coklat duduk pada barisan bawah yang hitam pada setiap channel, dan hidupkan pek bateri hanya selepas setiap servo sudah terpasang.
Uno juga membawa satu blok 3 Γ 4 lubang bersalut yang tidak berpin berhampiran tepi atasnya, bersilkskrin SCL/SDA/5V/GND. Itu lubang kosong, bukan soket β jumper yang ditolak masuk tidak menyentuh apa-apa. A4 dan A5 dalam bank analog ialah dua isyarat I2C yang sama, dan ia memang sudah bersoket.
Apa yang patut menyuap terminal skru V+?
Terminal V+ pada PCA9685 mahukan 5β6 V DC, iaitu julat yang Adafruit tetapkan untuk PCA9685 dengan servo terpasang padanya, dan tingkap itu ditentukan oleh servo, bukan oleh board. Servo hobi dibina untuk 4.8β6 V: di bawah lebih kurang 4.5 V tork runtuh dan pengawal dalaman servo itu sendiri mula brownout, manakala melebihi 6 V anda melajukan motor yang bergear melalui nilon dan memendekkan hayatnya.
Holder AA empat slot menyusun selnya secara bersiri, jadi kimia selnya yang menentukan di mana anda mendarat. Empat NiMH boleh cas semula pada 1.2 V nominal memberi 4.8 V, tepat dalam tingkap itu, dan NiMH memegang dataran itu untuk sebahagian besar nyahcasnya. Empat alkali pula 6.0 V nominal tetapi terbaca hampir 1.6 V setiap satu ketika baharu, jadi satu set baharu boleh duduk sekitar 6.4 V tanpa beban β di atas puncak tingkap itu sehingga servo pertama menariknya turun. Alkali boleh pakai; NiMH ialah jawapan yang tidak perlukan sebarang syarat, dan voltan cuma separuh sebabnya. Selebihnya ialah rintangan dalaman: sebuah AA alkali dibina untuk lampu suluh, bukan untuk empat motor yang bermula serentak, dan membawa rintangan dalaman beberapa kali ganda sel NiMH β jadi lonjakan yang sama yang ditempuh NiMH tanpa kesan akan menarik pek alkali turun sampai nampak dengan mata. Itu brownout yang serupa, cuma berpindah dari Arduino ke bateri.
Lead merah dan hitam holder itu berakhir bogel, dan itulah tepatnya yang terminal skru mahukan β merah masuk V+, hitam masuk GND, diketatkan atas tembaga dan bukan atas penebat. Bila empat servo bertukar menjadi lapan, atau anda beralih kepada servo metal-gear MG90S yang menarik lebih banyak arus (panduan perbandingan servo kami menghuraikan pilihan itu), tukar bateri kepada adapter 5 V 3 A dan pigtail barrel female: 3 A itu lebih kurang lapan servo 9 g yang stall sebagai ruang lebih. Channel itu percuma, arus tidak: enam belas SG90 yang bergerak serentak ialah permintaan 4 A, jadi saiz bekalan anda ikut servo yang anda pandu serentak, bukan ikut jumlah channel. Jangan sekali-kali jumper pin 5 V Uno ke V+. Itu menyerahkan semula arus servo kepada rel yang board ini wujud untuk melindunginya, dan kalau ada pek bateri pada terminal itu sekali, ia mengikat dua bekalan menjadi satu β pek alkali baharu kemudiannya duduk pada 6.4 V atas pin VCC cip itu sendiri dan menyuap balik ke Uno, dan itulah caranya sebuah board pemacu yang elok jadi rentung.
Mendawaikan terminal itu berserta satu barisan penuh servo, ditunjukkan pada kelajuan bench:
Bagaimana tick 12-bit menjadi sudut servo?
PCA9685 tidak tahu apa itu servo. Yang ia tahu ialah cara membahagi satu frame berulang kepada 4096 hirisan sama besar dan menahan setiap output tinggi selama bilangan hirisan yang anda pilih. Panggil setPWMFreq(50) dan frame itu menjadi 20 ms panjang, jadi satu hirisan β satu tick β ialah 20000 Β΅s Γ· 4096 = 4.88 Β΅s. Pembahagian tunggal itulah seluruh lapisan penterjemahannya.
Jadi setPWM(channel, 0, N) menaikkan pin itu pada permulaan frame dan menjatuhkannya N tick kemudian, memberi satu pulse selebar N Γ 4.88 Β΅s. Pulse 1000 Β΅s ialah 205 tick, 1500 Β΅s ialah 307, 2000 Β΅s ialah 410. Fikir dalam mikrosaat dan tukar sekali sahaja β mikrosaat itulah unit yang jarak gerak servo dispesifikasikan.
Ini juga sebab menyalin 150 dan 600 sebagai endpoint anda, nombor yang dibawa oleh setiap sketch contoh, berakhir salah. Darabkan ia pada tick yang tepat, 20000 Β΅s Γ· 4096 = 4.8828 Β΅s: 150 tick ialah 732 Β΅s dan 600 tick ialah 2930 Β΅s. Rentang itu lebih lebar daripada jarak gerak kebanyakan servo 9 g, jadi di setiap hujung horn itu sampai ke hentian mekanikalnya, pengawal dalaman masih nampak ralat yang ia tidak mampu betulkan, dan motor terus menarik hampir arus stall sementara servo itu berdengung. Nombor itu memang placeholder yang sengaja dilebihkan, bukan satu spesifikasi.
Dua perkara kekal halimunan kepada aritmetik tetapi jelas kepada mata anda: servo individu berbeza beberapa darjah pada pulse yang sama, dan prescaler PCA9685 diterbitkan daripada osilator dalaman cip itu sendiri, yang menurut nota pustaka Adafruit sendiri jatuh di mana-mana dalam jalur 23β27 MHz dari cip ke cip dan bukan tepat pada 25 MHz datasheet, jadi frame sebenar mungkin bukan tepat 20 ms.
Jadi kalibrasi secara mekanikal. Servo ini dihantar tanpa horn, jadi lekatkan sejalur masking tape pada spline outputnya sebagai bendera. Hantar 1500 Β΅s, kemudian melangkah keluar 25 Β΅s setiap kali sambil memerhatinya. Detik bendera itu berhenti bergerak β atau servo mula berdengung dan panas β anda sudah sampai hentian. Undur 50 Β΅s, rekod endpoint itu, ulang untuk arah satu lagi dan untuk setiap channel.

Sketch di bawah ialah bench itu sendiri, bukan sekadar demo: ia menerima mikrosaat melalui Serial Monitor, menukarnya, mengingati endpoint setiap channel dan kemudian menyapu keempat-empatnya antara nombor yang anda jumpa. Pasang Adafruit PWM Servo Driver Library daripada Library Manager IDE terlebih dahulu.
// PCA9685 + Arduino Uno: cari endpoint sebenar setiap servo, kemudian sweep empat sekali gus.
// Uno A4 -> SDA pemacu Uno A5 -> SCL pemacu
// Uno 5V -> VCC pemacu Uno GND -> GND pemacu (sebelah logik, miliamp)
// Holder bateri atau adapter 5 V -> terminal skru V+ pemacu (sebelah servo, amp)
// Servo dipasang pada channel 0-3. Uno kekal atas USB.
//
// Serial Monitor, 9600 baud, line ending "Newline". Arahan:
// 0 1500 hantar 1500 us ke channel 0 (jalankan nombor ini sampai horn berhenti bergerak)
// min 0 ingat pulse semasa sebagai endpoint bawah channel 0
// max 0 ingat pulse semasa sebagai endpoint atas channel 0
// sweep jalankan keempat-empat channel antara endpoint masing-masing
// show cetak jadual kalibrasi
#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x40);
const uint8_t CHANNELS = 4;
const uint16_t PWM_HZ = 50;
const uint32_t PERIOD_US = 1000000UL / PWM_HZ; // 20000 us setiap frame pada 50 Hz
// Tekaan permulaan, bukan had selamat: 1000-2000 us ialah jarak gerak PENUH
// NOMINAL sebuah servo 9 g (~0 dan ~180 darjah), jadi satu unit tertentu boleh
// jadi sudah berdengung di satu hujung. Sempitkan atau luaskan ikut channel.
uint16_t loUs[CHANNELS] = {1000, 1000, 1000, 1000};
uint16_t hiUs[CHANNELS] = {2000, 2000, 2000, 2000};
uint16_t nowUs[CHANNELS];
// PCA9685 membahagi frame 20 ms miliknya kepada 4096 langkah, jadi satu langkah
// ialah 20000 / 4096 = 4.88 us. Inilah keseluruhan penukarannya.
uint16_t usToTicks(uint16_t us) {
// + PERIOD_US / 2 membundarkan ke tick terdekat, bukan sentiasa memotong
return (uint16_t)((((uint32_t)us * 4096UL) + PERIOD_US / 2) / PERIOD_US);
}
void sendUs(uint8_t ch, uint16_t us) {
if (ch >= CHANNELS) return;
if (us < 500) us = 500; // had carian, bukan had selamat: servo 9 g sudah
if (us > 2500) us = 2500; // pun di hentiannya sekitar 1000 dan 2000 us
nowUs[ch] = us;
pwm.setPWM(ch, 0, usToTicks(us));
}
void show() {
for (uint8_t ch = 0; ch < CHANNELS; ch++) {
Serial.print(F("ch ")); Serial.print(ch);
Serial.print(F(" now ")); Serial.print(nowUs[ch]);
Serial.print(F(" us (")); Serial.print(usToTicks(nowUs[ch]));
Serial.print(F(" ticks) min ")); Serial.print(loUs[ch]);
Serial.print(F(" max ")); Serial.println(hiUs[ch]);
}
}
void sweep() {
for (uint16_t p = 0; p <= 100; p += 2) {
for (uint8_t ch = 0; ch < CHANNELS; ch++) {
sendUs(ch, loUs[ch] + (uint32_t)(hiUs[ch] - loUs[ch]) * p / 100);
}
delay(20);
}
for (int16_t p = 100; p >= 0; p -= 2) {
for (uint8_t ch = 0; ch < CHANNELS; ch++) {
sendUs(ch, loUs[ch] + (uint32_t)(hiUs[ch] - loUs[ch]) * p / 100);
}
delay(20);
}
Serial.println(F("sweep done"));
}
void setup() {
Serial.begin(9600);
Wire.begin();
pwm.begin();
// Osilator dalaman PCA9685 ialah 25 MHz di atas kertas tetapi jatuh di mana-mana
// dalam jalur 23-27 MHz dari cip ke cip, dan prescaler dikira daripada nombor
// itu. 27000000 ialah angka contoh Adafruit sendiri, bukan ukuran cip ANDA -
// dan itulah tepatnya sebab endpoint yang anda cari dengan mata di bawah
// mengalahkan mana-mana nombor yang dikira daripadanya.
pwm.setOscillatorFrequency(27000000);
pwm.setPWMFreq(PWM_HZ);
for (uint8_t ch = 0; ch < CHANNELS; ch++) sendUs(ch, 1500);
Serial.println(F("ready - try: 0 1500 / min 0 / max 0 / sweep / show"));
}
void loop() {
if (!Serial.available()) return;
String line = Serial.readStringUntil('\n');
line.trim();
if (line.length() == 0) return;
if (line == F("sweep")) { sweep(); return; }
if (line == F("show")) { show(); return; }
if (line.startsWith(F("min ")) || line.startsWith(F("max "))) {
uint8_t ch = line.substring(4).toInt();
if (ch >= CHANNELS) { Serial.println(F("no such channel")); return; }
if (line.startsWith(F("min "))) loUs[ch] = nowUs[ch];
else hiUs[ch] = nowUs[ch];
show();
return;
}
int8_t space = line.indexOf(' ');
if (space < 0) { Serial.println(F("?")); return; }
uint8_t ch = line.substring(0, space).toInt();
uint16_t us = line.substring(space + 1).toInt();
if (ch >= CHANNELS) { Serial.println(F("no such channel")); return; }
sendUs(ch, us);
show();
}
Ia dikompil kepada 10,226 bait, 31% daripada flash Uno. Kalibrasi satu channel pada satu masa dengan hanya servo itu sahaja terpasang, kemudian pasang balik yang lain dan taip sweep.
Bagaimana dua wayar memacu enam belas channel?
PCA9685 duduk atas I2C, iaitu satu bas berkongsi dan bukan satu set wayar khusus. SDA dan SCL menjalar ke setiap peranti serentak dan setiap peranti menyahut kepada satu alamat, jadi Uno menyebut nama cip yang ia mahu sebelum berkata apa-apa β dan begitulah caranya sebuah LCD I2C berkongsi dua pin yang sama ini tanpa bertelagah. PCA9685 menyahut kepada 0x40 seperti yang ia dihantar.
Enam pad bertanda A0βA5, bersilkskrin buka = 0 dan tutup = 1, ialah cara anda menukarnya. Setiap satu ialah satu bit offset yang ditambah kepada alamat asas: titikkan solder merentas A0 dan board itu menjadi 0x41, A1 seorang diri menjadikannya 0x42, kedua-duanya menjadikannya 0x43. Jadi enam puluh dua board boleh berkongsi sepasang pin Uno β 992 channel.
Itu juga satu-satunya kerja di sini yang perlukan soldering iron. Sebelah rantai-keluar, iaitu barisan enam lubang bercermin pada tepi kanan, dihantar tanpa pin, dan anda pateri header di situ hanya bila board kedua menyertai. Untuk binaan pertama, tiada apa dalam senarai bahagian ini perlu dipateri.

Kesilapan biasa yang kami lihat daripada pelanggan sebenar
Menjalankan jumper dari pin 5 V Uno ke V+. Ia nampak kemas dan membatalkan seluruh tujuan board itu β arus servo terus balik melalui polyfuse dan brownout kembali tanpa berubah.
Menyambung V+ tetapi bukan VCC. Cip itu tiada kuasa logik, jadi ia tidak pernah menyahut atas I2C dan setiap channel kekal senyap. Bayangan cerminnya, VCC tanpa V+, lebih sukar dikesan: sketch berjalan, pustaka tidak melaporkan sebarang ralat, dan servo cuma bergegar sedikit atau langsung diam sebab tiada apa menyuap pin merahnya.
Menyalin 150 dan 600 daripada sketch contoh. Tick itu merentang 732β2930 Β΅s, jadi kedua-dua hujung setiap sapuan memandu servo itu masuk ke hentiannya sendiri.
Membiarkan alkali yang sudah letih dalam holder. Pada 1.1 V setiap sel, pek itu sudah turun ke 4.4 V, dan simptomnya β tersentak-sentak bila berbeban, elok sahaja bila tiada beban β terbaca sama macam masalah kod.
Menyilang SDA dengan SCL. A4 dan A5 duduk bersebelahan, dan menukarnya memberi anda board yang tidak menyahut apa-apa β senyap yang sama seperti cip mati atau VCC yang tertinggal. Jalankan File β Examples β Wire β i2c_scanner milik IDE itu sendiri sebelum anda debug apa-apa lagi: kalau 0x40 muncul, pendawaian anda betul dan puncanya ada pada pulse anda.
FAQ
Boleh tak saya bagi kuasa servo dari pin 5V Arduino sahaja?
Satu atau dua yang kecil sahaja. Atas USB, 5 V Uno datang melalui polyfuse 500 mA, dan empat SG90 yang bergerak serentak meminta 400 mA hingga 1 A β jadi rel itu melendut, brown-out detector me-reset cip dan port serial boleh tercicir.
Voltan apa patut saya sambung ke terminal V+ PCA9685?
5β6 V DC dengan servo terpasang. Empat sel AA NiMH bersiri memberi 4.8 V dan kekal di situ; adapter 5 V 3 A ialah jawapan yang sama dengan lebih ruang. VCC pada header itu berasingan β kuasa logik 5 V daripada Uno, untuk cip sahaja.
Apa alamat I2C lalai PCA9685?
0x40. Pad A0βA5 menambah offset binari bila anda titik solder padanya β A0 memberi 0x41, A1 memberi 0x42, kedua-duanya memberi 0x43 β jadi sehingga 62 board boleh berkongsi sepasang pin Arduino.
Macam mana saya tukar lebar pulse servo kepada tick setPWM?
Pada 50 Hz frame itu 20000 Β΅s dan cip membelahnya kepada 4096 tick, jadi satu tick ialah 4.88 Β΅s. Bahagi pulse anda dengan 4.88: 1000 Β΅s ialah 205 tick, 1500 Β΅s ialah 307, 2000 Β΅s ialah 410.
Kenapa dua servo yang sama berhenti pada sudut berlainan walaupun nilainya sama?
Sebab servo hobi dibina ikut harga: potensiometer maklum balas dalamannya dan hentian hujungnya berbeza dari unit ke unit. Langkahkan pulse setiap servo keluar sampai horn berhenti bergerak, undur, dan simpan pasangan nilai channel itu β dan itulah yang sketch di atas buat.
Kemas kini terakhir Ogos 2026. Tersangkut? Chat dengan kami di WhatsApp.



16 Channel PWM Servo Motor Driver PCA9685 16 PWM Output with I2C Communication For Arduino Robotic
Arduino Uno Compatible SMD UNO R3 with Type B Cable - ATMEGA328P with CH340G-Microcontroller Project
SG90 MG90 Tower Pro Micro Servo Motor 9g 180 360 Servo Motor for Arduino Robotic - SG90- 180Β°
40pcs Dupont Wire 10cm 20cm 30cm for Breadboard DIY Experiment Jumper Wire Breadboard wire - DUPONT WIRE M-F 20CM
AA Battery Holder with Cover On/Off Switch 2/3/4 Slots Battery AA Holder Red/Black Wire - AA BATTERY CASE (4S)
Power Supply Adapter DC Universal AC to DC Converter PSU 5V2A 5V3A 9V2A 12V2A - P.S. ADAPTOR (5V3A)
5.5x2.1mm DC Power Male Connector Plug Jack Adapter for Arduino DIY Electronics Projects - 5.5x2.1 DC CONNECTOR (F)
Data Cable Type-A Type-C MicroUSB Type-B 0.5m 1m 30cm 0.3m 100cm Data Transfer Upload Code - TYPE-A TO TYPE-B (1.0M)