كيف أقوم بتعويض مؤشر UPS

أثناء التصحيح

في أواخر التسعينيات حصلت على UPS. جميل ، مع مؤشر LED ومجموعة من الأزرار ، كان به بطاريتان في الداخل ويمكنهما دعم حياة جهاز الكمبيوتر الخاص بي في ذلك الوقت (إلى جانب الشاشة!) لمدة 15 دقيقة. كانت الأوقات في كامتشاتكا صعبة في ذلك الوقت ، وتم إطفاء الأضواء بانتظام ، لذلك كان هذا الجهاز في متناول اليد. لقد مررت بأزمة الطاقة كلها معه ، وأكثر من مرة أنقذ أوراق فترتي من الفقد المفاجئ للكهرباء. وأيضًا ، يمكنك توصيل جهاز تسجيل به ، ومن خلال ضوء الشمع ، استمع إلى الراديو أو الأشرطة المفضلة لديك ، وأعد لنفسك عشاءً على موقد غاز محمول ...

وبطبيعة الحال ، كان UPS ينكسر. في المرة الأولى احترق محوله. ليس الحجم الكبير الموجود في العاكس ، ولكن البعض صغير ، ربما لقياس الجهد في الشبكة. لم أجد المصنع نفسه ، لقد قمت بإعداد مصنع عصامي ، وعمل الجهاز لبعض الوقت. ثم توقفت. لم أتمكن من إيجاد السبب لفترة طويلة جدًا جدًا. اضطررت إلى لحام أجزاء مختلفة ، والتحقق من أدائها وإعادة لحامها. لم يتم العثور على المشكلة. سقط الجهاز الممزق تحت السرير لبضع سنوات ، حتى يوم واحد ، جاءتني الفكرة لتطبيق 5 فولت مباشرة على وحدة التحكم. وها ، كان هناك صوت صفير للسماعة المدمجة وأظهرت الأرقام على مؤشر LED. كان على قيد الحياة! ثم إنها مسألة تقنية: مشيت على طول دائرة إمداد الطاقة مع الفولتميتر واكتشفت أنه تم لحام الصمامات على اللوحة ، والتي بدت وكأنها مقاومة!تم استبدال المصهر (المنفوخ بشكل طبيعي) وعادت UPS إلى الحياة.

لسوء الحظ ، لم يذهب إصلاحي وسنتان تحت السرير بعيدًا للجهاز من أجل لا شيء. بطريقة غير مفهومة ، احترق المنفذ في وحدة التحكم ، والتي كانت مسؤولة عن توهج LED الأخضر "On-Line" والجزء الأدنى من جميع مؤشرات القطاعات الرقمية. لا يوجد شيء يجب القيام به حيال ذلك - كان علي أن أتصالح. بعد مرور بعض الوقت ، غادرت كامتشاتكا وتباعدت مساراتنا.

مرت سنوات ، وبعد أن وصلت لزيارة والدي ، وجدت في الزاوية البعيدة بطاريتي المفضلة بلا انقطاع: مهجورة وقذرة وبدون بطاريات وأرجل مطاطية. وبحلول ذلك الوقت ، كنت قد اكتسبت بالفعل مسكني الخاص في مدينة أخرى ، لذلك تم اتخاذ القرار بأخذ الملجأ لنفسي ، واستعادة كفاءته واستخدامه للغرض المقصود.

التحدي

بادئ ذي بدء ، تم غسل وتجفيف UPS. بعد ذلك ، تم شراء أقدام مطاطية مناسبة وبطاريات جديدة في متجر قطع غيار راديو معين. لدهشتي الكبيرة ، تم العثور على محول مناسب في نفس المتجر ، مقابل منتجي محلي الصنع. لبضعة أيام من العمل ، والبطارية التي تم غسلها وتحديثها دون انقطاع تنقطع بسعادة وبدأت في شحن بطارياتها الجديدة. كان كل شيء على ما يرام ، لكن المؤشر لا يزال لا يعمل.

أتتني فكرة إصلاحها من قبل. بعد أن قمت برسم جميع الأرقام (وبعض الأحرف) لمؤشر الأجزاء السبعة على ورقة دفتر الملاحظات ، أدركت أنه من الممكن تحديد حالة الجزء الأدنى بواسطة حالة الباقي. يمكن إضاءة LED الأخضر عندما لا تضاء مصابيح LED أخرى. كانت هناك العديد من الأفكار حول كيفية القيام بذلك: من شريحة ROM بسيطة إلى FPGA بسيطة. ولكن ، منذ أن كنت طالبًا وعشت في كامتشاتكا ، لم تتح لي الفرصة لاكتساب أي شيء أكثر تعقيدًا من المنطق الصغير. تم تأجيل تحديد المؤشر.

رسم الشرائح

