Bagaimana saya melakukan prosthetisasi pada indikator UPS

selama debugging

Pada akhir 90-an saya mendapat UPS. Cantik, dengan indikator LED dan banyak tombol, ia memiliki dua baterai di dalam dan dapat mendukung kehidupan komputer saya pada saat itu (bersama dengan monitor!) Selama 15 menit. Waktu di Kamchatka sulit saat itu, lampu dimatikan secara teratur, jadi perangkat ini sangat berguna. Saya melewati seluruh krisis energi bersamanya, dan lebih dari sekali dia menyelamatkan surat-surat saya dari listrik yang tiba-tiba hilang. Dan juga, Anda dapat menghubungkan tape recorder ke sana dan, dengan cahaya lilin, dengarkan radio atau kaset favorit Anda, siapkan diri Anda makan malam di atas kompor gas portabel ...

Secara alami, UPS rusak. Pertama kali transformernya terbakar. Bukan yang besar dan ada di inverter, tapi ada yang kecil, mungkin untuk mengukur tegangan di jaringan. Tidak menemukan pabrik yang sama, saya membuat yang buatan sendiri, dan perangkat bekerja lebih lama. Lalu berhenti. Untuk waktu yang sangat lama, saya tidak dapat menemukan alasannya. Saya harus menyolder bagian yang berbeda, memeriksanya untuk kinerja dan menyoldernya kembali. Masalahnya tidak ditemukan. Perangkat yang patah jatuh di bawah tempat tidur selama beberapa tahun, sampai, suatu hari, ide datang kepada saya untuk menerapkan 5 volt langsung ke controller. Dan lihatlah: ada bunyi bip speaker terpasang dan angka muncul pada indikator LED. Dia hidup! Lebih jauh, ini masalah teknologi: Saya berjalan di sepanjang rangkaian catu daya dengan voltmeter dan menemukan bahwa sekring telah disolder di papan, yang tampak seperti resistor!Sekring (ditiup secara alami) diganti dan UPS hidup kembali.

Sayangnya, perbaikan saya dan dua tahun di bawah tempat tidur tidak hilang begitu saja. Dalam beberapa cara yang tidak dapat dipahami, port terbakar di controller, yang bertanggung jawab atas cahaya LED "On-Line" hijau dan segmen terendah dari semua indikator segmen digital. Tidak ada yang bisa dilakukan tentang hal itu - saya harus berdamai. Setelah beberapa waktu, saya meninggalkan Kamchatka dan jalan kami berbeda.

Tahun-tahun berlalu dan, setelah tiba untuk mengunjungi orang tua saya, di sudut jauh saya menemukan baterai favorit saya yang tidak terputus: ditinggalkan, kotor, tanpa baterai dan kaki karet. Pada saat itu, saya sudah mendapatkan perumahan saya sendiri di kota lain, jadi keputusan dibuat untuk mengambil perlindungan untuk diri saya sendiri, memulihkan efisiensinya dan menggunakannya untuk tujuan yang dimaksudkan.

Tantangan

Pertama-tama, UPS dicuci dan dikeringkan. Kemudian, di toko bagian radio tertentu, kaki karet yang cocok dan baterai baru dibeli. Yang mengejutkan saya, transformator yang cocok ditemukan di toko yang sama, sebagai imbalan untuk produk buatan saya. Beberapa hari kerja, dan baterai tanpa gangguan yang diperbarui dan diperbarui dengan gembira berdecit dan mulai mengisi baterai baru. Semuanya baik-baik saja, tetapi indikatornya masih tidak berfungsi.

Gagasan untuk memperbaikinya datang kepada saya sebelumnya. Setelah menggambar semua angka (dan beberapa huruf) dari tujuh segmen indikator pada lembar notebook, saya menyadari bahwa adalah mungkin untuk menentukan keadaan segmen terendah dengan keadaan sisanya. LED hijau dapat menyala ketika LED lain tidak menyala. Ada banyak pemikiran tentang bagaimana hal ini dapat dilakukan: dari chip ROM sederhana hingga FPGA sederhana. Tetapi, karena saya adalah seorang mahasiswa dan tinggal di Kamchatka, saya tidak memiliki kesempatan untuk mendapatkan sesuatu yang lebih rumit daripada logika kecil. Memperbaiki indikator ditunda.

menggambar segmen

Kali ini saya memutuskan untuk menangani masalah ini dengan serius. Setelah mencari-cari di tempat sampah, saya kembali tidak menemukan pada saya baik ROM, maupun FPGA dan CPLD. Tetapi, Arduino Pro Mini, atau lebih tepatnya, tiruan Cina murahnya dengan Ali Express, jatuh ke tangan. Saya membeli Arduin untuk membuat komputer mini berbasis WiFi SD card dari Transcend. Sayangnya, kartu itu mati selama percobaan, dan papan dengan mikrokontroler tetap menganggur. Tidak ada, kami menemukannya tantangan baru!

Bekerja

Tampilan dinamis diimplementasikan dalam modul display: sinyal segmen adalah umum untuk keempat indikator sehingga hanya satu yang menyala secara bersamaan. Selain itu: seolah-olah dengan indikator kelima, tiga LED juga terhubung. Lima sinyal pilihan memungkinkan Anda menentukan indikator (atau garis LED) mana yang sedang digunakan sekarang. Sinyal seleksi ini dipindai secara berurutan pada kecepatan yang cukup tinggi dan, karena inersia penglihatan, tampaknya semua indikator menyala secara bersamaan.

Pada awalnya, saya ingin menyiasati solusi paling sederhana: siklus biasa yang memeriksa sinyal dari enam segmen kerja, dan menghidupkan atau mematikan yang tidak berfungsi ketujuh. Sebenarnya, ini hanyalah emulasi dari ROM, yang saya pikirkan di awal.

Untuk melakukan ini, saya harus menghubungkan enam segmen kerja ke input mikrokontroler, dan segmen yang tidak bekerja ke output.

Setelah membuat sketsa array kecil yang membandingkan berbagai keadaan input dengan output dan loop yang mem-bypass array ini, saya memuat semuanya ke controller dan segera mendapat masalah: segmen bawah selalu bersinar. Pikiran pertama: cant dalam program. Namun, tidak peduli seberapa banyak saya melihat kode, tidak ada kesalahan yang ditemukan. Pada akhirnya, dapat dipahami bahwa siklus saya sama sekali tidak disinkronkan dengan pergantian indikator. Jika kita membaca status segmen pada akhir siklus pemilihan satu indikator, maka kemungkinan kita akan menyalakan atau menurunkan segmen berikutnya pada yang berikutnya. Kekacauan.

Tanpa berpikir dua kali, saya menyolder lima sinyal pemilihan indikator ke input Arduino gratis yang tersisa, mengaturnya untuk menghasilkan interupsi, dan mulai menggunakan interrupt handler alih-alih loop. Itu menjadi lebih baik, tetapi tidak memecahkan masalah. Di tempat yang tepat, ruasnya terbakar seperti seharusnya, tetapi di tempat-tempat di mana ia seharusnya padam, tidak ada cahaya sisa yang terang.

Setelah berpikir untuk beberapa waktu lagi, saya memutuskan bahwa efek ini dapat muncul jika siklus pencarian dalam array keadaan yang diinginkan untuk segmen membutuhkan waktu lebih lama daripada waktu pembakaran indikator. Dalam hal ini, kami juga keluar dari fase kami dan mengelola segmen indikator berikutnya. Adalah perlu bahwa sesedikit mungkin waktu berlalu antara saat menerima interupsi dari sinyal seleksi ke perintah kontrol segmen. Ini bisa dilakukan hanya dengan satu cara: untuk menghapus kode yang membuat keputusan tentang keadaan segmen dari interrupt handler, jalankan di loop utama dengan prioritas minimal, dan simpan hasilnya dalam semacam buffer global. Interrupt handler hanya perlu membaca nilai buffer global ini dan memadamkan atau menyalakan segmen tersebut, tergantung pada isinya. Dalam kasus terburukkita hanya bisa terlambat dengan perubahan status segmen dalam indikator tertentu, tetapi kita tidak akan naik ke yang berikutnya.