هذه المرة قررت معالجة المشكلة بجدية. بعد أن بحثت في صناديق ، لم أجد مرة أخرى لي ولا ROM ، ولا FPGA وأي CPLD. ولكن ، اردوينو برو ميني ، أو بالأحرى ، استنساخه الصيني الرخيص مع علي اكسبرس ، سقط في أيدي. اشتريت Arduin من أجل صنع جهاز كمبيوتر صغير يعتمد على بطاقة WiFi SD من Transcend. لسوء الحظ ، ماتت البطاقة أثناء التجارب ، وبقي اللوحة مع وحدة التحكم الدقيقة خاملاً. لا شيء ، وجدنا لها تحديًا جديدًا!

العمل

يتم تنفيذ العرض الديناميكي في وحدة العرض: إشارات المقطع شائعة في جميع المؤشرات الأربعة بحيث يتم إضاءة واحد منها فقط في كل مرة. علاوة على ذلك: كما هو الحال مع المؤشر الخامس ، يتم توصيل ثلاثة مصابيح LED أيضًا. تتيح لك خمس إشارات اختيار تحديد المؤشر (أو خط المصابيح) الذي يتم استخدامه الآن. يتم مسح إشارات الاختيار هذه بالتسلسل بسرعة عالية إلى حد ما ، وبسبب قصور الرؤية ، يبدو أن جميع المؤشرات مضاءة في نفس الوقت.

في البداية ، كنت أرغب في الالتفاف حول أبسط الحلول: دورة عادية تتحقق من الإشارات من ستة قطاعات عاملة ، وتشتغل أو توقف الحلقة السابعة التي لا تعمل. في الواقع ، هذه مجرد محاكاة للروم ، والتي فكرت بها في البداية.

للقيام بذلك ، اضطررت إلى توصيل ستة أجزاء عاملة بإدخال وحدة التحكم الدقيقة ، وجزء غير عامل إلى الإخراج.

بعد أن قمت برسم مصفوفة صغيرة قارنت بين مختلف حالات المدخلات والمخرجات والحلقة التي تتجاوز هذا الصفيف ، قمت بتحميل كل شيء في وحدة التحكم وحصلت على مشكلة على الفور: الجزء السفلي متوهج دائمًا. الفكر الأول: لا يمكن في البرنامج. ومع ذلك ، بغض النظر عن مدى النظر إلى الرمز ، لم يتم العثور على أخطاء. في النهاية ، أصبح من المفهوم أن دورتي لم تكن متزامنة بأي حال من الأحوال مع تبديل المؤشرات. إذا قرأنا حالة الأجزاء في نهاية دورة اختيار مؤشر واحد ، فمن المحتمل أننا سنضيء أو نخفض الجزء التالي في الجزء التالي. الفوضى.

دون التفكير مرتين ، قمت بلحام خمس إشارات اختيار مؤشر إلى إدخالات Arduino المجانية المتبقية ، وقمت بتعيينها لإنشاء مقاطعة ، وبدأت في استخدام معالج المقاطعة بدلاً من التكرار. أصبحت أفضل ، لكنها لم تحل المشكلة. في الأماكن الصحيحة ، تم حرق الجزء كما ينبغي ، ولكن في تلك الأماكن التي كان من المفترض أن يتم إخمادها ، لم يكن هناك توهج متبقي مشرق.

بعد التفكير لبعض الوقت ، قررت أن هذا التأثير قد يظهر إذا كانت دورة البحث في صفيف الحالة المرغوبة للأجزاء تستغرق وقتًا أطول من وقت حرق المؤشر. في هذه الحالة ، نخرج أيضًا من مرحلتنا وندير جزء المؤشر التالي. من الضروري أن يمر أقل وقت ممكن بين لحظة استقبال المقاطعة من إشارة التحديد إلى أمر التحكم في المقطع. يمكن القيام بذلك بطريقة واحدة فقط: لإزالة التعليمات البرمجية التي تتخذ القرار بشأن حالة المقطع من معالج المقاطعة ، وتشغيله في الحلقة الرئيسية مع الحد الأدنى من الأولوية ، وحفظ النتيجة في نوع من المخزن المؤقت العام. سيتعين على معالج المقاطعة قراءة قيمة هذا المخزن المؤقت العام وإطفاء أو إضاءة المقطع ، اعتمادًا على محتوياته. في أسوأ الأحواللا يمكننا أن نتأخر إلا مع التغيير في حالة الجزء في مؤشر معين ، لكننا لن نتسلق إلى المؤشر التالي.

كان هذا هو القرار الصحيح. ولكن في النهاية ، لم تعمل إلا بعد مزامنة دورة اتخاذ القرار مع مقاطعة باستخدام قفل الدوران ومنع معالجة المقاطعة خلال هذه الدورة. ولم تكتسب فحسب ، بل كسبت كما ينبغي!