Itu adalah keputusan yang tepat. Tapi akhirnya itu bekerja hanya setelah saya mensinkronisasi siklus pengambilan keputusan dengan interupsi menggunakan spin-lock dan melarang pemrosesan interupsi selama siklus ini. Dan itu tidak hanya diperoleh, tetapi diterima sebagaimana mestinya!

Ada masalah lain dengan indikator: sebagian besar waktu mereka hanya menunjukkan angka. Namun, setelah menyalakan UPS, proses pengujian dimulai, di mana, di samping angkanya, dua kata lagi muncul: TEST dan PASS. Dan jika, huruf T, E dan P dapat dengan mudah ditambahkan ke array karakter yang valid, dan S sama dengan 5s, maka huruf A tidak ada artinya, dari sudut pandang program saya, dari angka delapan. Siklus keputusan hanya menemukan pola yang sesuai dalam array dan menggambar segmen bawah. Itu perlu untuk datang dengan sesuatu untuk menghindari ini.

Dan saya datang dengan. Selama kedatangan sinyal tentang perubahan indikator, perlu untuk menentukan indikator mana yang dimiliki dan menyimpan status segmennya dalam variabel yang dialokasikan secara khusus untuknya. Sekarang, kapan saja, saya dapat secara akurat menentukan konten saat ini dari keempat indikator sekaligus. Dan jika simbol P, 5 dan 5 masing-masing ditampilkan pada yang pertama, ketiga dan keempat, maka simbol kedua pasti A, dan Anda tidak perlu menyalakan segmen bawah. Untuk berjaga-jaga, saya juga menambahkan pemrosesan kata FAIL, yang belum pernah saya lihat, tetapi yang saya harapkan akan muncul.

Semuanya, dengan indikator digital berakhir. Tetap hanya untuk memperbaiki LED On-Line hijau. Tapi di sini kejutan menunggu saya ... Idenya adalah ini: LED hijau (On-Line) selalu menyala sendiri. Jika LED kuning (Baterai) atau merah (Baterai Rendah) menyala, warna hijau seharusnya tidak menyala. Jadi, kami menyolder kabel dari LED ini ke mikrokontroler, menempatkan if () sederhana dengan "OR" yang logis dan semuanya harus bekerja. Tapi ternyata ketika LED kuning menyala, nyatanya, tidak menyala terus-menerus, tetapi berkedip cepat. Cepat, tetapi tidak cukup untuk jika () melompati dan tidak menyalakan LED hijau. Ternyata ketika bekerja dari jaringan, LED hijau menyala dengan kecerahan penuh, tetapi ketika beralih ke baterai, ia menyala setengah kecerahan, tetapi masih menyala. Yah, tidak masalah, saya pikir, saya akan memasang filter low-pass sederhana:Saya akan memotong semua flash cepat, tetapi saya hanya akan meninggalkan yang lambat yang sesuai dengan transisi ke baterai dan sebaliknya. Analisis waktu berkedip LED kuning membawa kejutan berikut: periode pulsa yang dipasok ke itu sangat tidak stabil dan dapat mencapai nilai yang cukup besar. Ternyata filter harus melewati sinyal tidak lebih tinggi dari 0,5-1 Hz. Ini tidak terlalu baik, karena kami mendapat penundaan yang agak besar dalam mengubah sinyal On-Line, tetapi cukup dapat ditoleransi.karena kita mendapatkan penundaan yang agak besar dalam mengubah sinyal On-Line, tetapi itu cukup lumayan.karena kita mendapatkan penundaan yang agak besar dalam mengubah sinyal On-Line, tetapi itu cukup lumayan.

Saya memutuskan untuk membuat filter sangat sederhana. Kami 50 kali, secara berkala, memantau status LED kuning dan merah. Jika salah satunya terbakar, maka kami menambah penghitung khusus dengan satu. Kemudian, kami memeriksa nilai penghitung, dan jika LED kontrol menyala untuk 50% dari waktu yang dicentang, maka kami percaya bahwa itu menyala, dan jika kurang, maka itu mati. Dalam proses debugging, saya harus mengurangi angka ini menjadi 10%. Mengapa - tidak mengetahuinya.

perakitan akhir

Dan itu semua berhasil! Hanya tersisa untuk dengan indah memasang papan Arduino dalam wadah UPS dengan selotip dua sisi dan pistol berperekat.



Untuk yang penasaran:
kode yang dihasilkan
#include <stdint.h>
#include <avr/io.h>
#include <avr/interrupt.h>



#define AVG_TIME    50
#define THS_TIME    45


#define SD_SEG_A    _BV(0)
#define SD_SEG_B    _BV(1)
#define SD_SEG_C    _BV(2)
#define SD_SEG_D    _BV(3)
#define SD_SEG_E    _BV(4)
#define SD_SEG_F    _BV(5)
#define SD_SEG_G    _BV(6)
#define SD_LED_RED  SD_SEG_A
#define SD_LED_YLW  SD_SEG_C

#define LD_SEL_LED  _BV(0)
#define LD_SEL_1    _BV(1)
#define LD_SEL_2    _BV(2)
#define LD_SEL_3    _BV(3)
#define LD_SEL_4    _BV(4)

#define GET_SEL     (PINC & 0x1f)


#define SD_SYM_NONE (0)
#define SD_SYM_0    (SD_SEG_A | SD_SEG_B | SD_SEG_C | SD_SEG_D | SD_SEG_E | SD_SEG_F)
#define SD_SYM_1    (SD_SEG_B | SD_SEG_C)
#define SD_SYM_2    (SD_SEG_A | SD_SEG_B | SD_SEG_D | SD_SEG_E | SD_SEG_G)
#define SD_SYM_3    (SD_SEG_A | SD_SEG_B | SD_SEG_C | SD_SEG_D | SD_SEG_G)
#define SD_SYM_4    (SD_SEG_B | SD_SEG_C | SD_SEG_F | SD_SEG_G)
#define SD_SYM_5    (SD_SEG_A | SD_SEG_C | SD_SEG_D | SD_SEG_F | SD_SEG_G)
#define SD_SYM_6    (SD_SEG_A | SD_SEG_C | SD_SEG_D | SD_SEG_E | SD_SEG_F | SD_SEG_G)
#define SD_SYM_7    (SD_SEG_A | SD_SEG_B | SD_SEG_C)
#define SD_SYM_8    (SD_SEG_A | SD_SEG_B | SD_SEG_C | SD_SEG_D | SD_SEG_E | SD_SEG_F | SD_SEG_G)
#define SD_SYM_9    (SD_SEG_A | SD_SEG_B | SD_SEG_C | SD_SEG_D | SD_SEG_F | SD_SEG_G)
#define SD_SYM_E    (SD_SEG_A | SD_SEG_D | SD_SEG_E | SD_SEG_F | SD_SEG_G)
#define SD_SYM_P    (SD_SEG_A | SD_SEG_B | SD_SEG_E | SD_SEG_F | SD_SEG_G)
#define SD_SYM_T    (SD_SEG_D | SD_SEG_E | SD_SEG_F | SD_SEG_G)

#define GET_SYM     (~PIND & 0x7f)


#define BROKEN_SEG  (SD_SEG_D)



static uint8_t sd_symbols[] = {                 // list of known symbols
    SD_SYM_NONE,
    SD_SYM_0, SD_SYM_1, SD_SYM_2, SD_SYM_3, SD_SYM_4,
    SD_SYM_5, SD_SYM_6, SD_SYM_7, SD_SYM_8, SD_SYM_9,
    SD_SYM_E, SD_SYM_P, SD_SYM_T
};
volatile static uint8_t sel, symbol;            // current input signals
volatile static short fb0, fb1, fb2, fb3, fb4;  // display frame buffer