كانت هناك مشكلة أخرى في المؤشرات: في معظم الأحيان أظهروا أرقامًا فقط. ومع ذلك ، بعد تشغيل UPS ، بدأت عملية الاختبار ، ظهرت خلالها ، بالإضافة إلى الأرقام ، كلمتان أخريان: TEST و PASS. وإذا كان من الممكن ببساطة إضافة الأحرف T و E و P إلى مجموعة الأحرف الصالحة ، وكان S هو نفسه 5s ، فإن الحرف A لم يكن شيئًا ، من وجهة نظر برنامجي ، من الشكل الثامن. وجدت دورة القرار ببساطة النمط المناسب في الصفيف ولفت الجزء السفلي. كان من الضروري الخروج بشيء لتجنب ذلك.

وخرجت. أثناء وصول إشارة حول تغيير المؤشر ، من الضروري تحديد المؤشر الذي ينتمي إليه وحفظ حالة مقاطعه في متغير مخصص له. الآن ، في أي لحظة من الزمن ، يمكنني تحديد المحتوى الحالي لجميع المؤشرات الأربعة بدقة في آن واحد. وإذا تم عرض الرموز P و 5 و 5 على الأول والثالث والرابع على التوالي ، فإن الرمز الثاني هو بالتأكيد A ، ولا تحتاج إلى إضاءة الجزء السفلي. تحسبًا لذلك ، أضفت أيضًا معالجة كلمة FAIL ، التي لم أرها مطلقًا ، ولكنني توقعت ظهورها.

كل شيء ، مع انتهاء المؤشر الرقمي. يبقى فقط لإصلاح LED على الخط الأخضر. ولكن هنا كانت مفاجأة في انتظاري ... كانت الفكرة هي: LED الأخضر (على الإنترنت) دائمًا يضيء بمفرده. إذا كانت أضواء LED (البطارية) الصفراء أو الحمراء (بطارية منخفضة) مضاءة ، فلا ينبغي أن يضيء اللون الأخضر. وبالتالي ، نحن نلحم الأسلاك من هذه المصابيح إلى وحدة التحكم الدقيقة ، ونضع بسيطة إذا () مع "OR" منطقي وكل شيء يجب أن يعمل. ولكن اتضح أنه عند تشغيل LED الأصفر ، فإنه في الواقع لا يضيء باستمرار ، ولكنه يومض بسرعة. سريع ، ولكن ليس كافيًا إذا تخطي () ولم يضيء مؤشر LED الأخضر. اتضح أنه عند العمل من الشبكة ، يضيء مصباح LED الأخضر بسطوع كامل ، ولكن عند التبديل إلى البطارية ، يحترق بنصف سطوع ، ولكنه لا يزال يحترق. حسنًا ، ليست مشكلة ، فكرت ، سأضع فلترًا بسيطًا للتمرير المنخفض:سأقطع جميع الومضات السريعة ، لكني سأترك فقط الومضات البطيئة التي تتوافق مع الانتقال إلى البطارية والعكس بالعكس. جلب تحليل وقت وميض LED الأصفر المفاجأة التالية: فترة النبضات التي يتم توفيرها لها غير مستقرة للغاية ويمكن أن تصل إلى قيم كبيرة جدًا. اتضح أن المرشح يجب أن يمر إشارات لا تزيد عن 0.5-1 هرتز. هذا ليس جيدًا جدًا ، لأننا نحصل على تأخير كبير إلى حد ما في تغيير الإشارة عبر الإنترنت ، ولكنه مقبول تمامًا.نظرًا لأن لدينا تأخيرًا كبيرًا إلى حد ما في تغيير الإشارة عبر الإنترنت ، إلا أنه يمكن تحمله تمامًا.نظرًا لأن لدينا تأخيرًا كبيرًا إلى حد ما في تغيير الإشارة عبر الإنترنت ، إلا أنه يمكن تحمله تمامًا.

قررت أن أجعل المرشح بسيطًا جدًا. نحن نراقب 50 مرة ، على فترات منتظمة ، حالة المصابيح الصفراء والحمراء. إذا أحرق أحدهم ، فإننا نزيد العداد الخاص بواحد. بعد ذلك ، نتحقق من قيمة العداد ، وإذا كانت مصابيح LED للتحكم تضيء لمدة 50 ٪ من الوقت المحدد ، فإننا نعتقد أنها تعمل ، وإذا كانت أقل ، فعندئذٍ تكون مطفأة. في عملية التصحيح ، كان علي تخفيض هذا الرقم إلى 10٪. لماذا - لم نكتشف ذلك.

التجميع النهائي

وعمل كل شيء! بقي فقط لتركيب لوحة Arduino بشكل جميل في علبة UPS بشريط مزدوج الجوانب ومسدس لاصق.



للفضول:
الكود الناتج
#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/ar397697/


All Articles