// display routine
ISR(PCINT1_vect) {
    sel = GET_SEL;
    symbol = GET_SYM;

    if (((sel & LD_SEL_LED) && fb0) ||
            ((sel & LD_SEL_1) && fb1) ||
            ((sel & LD_SEL_2) && fb2) ||
            ((sel & LD_SEL_3) && fb3) ||
            ((sel & LD_SEL_4) && fb4)){
        PORTD &= ~BROKEN_SEG;
    }
    else {
        PORTD |= BROKEN_SEG;
    }
}


//
// entry point
//

int main(void)
{
    int cur_time;
    int led_on_time;
    uint8_t last_symbol_1, last_symbol_2, last_symbol_3, last_symbol_4;
    int i;

    // setup GPIO ports
    DDRC = 0;
    DDRD = BROKEN_SEG;

    // setup pin change interrupt
    PCICR |= _BV(PCIE1);
    PCMSK1 |= _BV(PCINT8) | _BV(PCINT9) | _BV(PCINT10) | _BV(PCINT11) | _BV(PCINT12);

    cur_time = 0;
    led_on_time = 0;
    last_symbol_1 = last_symbol_2 = last_symbol_3 = last_symbol_4 = 0;
    fb0 = fb1 = fb2 = fb3 = fb4 = 0;

    while(1) {
        // sync with display strobe
        sei();
        while (sel == 0) {}
        cli();

        // if select one of segment indicator
        if (sel & (LD_SEL_1 | LD_SEL_2 | LD_SEL_3 | LD_SEL_4)) {
            // looking for displayed symbol
            for (i = 0; i < 14; i++) {
                uint8_t sd_symbol = sd_symbols[i];
                if ((symbol & ~BROKEN_SEG) == (sd_symbol & ~BROKEN_SEG)) {
                    short val;
                    if (sd_symbol & BROKEN_SEG) {
                        val = 1;
                    } else {
                        val = 0;
                    }

                    if (sel & LD_SEL_1) {
                        last_symbol_1 = sd_symbol;
                        fb1 = val;
                    } else if (sel & LD_SEL_2) {
                        last_symbol_2 = sd_symbol;
                        fb2 = val;
                    } else if (sel & LD_SEL_3) {
                        last_symbol_3 = sd_symbol;
                        fb3 = val;
                    } else if (sel & LD_SEL_4) {
                        last_symbol_4 = sd_symbol;
                        fb4 = val;
                    }

                    // PASS workaround
                    if ((last_symbol_1 == SD_SYM_P) &&(last_symbol_2 == SD_SYM_8) &&
                            (last_symbol_3 == SD_SYM_5) && (last_symbol_4 == SD_SYM_5)) {
                        fb2 = 0;
                    }
                    // FAIL workaround
                    else if ((last_symbol_1 == SD_SYM_E) &&(last_symbol_2 == SD_SYM_8) &&
                            (last_symbol_3 == SD_SYM_1) && (last_symbol_4 == SD_SYM_1)) {
                        fb1 = 0;
                        fb2 = 0;
                        fb4 = 1;
                    }

                    break;
                }
            }
        }
        // if select LED line
        else if (sel & LD_SEL_LED) {
            if (cur_time++ > AVG_TIME) {
                if (led_on_time < THS_TIME) {
                    fb0 = 0;
                } else {
                    fb0 = 1;
                }
                cur_time = 0;
                led_on_time = 0;
            } else {
                if ((symbol & (SD_LED_RED | SD_LED_YLW)) == 0) {
                    led_on_time++;
                }
            }
        }

        // reset sync flag
        sel = 0;
    }

    return 0;
}

Source: https://habr.com/ru/post/id397697/


All Articles